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 local base = _G
env.info("Loading MOOSE " .. base.timer.getAbsTime() ) 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 = {}
Include.MissionPath = script_path() .. "Mission\\" Include.Path = function()
Include.ProgramPath = "Scripts\\Moose\\Moose\\" local str = debug.getinfo(2, "S").source
return str:match("(.*/)"):sub(1,-2):gsub("\\","/")
env.info( "Include.MissionPath = " .. Include.MissionPath) end
env.info( "Include.ProgramPath = " .. Include.ProgramPath)
Include.Files = {}
Include.File = function( IncludeFile ) Include.File = function( IncludeFile )
if not Include.Files[ IncludeFile ] then if not Include.Files[ IncludeFile ] then
Include.Files[IncludeFile] = IncludeFile 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 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 if f == nil then
error ("Could not load MOOSE file " .. IncludeFile .. ".lua" ) error ("Could not load MOOSE file " .. IncludeFile .. ".lua" )
else else
env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath ) env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.MissionPath )
return f() return f()
end end
else else
env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.MissionPath ) env.info( "Include:" .. IncludeFile .. " loaded from " .. Include.ProgramPath )
return f() return f()
end end
end 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" ) Include.File( "Database" )
env.info("Loaded MOOSE Include Engine") 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" ) Include.File( "Routines" )
_TraceOn = true
_TraceClass = {
DATABASE = true,
--SEAD = true,
--DESTROYBASETASK = true,
--MOVEMENT = true,
--SPAWN = true,
--GROUP = true,
--UNIT = true,
}
BASE = { BASE = {
ClassName = "BASE", ClassName = "BASE",
ClassID = 0, ClassID = 0,
Events = {} Events = {}
} }
--- The base constructor. This is the top top class of all classed defined within the MOOSE. --- 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 Child.__index = Child
end end
--Child.ClassName = Child.ClassName .. '.' .. Child.ClassID --Child.ClassName = Child.ClassName .. '.' .. Child.ClassID
trace.i( Child.ClassName, 'Inherited from ' .. Parent.ClassName ) self:T( 'Inherited from ' .. Parent.ClassName )
return Child return Child
end end
@ -104,6 +114,7 @@ trace.f( self.ClassName )
return self return self
end end
BaseEventCodes = { BaseEventCodes = {
"S_EVENT_SHOT", "S_EVENT_SHOT",
"S_EVENT_HIT", "S_EVENT_HIT",
@ -129,7 +140,46 @@ BaseEventCodes = {
"S_EVENT_SHOOTING_START", "S_EVENT_SHOOTING_START",
"S_EVENT_SHOOTING_END", "S_EVENT_SHOOTING_END",
"S_EVENT_MAX", "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) function BASE:onEvent(event)
--trace.f(self.ClassName, event ) --trace.f(self.ClassName, event )
@ -159,3 +209,22 @@ function BASE:onEvent(event)
end 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, ClientTransport = false,
ClientBriefingShown = false, ClientBriefingShown = false,
_Menus = {}, _Menus = {},
_Cargos = {},
_Tasks = {}, _Tasks = {},
Messages = { Messages = {
} }
@ -45,10 +44,9 @@ CLIENT = {
-- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() ) -- Mission:AddClient( CLIENT:New( 'RU MI-8MTV2*RAMP-Deploy Troops 4' ):Transport() )
function CLIENT:New( ClientName, ClientBriefing ) function CLIENT:New( ClientName, ClientBriefing )
trace.f(self.ClassName)
-- Arrange meta tables
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
self:T()
self.ClientName = ClientName self.ClientName = ClientName
self:AddBriefing( ClientBriefing ) self:AddBriefing( ClientBriefing )
self.MessageSwitch = true self.MessageSwitch = true
@ -59,29 +57,162 @@ end
--- Resets a CLIENT. --- 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. -- @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 ) function CLIENT:Reset( ClientName )
trace.f(self.ClassName) self:T()
self._Menus = {} self._Menus = {}
self._Cargos = {}
end end
--- ClientGroup returns the Group of a Client. --- 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 -- @treturn Group
function CLIENT:ClientGroup() function CLIENT:ClientGroup()
--trace.f(self.ClassName) --self:T()
local ClientData = Group.getByName( self.ClientName )
if ClientData and ClientData:isExist() then -- local ClientData = Group.getByName( self.ClientName )
trace.i( self.ClassName, self.ClientName .. " : group found!" ) -- if ClientData and ClientData:isExist() then
return ClientData -- self:T( self.ClientName .. " : group found!" )
else -- return ClientData
-- trace.x( self.ClassName, self.ClientName .. " : no group found!" ) -- else
return nil -- 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 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 end
--- Transport defines that the Client is a Transport. --- Transport defines that the Client is a Transport.
-- @treturn CLIENT -- @treturn CLIENT
function CLIENT:Transport() function CLIENT:Transport()
trace.f(self.ClassName) self:T()
self.ClientTransport = true self.ClientTransport = true
return self return self
@ -91,7 +222,7 @@ end
-- @tparam string ClientBriefing is the text defining the Mission briefing. -- @tparam string ClientBriefing is the text defining the Mission briefing.
-- @treturn CLIENT -- @treturn CLIENT
function CLIENT:AddBriefing( ClientBriefing ) function CLIENT:AddBriefing( ClientBriefing )
trace.f(self.ClassName) self:T()
self.ClientBriefing = ClientBriefing self.ClientBriefing = ClientBriefing
return self return self
end end
@ -99,114 +230,29 @@ end
--- IsTransport returns if a Client is a transport. --- IsTransport returns if a Client is a transport.
-- @treturn bool -- @treturn bool
function CLIENT:IsTransport() function CLIENT:IsTransport()
trace.f(self.ClassName) self:T()
return self.ClientTransport return self.ClientTransport
end 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. --- ShowCargo shows the @{CARGO} within the CLIENT to the Player.
-- The @{CARGO} is shown throught the MESSAGE system of DCS World. -- The @{CARGO} is shown throught the MESSAGE system of DCS World.
function CLIENT:ShowCargo() function CLIENT:ShowCargo()
trace.f(self.ClassName) self:T()
local CargoMsg = "" local CargoMsg = ""
for CargoName, Cargo in pairs( self._Cargos ) do for CargoName, Cargo in pairs( CARGOS ) do
if CargoMsg ~= "" then if self == Cargo:IsLoadedInClient() then
CargoMsg = CargoMsg .. "\n" CargoMsg = CargoMsg .. Cargo.CargoName .. " Type:" .. Cargo.CargoType .. " Weight: " .. Cargo.CargoWeight .. "\n"
end 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 }
end end
end
return self if CargoMsg == "" then
CargoMsg = "empty"
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
end end
self._Cargos[CargoName] = Cargo
self:ShowCargo()
end
return self self:Message( CargoMsg, 15, self.ClientName .. "/Cargo", "Co-Pilot: Cargo Status", 30 )
end
--- 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 end
--- SwitchMessages is a local function called by the DCS World Menu system to switch off messages. --- 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 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. -- @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 ) 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 not self.MenuMessages then
if self:ClientGroup() and self:ClientGroup():getID() then if self:GetClientGroupID() then
self.MenuMessages = MENU_SUB_GROUP:New( self:ClientGroup():getID(), 'Messages' ) self.MenuMessages = MENU_SUB_GROUP:New( self:GetClientGroupID(), 'Messages' )
self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:ClientGroup():getID(), 'Messages On', self.MenuMessages, CLIENT.SwitchMessages, { self, true } ) self.MenuRouteMessageOn = MENU_COMMAND_GROUP:New( self:GetClientGroupID(), '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 } ) self.MenuRouteMessageOff = MENU_COMMAND_GROUP:New( self:GetClientGroupID(),'Messages Off', self.MenuMessages, CLIENT.SwitchMessages, { self, false } )
end end
end end
@ -248,7 +294,7 @@ trace.f( self.ClassName, { Message, MessageDuration, MessageId, MessageCategory,
end end
MESSAGE:New( Message, MessageCategory, MessageDuration, MessageId ):ToClient( self ) MESSAGE:New( Message, MessageCategory, MessageDuration, MessageId ):ToClient( self )
else 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 if timer.getTime() - self.Messages[MessageId].MessageTime >= self.Messages[MessageId].MessageDuration + 10 then
MESSAGE:New( Message, MessageCategory, MessageDuration, MessageId ):ToClient( self ) MESSAGE:New( Message, MessageCategory, MessageDuration, MessageId ):ToClient( self )
self.Messages[MessageId].MessageTime = timer.getTime() self.Messages[MessageId].MessageTime = timer.getTime()

View File

@ -13,6 +13,7 @@ DATABASE = {
NavPoints = {}, NavPoints = {},
Statics = {}, Statics = {},
Players = {}, Players = {},
ActivePlayers = {},
ClientsByName = {}, ClientsByName = {},
ClientsByID = {}, ClientsByID = {},
} }
@ -27,7 +28,7 @@ DATABASECategory =
{ {
[Unit.Category.AIRPLANE] = "Plane", [Unit.Category.AIRPLANE] = "Plane",
[Unit.Category.HELICOPTER] = "Helicopter", [Unit.Category.HELICOPTER] = "Helicopter",
[Unit.Category.GROUND_UNIT] = "Ground", [Unit.Category.GROUND_UNIT] = "Vehicle",
[Unit.Category.SHIP] = "Ship", [Unit.Category.SHIP] = "Ship",
[Unit.Category.STRUCTURE] = "Structure", [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. -- -- 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() -- DBObject = DATABASE:New()
function DATABASE:New() function DATABASE:New()
trace.f(self.ClassName )
-- Inherits from BASE -- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
@ -120,14 +120,14 @@ trace.f(self.ClassName )
return self return self
end end
--- Instantiate new Groups within the DCSRTE. --- 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: -- This method expects EXACTLY the same structure as a structure within the ME, and needs 2 additional fields defined:
-- SpawnCountryID, SpawnCategoryID -- SpawnCountryID, SpawnCategoryID
-- This method is used by the SPAWN class. -- This method is used by the SPAWN class.
function DATABASE:Spawn( SpawnTemplate ) 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 SpawnCountryID = SpawnTemplate.SpawnCountryID
local SpawnCategoryID = SpawnTemplate.SpawnCategoryID local SpawnCategoryID = SpawnTemplate.SpawnCategoryID
@ -140,16 +140,18 @@ trace.f( self.ClassName, SpawnTemplate )
coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate ) coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate )
end end
--- Set a status to a Group within the Database, this to check crossing events for example. --- Set a status to a Group within the Database, this to check crossing events for example.
function DATABASE:SetStatusGroup( GroupName, Status ) function DATABASE:SetStatusGroup( GroupName, Status )
trace.f( self.ClassName, Status ) self:T( Status )
self.Groups[GroupName].Status = Status self.Groups[GroupName].Status = Status
end end
--- Get a status to a Group within the Database, this to check crossing events for example. --- Get a status to a Group within the Database, this to check crossing events for example.
function DATABASE:GetStatusGroup( GroupName ) function DATABASE:GetStatusGroup( GroupName )
trace.f( self.ClassName, Status ) self:T( Status )
if self.Groups[GroupName] then if self.Groups[GroupName] then
return self.Groups[GroupName].Status return self.Groups[GroupName].Status
@ -162,6 +164,7 @@ end
--- Private --- Private
-- @section Private -- @section Private
--- Registers new Group Templates within the DATABASE Object. --- Registers new Group Templates within the DATABASE Object.
function DATABASE:_RegisterGroup( GroupTemplate ) function DATABASE:_RegisterGroup( GroupTemplate )
@ -175,7 +178,9 @@ function DATABASE:_RegisterGroup( GroupTemplate )
self.Groups[GroupTemplateName].Template = GroupTemplate self.Groups[GroupTemplateName].Template = GroupTemplate
self.Groups[GroupTemplateName].groupId = GroupTemplate.groupId self.Groups[GroupTemplateName].groupId = GroupTemplate.groupId
self.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units 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 for unit_num, UnitTemplate in pairs(GroupTemplate.units) do
@ -190,20 +195,24 @@ function DATABASE:_RegisterGroup( GroupTemplate )
self.ClientsByName[UnitTemplateName] = UnitTemplate self.ClientsByName[UnitTemplateName] = UnitTemplate
self.ClientsByID[UnitTemplate.unitId] = UnitTemplate self.ClientsByID[UnitTemplate.unitId] = UnitTemplate
end end
trace.i( self.ClassName, { "Unit", self.Units[UnitTemplateName].UnitName } ) self:T( { "Unit", self.Units[UnitTemplateName].UnitName } )
end end
end end
--- Events --- Events
-- @section Events -- @section Events
--- Track DCSRTE DEAD or CRASH events for the internal scoring. --- Track DCSRTE DEAD or CRASH events for the internal scoring.
function DATABASE:OnDeadOrCrash( event ) function DATABASE:OnDeadOrCrash( event )
trace.f( self.ClassName, { event } ) self:T( { event } )
local TargetUnitName = nil local TargetUnit = nil
local TargetGroupName = nil local TargetGroup = nil
local TargetPlayerName = nil local TargetUnitName = ""
local TargetGroupName = ""
local TargetPlayerName = ""
local TargetCoalition = nil local TargetCoalition = nil
local TargetCategory = nil local TargetCategory = nil
local TargetType = nil local TargetType = nil
@ -212,30 +221,42 @@ trace.f( self.ClassName, { event } )
local TargetUnitType = nil local TargetUnitType = nil
if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
TargetUnitName = event.initiator:getName()
TargetGroupName = Unit.getGroup(event.initiator):getName() TargetUnit = event.initiator
TargetPlayerName = event.initiator:getPlayerName() 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() TargetCoalition = TargetUnit:getCoalition()
TargetCategory = Unit.getGroup(event.initiator):getCategory() --TargetCategory = TargetUnit:getCategory()
TargetType = event.initiator:getTypeName() TargetCategory = TargetUnitDesc.category -- Workaround
TargetType = TargetUnit:getTypeName()
TargetUnitCoalition = DATABASECoalition[TargetCoalition] TargetUnitCoalition = DATABASECoalition[TargetCoalition]
TargetUnitCategory = DATABASECategory[TargetCategory] TargetUnitCategory = DATABASECategory[TargetCategory]
TargetUnitType = TargetType TargetUnitType = TargetType
trace.i( self.ClassName, { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
end end
for PlayerName, PlayerData in pairs( self.Players ) do for PlayerName, PlayerData in pairs( self.Players ) do
if PlayerData then -- This should normally not happen, but i'll test it anyway. 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 -- Some variables
local InitUnitCoalition = DATABASECoalition[PlayerData.UnitCoalition]
local InitUnitCategory = DATABASECategory[PlayerData.UnitCategory]
local InitUnitType = PlayerData.UnitType
local InitUnitName = PlayerData.UnitName 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? -- What is he hitting?
if TargetCategory then if TargetCategory then
@ -251,17 +272,17 @@ trace.f( self.ClassName, { event } )
PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = 0 PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = 0
end 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].Penalty = PlayerData.Kill[TargetCategory][TargetType].Penalty + 25
PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = PlayerData.Kill[TargetCategory][TargetType].PenaltyKill + 1 PlayerData.Kill[TargetCategory][TargetType].PenaltyKill = PlayerData.Kill[TargetCategory][TargetType].PenaltyKill + 1
MESSAGE:New( "Player '" .. PlayerName .. "' killed a target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. MESSAGE:New( "Player '" .. PlayerName .. "' killed a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
PlayerData.Kill[TargetCategory][TargetType].PenaltyKill .. " times. Score: " .. PlayerData.Kill[TargetCategory][TargetType].Penalty, PlayerData.Kill[TargetCategory][TargetType].PenaltyKill .. " times. Penalty: -" .. PlayerData.Kill[TargetCategory][TargetType].Penalty,
"Game Status: Score", 20, "/PENALTY" .. PlayerName .. "/" .. InitUnitName ):ToAll() "Game Status: Penalty", 20, "/PENALTY" .. PlayerName .. "/" .. InitUnitName ):ToAll()
self:ScoreAdd( PlayerName, "KILL_PENALTY", 1, -125, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreAdd( PlayerName, "KILL_PENALTY", 1, -125, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
else else
PlayerData.Kill[TargetCategory][TargetType].Score = PlayerData.Kill[TargetCategory][TargetType].Score + 10 PlayerData.Kill[TargetCategory][TargetType].Score = PlayerData.Kill[TargetCategory][TargetType].Score + 10
PlayerData.Kill[TargetCategory][TargetType].ScoreKill = PlayerData.Kill[TargetCategory][TargetType].ScoreKill + 1 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, PlayerData.Kill[TargetCategory][TargetType].ScoreKill .. " times. Score: " .. PlayerData.Kill[TargetCategory][TargetType].Score,
"Game Status: Score", 20, "/SCORE" .. PlayerName .. "/" .. InitUnitName ):ToAll() "Game Status: Score", 20, "/SCORE" .. PlayerName .. "/" .. InitUnitName ):ToAll()
self:ScoreAdd( PlayerName, "KILL_SCORE", 1, 10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) 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
end end
--- Scheduled --- Scheduled
-- @section Scheduled -- @section Scheduled
--- Follows new players entering Clients within the DCSRTE. --- Follows new players entering Clients within the DCSRTE.
function DATABASE:_FollowPlayers() function DATABASE:_FollowPlayers()
trace.scheduled( self.ClassName, "_FollowPlayers" ) self:T( "_FollowPlayers" )
local ClientUnit = 0 local ClientUnit = 0
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers(coalition.side.RED), AlivePlayersBlue = coalition.getPlayers(coalition.side.BLUE) } 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 = {} local AlivePlayerUnits = {}
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
trace.l( self.ClassName, "_FollowPlayers", CoalitionData ) self:T( { "_FollowPlayers", CoalitionData } )
for UnitId, UnitData in pairs( CoalitionData ) do for UnitId, UnitData in pairs( CoalitionData ) do
self:_AddPlayerFromUnit( UnitData ) self:_AddPlayerFromUnit( UnitData )
end end
end end
end end
--- Private --- Private
-- @section Private -- @section Private
--- Add a new player entering a Unit. --- Add a new player entering a Unit.
function DATABASE:_AddPlayerFromUnit( UnitData ) function DATABASE:_AddPlayerFromUnit( UnitData )
trace.f( self.ClassName, UnitData ) self:T( UnitData )
if UnitData:isExist() then if UnitData:isExist() then
local UnitName = UnitData:getName() 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 self:T( { PlayerName, UnitName, UnitCategory, UnitCoalition, UnitTypeName } )
local GroupName = GroupData:getName()
local PlayerName = UnitData:getPlayerName()
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] = {}
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].Hit = {}
self.Players[PlayerName] = {} self.Players[PlayerName].Kill = {}
self.Players[PlayerName].Hit = {} self.Players[PlayerName].Mission = {}
self.Players[PlayerName].Kill = {}
self.Players[PlayerName].Mission = {} -- for CategoryID, CategoryName in pairs( DATABASECategory ) do
-- self.Players[PlayerName].Hit[CategoryID] = {}
-- for CategoryID, CategoryName in pairs( DATABASECategory ) do -- self.Players[PlayerName].Kill[CategoryID] = {}
-- self.Players[PlayerName].Hit[CategoryID] = {} -- end
-- self.Players[PlayerName].Kill[CategoryID] = {} self.Players[PlayerName].HitPlayers = {}
-- end self.Players[PlayerName].HitUnits = {}
self.Players[PlayerName].HitPlayers = {} self.Players[PlayerName].Penalty = 0
self.Players[PlayerName].HitUnits = {} self.Players[PlayerName].PenaltyCoalition = 0
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()
end 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
end end
--- Registers Scores the players completing a Mission Task. --- Registers Scores the players completing a Mission Task.
function DATABASE:_AddMissionTaskScore( PlayerUnit, MissionName, Score ) function DATABASE:_AddMissionTaskScore( PlayerUnit, MissionName, Score )
trace.f( self.ClassName, { PlayerUnit, MissionName, Score } ) self:T( { PlayerUnit, MissionName, Score } )
local PlayerName = PlayerUnit:getPlayerName() 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].ScoreTask = 0
self.Players[PlayerName].Mission[MissionName].ScoreMission = 0 self.Players[PlayerName].Mission[MissionName].ScoreMission = 0
end end
self:T( PlayerName )
self:T( self.Players[PlayerName].Mission[MissionName] )
self.Players[PlayerName].Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score 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. --- Registers Mission Scores for possible multiple players that contributed in the Mission.
function DATABASE:_AddMissionScore( MissionName, Score ) 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 for PlayerName, PlayerData in pairs( self.Players ) do
@ -388,15 +414,18 @@ trace.f( self.ClassName, { PlayerUnit, MissionName, Score } )
end end
end end
--- Events --- Events
-- @section Events -- @section Events
function DATABASE:OnHit( event )
trace.f( self.ClassName, { event } )
local InitUnitName = nil function DATABASE:OnHit( event )
local InitGroupName = nil self:T( { event } )
local InitPlayerName = nil
local InitUnit = nil
local InitUnitName = ""
local InitGroupName = ""
local InitPlayerName = "dummy"
local InitCoalition = nil local InitCoalition = nil
local InitCategory = nil local InitCategory = nil
@ -405,9 +434,10 @@ trace.f( self.ClassName, { event } )
local InitUnitCategory = nil local InitUnitCategory = nil
local InitUnitType = nil local InitUnitType = nil
local TargetUnitName = nil local TargetUnit = nil
local TargetGroupName = nil local TargetUnitName = ""
local TargetPlayerName = nil local TargetGroupName = ""
local TargetPlayerName = ""
local TargetCoalition = nil local TargetCoalition = nil
local TargetCategory = 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 event.initiator:getName() then
if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT 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() InitUnitName = InitUnit:getName()
InitGroupName = Unit.getGroup(event.initiator):getName() if InitGroup and InitGroup:isExist() then
InitPlayerName = event.initiator:getPlayerName() InitGroupName = InitGroup:getName()
end
InitPlayerName = InitUnit:getPlayerName()
InitCoalition = Unit.getGroup(event.initiator):getCoalition() InitCoalition = InitUnit:getCoalition()
InitCategory = Unit.getGroup(event.initiator):getCategory() --InitCategory = InitUnit:getCategory()
InitType = event.initiator:getTypeName() InitCategory = InitUnitDesc.category -- Workaround
InitType = InitUnit:getTypeName()
InitUnitCoalition = DATABASECoalition[InitCoalition] InitUnitCoalition = DATABASECoalition[InitCoalition]
InitUnitCategory = DATABASECategory[InitCategory] InitUnitCategory = DATABASECategory[InitCategory]
InitUnitType = InitType 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 end
if event.target and Object.getCategory(event.target) == Object.Category.UNIT then 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() TargetUnitName = TargetUnit:getName()
TargetGroupName = Unit.getGroup(event.target):getName() if TargetGroup and TargetGroup:isExist() then
TargetPlayerName = event.target:getPlayerName() TargetGroupName = TargetGroup:getName()
end
TargetPlayerName = TargetUnit:getPlayerName()
TargetCoalition = Unit.getGroup(event.target):getCoalition() TargetCoalition = TargetUnit:getCoalition()
TargetCategory = Unit.getGroup(event.target):getCategory() --TargetCategory = TargetUnit:getCategory()
TargetType = event.target:getTypeName() TargetCategory = TargetUnitDesc.category -- Workaround
TargetType = TargetUnit:getTypeName()
TargetUnitCoalition = DATABASECoalition[TargetCoalition] TargetUnitCoalition = DATABASECoalition[TargetCoalition]
TargetUnitCategory = DATABASECategory[TargetCategory] TargetUnitCategory = DATABASECategory[TargetCategory]
TargetUnitType = TargetType 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 end
if InitPlayerName ~= nil then -- It is a player that is hitting something 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 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 ... 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 self.Players[InitPlayerName].HitPlayers = self.Players[InitPlayerName].HitPlayers + 1
end end
trace.i( self.ClassName, "Hitting Something" ) self:T( "Hitting Something" )
-- What is he hitting? -- What is he hitting?
if TargetCategory then if TargetCategory then
if not self.Players[InitPlayerName].Hit[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].Penalty = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].Penalty + 10
self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit + 1 self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit = self.Players[InitPlayerName].Hit[TargetCategory][TargetUnitName].PenaltyHit + 1
MESSAGE:New( "Player '" .. InitPlayerName .. "' hit a friendly " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " .. 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() "Game Status: Penalty", 20, "/PENALTY" .. InitPlayerName .. "/" .. InitUnitName ):ToAll()
self:ScoreAdd( InitPlayerName, "HIT_PENALTY", 1, -25, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) self:ScoreAdd( InitPlayerName, "HIT_PENALTY", 1, -25, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
else else
@ -498,14 +544,132 @@ trace.f( self.ClassName, { event } )
end end
end end
function DATABASE:ReportScoreAll() function DATABASE:ReportScoreAll()
env.info( "Hello World " )
local ScoreMessage = "" local ScoreMessage = ""
local PlayerMessage = "" local PlayerMessage = ""
self:T( "Score Report" )
for PlayerName, PlayerData in pairs( self.Players ) do for PlayerName, PlayerData in pairs( self.Players ) do
if PlayerData then -- This should normally not happen, but i'll test it anyway. 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 -- Some variables
local InitUnitCoalition = DATABASECoalition[PlayerData.UnitCoalition] local InitUnitCoalition = DATABASECoalition[PlayerData.UnitCoalition]
@ -521,18 +685,22 @@ function DATABASE:ReportScoreAll()
local ScoreMessageHits = "" local ScoreMessageHits = ""
for CategoryID, CategoryName in pairs( DATABASECategory ) do for CategoryID, CategoryName in pairs( DATABASECategory ) do
self:T( CategoryName )
if PlayerData.Hit[CategoryID] then if PlayerData.Hit[CategoryID] then
local Score = 0 local Score = 0
local ScoreHit = 0 local ScoreHit = 0
local Penalty = 0 local Penalty = 0
local PenaltyHit = 0 local PenaltyHit = 0
self:T( "Hit scores exist for player " .. PlayerName )
for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do for UnitName, UnitData in pairs( PlayerData.Hit[CategoryID] ) do
Score = Score + UnitData.Score Score = Score + UnitData.Score
ScoreHit = ScoreHit + UnitData.ScoreHit ScoreHit = ScoreHit + UnitData.ScoreHit
Penalty = Penalty + UnitData.Penalty Penalty = Penalty + UnitData.Penalty
PenaltyHit = UnitData.PenaltyHit PenaltyHit = UnitData.PenaltyHit
end 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 PlayerScore = PlayerScore + Score
PlayerPenalty = PlayerPenalty + Penalty PlayerPenalty = PlayerPenalty + Penalty
else else
@ -540,11 +708,12 @@ function DATABASE:ReportScoreAll()
end end
end end
if ScoreMessageHits ~= "" then if ScoreMessageHits ~= "" then
ScoreMessage = ScoreMessage .. " Hits: " .. ScoreMessageHits .. " " ScoreMessage = ScoreMessage .. "\n Hits: " .. ScoreMessageHits .. " "
end end
local ScoreMessageKills = "" local ScoreMessageKills = ""
for CategoryID, CategoryName in pairs( DATABASECategory ) do for CategoryID, CategoryName in pairs( DATABASECategory ) do
self:T( "Kill scores exist for player " .. PlayerName )
if PlayerData.Kill[CategoryID] then if PlayerData.Kill[CategoryID] then
local Score = 0 local Score = 0
local ScoreKill = 0 local ScoreKill = 0
@ -557,8 +726,10 @@ function DATABASE:ReportScoreAll()
Penalty = Penalty + UnitData.Penalty Penalty = Penalty + UnitData.Penalty
PenaltyKill = PenaltyKill + UnitData.PenaltyKill PenaltyKill = PenaltyKill + UnitData.PenaltyKill
end 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 PlayerScore = PlayerScore + Score
PlayerPenalty = PlayerPenalty + Penalty PlayerPenalty = PlayerPenalty + Penalty
@ -567,16 +738,16 @@ function DATABASE:ReportScoreAll()
end end
end end
if ScoreMessageKills ~= "" then if ScoreMessageKills ~= "" then
ScoreMessage = ScoreMessage .. " Kills: " .. ScoreMessageKills .. " " ScoreMessage = ScoreMessage .. "\n Kills: " .. ScoreMessageKills .. " "
end end
local ScoreMessageCoalitionChangePenalties = "" local ScoreMessageCoalitionChangePenalties = ""
if PlayerData.PenaltyCoalition ~= 0 then 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 PlayerPenalty = PlayerPenalty + PlayerData.Penalty
end end
if ScoreMessageCoalitionChangePenalties ~= "" then if ScoreMessageCoalitionChangePenalties ~= "" then
ScoreMessage = ScoreMessage .. " Coalition: " .. ScoreMessageCoalitionChangePenalties .. " " ScoreMessage = ScoreMessage .. "\n Coalition: " .. ScoreMessageCoalitionChangePenalties .. " "
end end
local ScoreMessageMission = "" local ScoreMessageMission = ""
@ -590,26 +761,26 @@ function DATABASE:ReportScoreAll()
PlayerScore = PlayerScore + ScoreMission + ScoreTask PlayerScore = PlayerScore + ScoreMission + ScoreTask
if ScoreMessageMission ~= "" then if ScoreMessageMission ~= "" then
ScoreMessage = ScoreMessage .. " Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ") " ScoreMessage = ScoreMessage .. "\n Tasks: " .. ScoreTask .. " Mission: " .. ScoreMission .. " ( " .. ScoreMessageMission .. ") "
end end
PlayerMessage = string.format( " Player '%s' Score = %d ( %d Score, -%d Penalties ):", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty ) PlayerMessage = PlayerMessage .. string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties ):%s", PlayerName, PlayerScore - PlayerPenalty, PlayerScore, PlayerPenalty, ScoreMessage )
MESSAGE:New( PlayerMessage .. ScoreMessage, "Player Scores", 30, "/SCORE/" .. PlayerName ):ToAll()
end end
end end
end MESSAGE:New( PlayerMessage, "Player Scores", 30, "AllPlayerScores"):ToAll()
function DATABASE:ReportScorePlayer()
end end
function DATABASE:ScoreMenu() function DATABASE:ScoreMenu()
local ReportScore = SUBMENU:New( 'Scoring' ) local ReportScore = SUBMENU:New( 'Scoring' )
local ReportAllScores = COMMANDMENU:New( 'Score All Active Players', ReportScore, DATABASE.ReportScoreAll, self ) local ReportAllScores = COMMANDMENU:New( 'Score All Active Players', ReportScore, DATABASE.ReportScoreAll, self )
local ReportPlayerScores = COMMANDMENU:New('Your Current Score', ReportScore, DATABASE.ReportScorePlayer, self ) local ReportPlayerScores = COMMANDMENU:New('Your Current Score', ReportScore, DATABASE.ReportScorePlayer, self )
end end
-- File Logic for tracking the scores -- File Logic for tracking the scores
function DATABASE:SecondsToClock(sSeconds) function DATABASE:SecondsToClock(sSeconds)
@ -625,6 +796,7 @@ local nSeconds = sSeconds
end end
end end
function DATABASE:ScoreOpen() function DATABASE:ScoreOpen()
if lfs then if lfs then
local fdir = lfs.writedir() .. [[Logs\]] .. "Player_Scores_" .. os.date( "%Y-%m-%d_%H-%M-%S" ) .. ".csv" 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 if not self.StatFile then
error( "Error: Cannot open 'Player Scores.csv' file in " .. lfs.writedir() ) error( "Error: Cannot open 'Player Scores.csv' file in " .. lfs.writedir() )
end 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") self.RunID = os.date("%y-%m-%d_%H-%M-%S")
end end
end end
function DATABASE:ScoreAdd( PlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType ) function DATABASE:ScoreAdd( PlayerName, ScoreType, ScoreTimes, ScoreAmount, PlayerUnitName, PlayerUnitCoalition, PlayerUnitCategory, PlayerUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
--write statistic information to file --write statistic information to file
local ScoreTime = self:SecondsToClock(timer.getTime()) local ScoreTime = self:SecondsToClock(timer.getTime())
@ -648,11 +821,12 @@ function DATABASE:ScoreAdd( PlayerName, ScoreType, ScoreTimes, ScoreAmount, Play
if PlayerUnit then if PlayerUnit then
if not PlayerUnitCategory then if not PlayerUnitCategory then
PlayerUnitCategory = DATABASECategory[Unit.getGroup(PlayerUnit):getCategory()] --PlayerUnitCategory = DATABASECategory[PlayerUnit:getCategory()]
PlayerUnitCategory = DATABASECategory[PlayerUnit:getDesc().category]
end end
if not PlayerUnitCoalition then if not PlayerUnitCoalition then
PlayerUnitCoalition = DATABASECoalition[Unit.getGroup(PlayerUnit):getCoalition()] PlayerUnitCoalition = DATABASECoalition[PlayerUnit:getCoalition()]
end end
if not PlayerUnitType then if not PlayerUnitType then
@ -695,6 +869,7 @@ function DATABASE:ScoreAdd( PlayerName, ScoreType, ScoreTimes, ScoreAmount, Play
self.StatFile:write( "\n" ) self.StatFile:write( "\n" )
end end
end end
function LogClose() function LogClose()
if lfs then 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. --- 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 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. -- @tparam CARGO_TYPE CargoType Type of the Cargo.
function DEPLOYTASK:New( LandingZones, CargoType ) function DEPLOYTASK:New( CargoType )
trace.f(self.ClassName) 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 local Valid = true
Valid = routines.ValidateZone( LandingZones, "LandingZones", Valid )
Valid = routines.ValidateEnumeration( CargoType, "CargoType", CARGO_TYPE, Valid )
if Valid then if Valid then
Child.Name = 'Deploy Cargo' self.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." 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."
if type( LandingZones ) == "table" then self.CargoType = CargoType
Child.LandingZones = LandingZones self.GoalVerb = CargoType .. " " .. self.GoalVerb
else self.Stages = { STAGE_CARGO_INIT:New(), STAGE_CARGO_LOAD:New(), STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGEUNLOAD:New(), STAGEDONE:New() }
Child.LandingZones = { LandingZones } self.SetStage( self, 1 )
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 )
end 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 end
--- When the cargo is unloaded, it will move to the target zone name. --- 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. -- @tparam string TargetZoneName Name of the Zone to where the Cargo should move after unloading.
function DEPLOYTASK:SetCargoTargetZoneName( TargetZoneName ) function DEPLOYTASK:SetCargoTargetZoneName( TargetZoneName )
trace.f(self.ClassName) self:T()
local Valid = true local Valid = true
@ -60,57 +85,68 @@ trace.f(self.ClassName)
end end
function DEPLOYTASK:AddCargoMenus( Client, Cargos, TransportRadius ) 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 } ) trace.i( self.ClassName, { Cargo.ClassName, Cargo.CargoName, Cargo.CargoType, Cargo.CargoWeight } )
if Client._Menus[CargoData.CargoType] == nil then
Client._Menus[CargoData.CargoType] = {}
end
if not Client._Menus[CargoData.CargoType].DeployMenu then if Cargo:IsStatusLoaded() and Client == Cargo:IsLoadedInClient() then
Client._Menus[CargoData.CargoType].DeployMenu = missionCommands.addSubMenuForGroup(
Client:ClientGroup():getID(), if Client._Menus[Cargo.CargoType] == nil then
self.TEXT[1], Client._Menus[Cargo.CargoType] = {}
nil 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 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
end end
function DEPLOYTASK:RemoveCargoMenus( Client ) 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 for MenuID, MenuData in pairs( Client._Menus ) do
if MenuData.DeploySubMenus ~= nil then if MenuData.DeploySubMenus ~= nil then
for SubMenuID, SubMenuData in pairs( MenuData.DeploySubMenus ) do for SubMenuID, SubMenuData in pairs( MenuData.DeploySubMenus ) do
missionCommands.removeItemForGroup( Client:ClientGroup():getID(), SubMenuData ) missionCommands.removeItemForGroup( ClientGroupID, SubMenuData )
trace.i( self.ClassName, "Removed DeploySubMenu " ) trace.i( self.ClassName, "Removed DeploySubMenu " )
SubMenuData = nil SubMenuData = nil
end end
end end
if MenuData.DeployMenu then if MenuData.DeployMenu then
missionCommands.removeItemForGroup( Client:ClientGroup():getID(), MenuData.DeployMenu ) missionCommands.removeItemForGroup( ClientGroupID, MenuData.DeployMenu )
trace.i( self.ClassName, "Removed DeployMenu " ) trace.i( self.ClassName, "Removed DeployMenu " )
MenuData.DeployMenu = nil MenuData.DeployMenu = nil
end 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}. -- @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 -- @treturn DESTROYBASETASK
function DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupPrefixes, DestroyPercentage ) function DESTROYBASETASK:New( DestroyGroupType, DestroyUnitType, DestroyGroupPrefixes, DestroyPercentage )
trace.f(self.ClassName) local self = BASE:Inherit( self, TASK:New() )
self:T()
-- Inheritance
local Child = BASE:Inherit( self, TASK:New() )
Child.Name = 'Destroy' self.Name = 'Destroy'
Child.Destroyed = 0 self.Destroyed = 0
Child.DestroyGroupPrefixes = DestroyGroupPrefixes self.DestroyGroupPrefixes = DestroyGroupPrefixes
Child.DestroyGroupType = DestroyGroupType self.DestroyGroupType = DestroyGroupType
Child.DestroyUnitType = DestroyUnitType self.DestroyUnitType = DestroyUnitType
Child.TaskBriefing = "Task: Destroy " .. DestroyGroupType .. "." self.TaskBriefing = "Task: Destroy " .. DestroyGroupType .. "."
Child.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEGROUPSDESTROYED:New(), STAGEDONE:New() } self.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEGROUPSDESTROYED:New(), STAGEDONE:New() }
Child.SetStage( Child, 1 ) 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) ) --env.info( 'New Table self = ' .. tostring(self) )
return Child return self
end end
--- Handle the S_EVENT_DEAD events to validate the destruction of units for the task monitoring. --- Handle the S_EVENT_DEAD events to validate the destruction of units for the task monitoring.
-- @param event Event structure of DCS world. -- @param event Event structure of DCS world.
function DESTROYBASETASK:EventDead( event ) function DESTROYBASETASK:EventDead( event )
trace.f( self.ClassName, { 'EventDead', event } ) self:T( { 'EventDead', event } )
if event.initiator then if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
local DestroyGroup = Unit.getGroup( event.initiator )
local DestroyGroupName = DestroyGroup:getName()
local DestroyUnit = event.initiator local DestroyUnit = event.initiator
local DestroyUnitName = DestroyUnit:getName() 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 local UnitsDestroyed = 0
trace.i( self.ClassName, DestroyGroupName ) self:T( DestroyGroupName )
trace.i( self.ClassName, DestroyUnitName ) self:T( DestroyUnitName )
for DestroyGroupPrefixID, DestroyGroupPrefix in pairs( self.DestroyGroupPrefixes ) do for DestroyGroupPrefixID, DestroyGroupPrefix in pairs( self.DestroyGroupPrefixes ) do
trace.i( self.ClassName, DestroyGroupPrefix ) self:T( DestroyGroupPrefix )
if string.find( DestroyGroupName, DestroyGroupPrefix, 1, true ) then 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 ) UnitsDestroyed = self:ReportGoalProgress( DestroyGroup, DestroyUnit )
trace.i( self.ClassName, UnitsDestroyed ) self:T( UnitsDestroyed )
end end
end end
trace.i( self.ClassName, { UnitsDestroyed } ) self:T( { UnitsDestroyed } )
self:IncreaseGoalCount( UnitsDestroyed, self.GoalVerb ) self:IncreaseGoalCount( UnitsDestroyed, self.GoalVerb )
end end
end end
@ -73,7 +74,7 @@ end
-- @param DestroyGroup Group structure describing the group to be evaluated. -- @param DestroyGroup Group structure describing the group to be evaluated.
-- @param DestroyUnit Unit structure describing the Unit to be evaluated. -- @param DestroyUnit Unit structure describing the Unit to be evaluated.
function DESTROYBASETASK:ReportGoalProgress( DestroyGroup, DestroyUnit ) function DESTROYBASETASK:ReportGoalProgress( DestroyGroup, DestroyUnit )
trace.f(self.ClassName) self:T()
return 0 return 0
end 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 ) function MESSAGE:ToClient( Client )
trace.f(self.ClassName ) 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 ) 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 end
return self return self
end 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. --- Sends a MESSAGE to a Coalition.
-- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}. -- @param CoalitionSide needs to be filled out by the defined structure of the standard scripting engine @{coalition.side}.
-- @treturn MESSAGE -- @treturn MESSAGE

View File

@ -4,7 +4,6 @@
Include.File( "Routines" ) Include.File( "Routines" )
Include.File( "Base" ) Include.File( "Base" )
Include.File( "Mission" )
Include.File( "Client" ) Include.File( "Client" )
Include.File( "Task" ) Include.File( "Task" )
@ -16,7 +15,6 @@ MISSION = {
_Clients = {}, _Clients = {},
_Tasks = {}, _Tasks = {},
_ActiveTasks = {}, _ActiveTasks = {},
_Cargos = {},
GoalFunction = nil, GoalFunction = nil,
MissionReportTrigger = 0, MissionReportTrigger = 0,
MissionProgressTrigger = 0, MissionProgressTrigger = 0,
@ -30,23 +28,13 @@ MISSION = {
_GoalTasks = {} _GoalTasks = {}
} }
CARGOSTATUS = {
NONE = 0,
LOADED = 1,
UNLOADED = 2,
LOADING = 3,
LoadCount= 0,
UnloadCount = 0
}
function MISSION:Meta() function MISSION:Meta()
trace.f(self.ClassName)
-- Arrange meta tables local self = BASE:Inherit( self, BASE:New() )
local Child = BASE:Inherit( self, BASE:New() ) self:T()
trace.r( self.ClassName, "", { Child } )
return Child return self
end end
--- This is the main MISSION declaration method. Each Mission is like the master or a Mission orchestration between, Clients, Tasks, Stages etc. --- 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( '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' ) -- 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 ) function MISSION:New( MissionName, MissionPriority, MissionBriefing, MissionCoalition )
trace.f(self.ClassName, { MissionName, MissionPriority, MissionBriefing, MissionCoalition } )
self = MISSION:Meta() self = MISSION:Meta()
self:T({ MissionName, MissionPriority, MissionBriefing, MissionCoalition })
local Valid = true local Valid = true
@ -83,20 +72,19 @@ trace.f(self.ClassName, { MissionName, MissionPriority, MissionBriefing, Mission
self.MissionCoalition = MissionCoalition self.MissionCoalition = MissionCoalition
end end
trace.r( self.ClassName, "" )
return self return self
end end
--- Returns if a Mission has completed. --- Returns if a Mission has completed.
-- @treturn bool -- @treturn bool
function MISSION:IsCompleted() function MISSION:IsCompleted()
trace.f(self.ClassName) self:T()
return self.MissionStatus == "ACCOMPLISHED" return self.MissionStatus == "ACCOMPLISHED"
end end
--- Set a Mission to completed. --- Set a Mission to completed.
function MISSION:Completed() function MISSION:Completed()
trace.f(self.ClassName) self:T()
self.MissionStatus = "ACCOMPLISHED" self.MissionStatus = "ACCOMPLISHED"
self:StatusToClients() self:StatusToClients()
end end
@ -104,27 +92,27 @@ end
--- Returns if a Mission is ongoing. --- Returns if a Mission is ongoing.
-- treturn bool -- treturn bool
function MISSION:IsOngoing() function MISSION:IsOngoing()
trace.f(self.ClassName) self:T()
return self.MissionStatus == "ONGOING" return self.MissionStatus == "ONGOING"
end end
--- Set a Mission to ongoing. --- Set a Mission to ongoing.
function MISSION:Ongoing() function MISSION:Ongoing()
trace.f(self.ClassName) self:T()
self.MissionStatus = "ONGOING" self.MissionStatus = "ONGOING"
self:StatusToClients() --self:StatusToClients()
end end
--- Returns if a Mission is pending. --- Returns if a Mission is pending.
-- treturn bool -- treturn bool
function MISSION:IsPending() function MISSION:IsPending()
trace.f(self.ClassName) self:T()
return self.MissionStatus == "PENDING" return self.MissionStatus == "PENDING"
end end
--- Set a Mission to pending. --- Set a Mission to pending.
function MISSION:Pending() function MISSION:Pending()
trace.f(self.ClassName) self:T()
self.MissionStatus = "PENDING" self.MissionStatus = "PENDING"
self:StatusToClients() self:StatusToClients()
end end
@ -132,31 +120,31 @@ end
--- Returns if a Mission has failed. --- Returns if a Mission has failed.
-- treturn bool -- treturn bool
function MISSION:IsFailed() function MISSION:IsFailed()
trace.f(self.ClassName) self:T()
return self.MissionStatus == "FAILED" return self.MissionStatus == "FAILED"
end end
--- Set a Mission to failed. --- Set a Mission to failed.
function MISSION:Failed() function MISSION:Failed()
trace.f(self.ClassName) self:T()
self.MissionStatus = "FAILED" self.MissionStatus = "FAILED"
self:StatusToClients() self:StatusToClients()
end end
--- Send the status of the MISSION to all Clients. --- Send the status of the MISSION to all Clients.
function MISSION:StatusToClients() function MISSION:StatusToClients()
trace.f(self.ClassName) self:T()
if timer.getTime() >= self.MissionReportTrigger then if self.MissionReportFlash then
for ClientID, Client in pairs( self._Clients ) do 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") Client:Message( self.MissionCoalition .. ' "' .. self.Name .. '": ' .. self.MissionStatus .. '! ( ' .. self.MissionPriority .. ' mission ) ', 10, self.Name .. '/Status', "Mission Command: Mission Status")
end end
end end
trace.e()
end end
--- Handles the reporting. After certain time intervals, a MISSION report MESSAGE will be shown to All Players. --- Handles the reporting. After certain time intervals, a MISSION report MESSAGE will be shown to All Players.
function MISSION:ReportTrigger() function MISSION:ReportTrigger()
trace.f(self.ClassName) self:T()
if self.MissionReportShow == true then if self.MissionReportShow == true then
self.MissionReportShow = false self.MissionReportShow = false
trace.r( "MISSION", "1", { true } ) trace.r( "MISSION", "1", { true } )
@ -181,16 +169,17 @@ end
--- Report the status of all MISSIONs to all active Clients. --- Report the status of all MISSIONs to all active Clients.
function MISSION:ReportToAll() function MISSION:ReportToAll()
trace.f(self.ClassName) self:T()
local AlivePlayers = '' local AlivePlayers = ''
for ClientID, Client in pairs( self._Clients ) do for ClientID, Client in pairs( self._Clients ) do
if Client:ClientGroup() then if Client:ClientGroup() then
if Client:ClientGroup():getUnit(1) then if Client:GetClientGroupUnit() then
if Client:ClientGroup():getUnit(1):getLife() > 0.0 then if Client:GetClientGroupUnit():getLife() > 0.0 then
if AlivePlayers == '' then if AlivePlayers == '' then
AlivePlayers = ' Players: ' .. Client:ClientGroup():getUnit(1):getPlayerName() AlivePlayers = ' Players: ' .. Client:GetClientGroupUnit():getPlayerName()
else else
AlivePlayers = AlivePlayers .. ' / ' .. Client:ClientGroup():getUnit(1):getPlayerName() AlivePlayers = AlivePlayers .. ' / ' .. Client:GetClientGroupUnit():getPlayerName()
end end
end end
end end
@ -202,7 +191,6 @@ trace.f(self.ClassName)
TaskText = TaskText .. " - Task " .. TaskID .. ": " .. TaskData.Name .. ": " .. TaskData:GetGoalProgress() .. "\n" TaskText = TaskText .. " - Task " .. TaskID .. ": " .. TaskData.Name .. ": " .. TaskData:GetGoalProgress() .. "\n"
end 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() 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 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' ) -- 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 ) -- Mission:AddGoalFunction( DeployPatriotTroopsGoal )
function MISSION:AddGoalFunction( GoalFunction ) function MISSION:AddGoalFunction( GoalFunction )
trace.f(self.ClassName) self:T()
self.GoalFunction = GoalFunction self.GoalFunction = GoalFunction
trace.e()
end end
--- Show the briefing of the MISSION to the CLIENT. --- Show the briefing of the MISSION to the CLIENT.
-- @tparam CLIENT Client to show briefing to. -- @tparam CLIENT Client to show briefing to.
-- @treturn CLIENT -- @treturn CLIENT
function MISSION:ShowBriefing( Client ) function MISSION:ShowBriefing( Client )
trace.f(self.ClassName, { Client } ) self:T( { Client.ClientName } )
if not Client.ClientBriefingShown then if not Client.ClientBriefingShown then
Client.ClientBriefingShown = true Client.ClientBriefingShown = true
Client:Message( '(Press the keys [LEFT ALT]+[B] to view the briefing pages. Browse through the graphical briefing.)\n' .. local Briefing = self.MissionBriefing
self.MissionBriefing, 40, self.Name .. '/MissionBriefing', "Mission Command: Mission Briefing" )
if Client.ClientBriefing then if Client.ClientBriefing then
Client:Message( Client.ClientBriefing, 40, self.Name .. '/ClientBriefing', "Mission Command: Mission Briefing" ) Briefing = Briefing .. "\n" .. Client.ClientBriefing
end end
Briefing = Briefing .. "\n (Press [LEFT ALT]+[B] to view the graphical documentation.)"
Client:Message( Briefing, 30, self.Name .. '/MissionBriefing', "Command: Mission Briefing" )
end end
trace.r( "", "", { Client } )
return Client return Client
end 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*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() ) -- 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 ) function MISSION:AddClient( Client )
trace.f(self.ClassName, { Client } ) self:T( { Client } )
local Valid = true local Valid = true
@ -296,8 +283,7 @@ end
-- -- Seach for Client "Bomber" within the Mission. -- -- Seach for Client "Bomber" within the Mission.
-- local BomberClient = Mission:FindClient( "Bomber" ) -- local BomberClient = Mission:FindClient( "Bomber" )
function MISSION:FindClient( ClientName ) function MISSION:FindClient( ClientName )
trace.f(self.ClassName) self:T( { self._Clients[ClientName] } )
trace.r( "", "", { self._Clients[ClientName] } )
return self._Clients[ClientName] return self._Clients[ClientName]
end end
@ -328,13 +314,12 @@ end
-- Mission:AddTask( DeployTask, 2 ) -- Mission:AddTask( DeployTask, 2 )
function MISSION:AddTask( Task, TaskNumber ) function MISSION:AddTask( Task, TaskNumber )
trace.f(self.ClassName) self:T()
self._Tasks[TaskNumber] = Task self._Tasks[TaskNumber] = Task
self._Tasks[TaskNumber]:EnableEvents() self._Tasks[TaskNumber]:EnableEvents()
self._Tasks[TaskNumber].ID = TaskNumber self._Tasks[TaskNumber].ID = TaskNumber
trace.r( self.ClassName, "" )
return Task return Task
end end
@ -346,7 +331,7 @@ trace.r( self.ClassName, "" )
-- Task2 = Mission:GetTask( 2 ) -- Task2 = Mission:GetTask( 2 )
function MISSION:GetTask( TaskNumber ) function MISSION:GetTask( TaskNumber )
trace.f(self.ClassName) self:T()
local Valid = true local Valid = true
@ -370,51 +355,11 @@ end
-- Tasks = Mission:GetTasks() -- Tasks = Mission:GetTasks()
-- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" ) -- env.info( "Task 2 Completion = " .. Tasks[2]:GetGoalPercentage() .. "%" )
function MISSION:GetTasks() function MISSION:GetTasks()
trace.f(self.ClassName) self:T()
return self._Tasks return self._Tasks
end 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. _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 -- loop through the missions in the TransportTasks
for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do for MissionName, Mission in pairs( MISSIONSCHEDULER.Missions ) do
trace.i( "MISSIONSCHEDULER", MissionName )
if not Mission:IsCompleted() then if not Mission:IsCompleted() then
@ -457,8 +404,10 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
local ClientsAlive = false local ClientsAlive = false
for ClientID, Client in pairs( Mission._Clients ) do 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. -- There is at least one Client that is alive... So the Mission status is set to Ongoing.
ClientsAlive = true ClientsAlive = true
@ -476,13 +425,10 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
Client._Tasks[TaskNumber] = routines.utils.deepCopy( Mission._Tasks[TaskNumber] ) Client._Tasks[TaskNumber] = routines.utils.deepCopy( Mission._Tasks[TaskNumber] )
-- Each MissionTask must point to the original Mission. -- Each MissionTask must point to the original Mission.
Client._Tasks[TaskNumber].MissionTask = Mission._Tasks[TaskNumber] Client._Tasks[TaskNumber].MissionTask = Mission._Tasks[TaskNumber]
Client._Tasks[TaskNumber].Cargos = Mission._Tasks[TaskNumber].Cargos
Client._Tasks[TaskNumber].LandingZones = Mission._Tasks[TaskNumber].LandingZones
end 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() Mission:Ongoing()
end end
@ -524,6 +470,7 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
end end
if Task:IsDone() then 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" ) ) --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 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 if Mission.GoalFunction ~= nil then
Mission.GoalFunction( Mission, Client ) Mission.GoalFunction( Mission, Client )
end end
_Database:_AddMissionTaskScore( Client:ClientGroup():getUnit(1), Mission.Name, 25 ) _Database:_AddMissionTaskScore( Client:GetClientGroupUnit(), Mission.Name, 25 )
-- if not Mission:IsCompleted() then -- if not Mission:IsCompleted() then
-- end -- end
@ -580,9 +527,6 @@ trace.scheduled("MISSIONSCHEDULER","Scheduler")
-- So first sanitize Client._Tasks[TaskNumber].MissionTask, after that, sanitize only the whole _Tasks structure... -- So first sanitize Client._Tasks[TaskNumber].MissionTask, after that, sanitize only the whole _Tasks structure...
--Client._Tasks[TaskNumber].MissionTask = nil --Client._Tasks[TaskNumber].MissionTask = nil
--Client._Tasks = 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 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 ) -- 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 ) function MOVEMENT:New( MovePrefixes, MoveMaximum )
trace.f(self.ClassName, { MovePrefixes, MoveMaximum } ) local self = BASE:Inherit( self, BASE:New() )
self:T( { MovePrefixes, MoveMaximum } )
-- Inherits from BASE
local Child = BASE:Inherit( self, BASE:New() )
if type( MovePrefixes ) == 'table' then if type( MovePrefixes ) == 'table' then
Child.MovePrefixes = MovePrefixes self.MovePrefixes = MovePrefixes
else else
Child.MovePrefixes = { MovePrefixes } self.MovePrefixes = { MovePrefixes }
end end
Child.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart. self.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... self.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 self.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.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 ) self.AddEvent( self, world.event.S_EVENT_BIRTH, self.OnBirth )
Child.AddEvent( Child, world.event.S_EVENT_DEAD, Child.OnDeadOrCrash ) self.AddEvent( self, world.event.S_EVENT_DEAD, self.OnDeadOrCrash )
Child.AddEvent( Child, world.event.S_EVENT_CRASH, Child.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 end
--- Call this function to start the MOVEMENT scheduling. --- Call this function to start the MOVEMENT scheduling.
function MOVEMENT:ScheduleStart() function MOVEMENT:ScheduleStart()
trace.f( self.ClassName ) self:T()
self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 ) self.MoveFunction = routines.scheduleFunction( self._Scheduler, { self }, timer.getTime() + 1, 120 )
end end
--- Call this function to stop the MOVEMENT scheduling. --- Call this function to stop the MOVEMENT scheduling.
-- @todo need to implement it ... Forgot. -- @todo need to implement it ... Forgot.
function MOVEMENT:ScheduleStop() function MOVEMENT:ScheduleStop()
trace.f( self.ClassName ) self:T()
end end
--- Captures the birth events when new Units were spawned. --- Captures the birth events when new Units were spawned.
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration. -- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
function MOVEMENT:OnBirth( event ) 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 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 if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
trace.l(self.ClassName, "OnBirth", "Birth object : " .. event.initiator:getName() ) local MovementUnit = event.initiator
local GroupData = Unit.getGroup(event.initiator) local MovementUnitName = MovementUnit:getName()
if GroupData and GroupData:isExist() then self:T( "Birth object : " .. MovementUnitName )
local EventGroupName = GroupData:getName() local MovementGroup = MovementUnit:getGroup()
if MovementGroup and MovementGroup:isExist() then
local MovementGroupName = MovementGroup:getName()
for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do 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.AliveUnits = self.AliveUnits + 1
self.MoveGroups[EventGroupName] = EventGroupName self.MoveUnits[MovementUnitName] = MovementGroupName
trace.l(self.ClassName, "OnBirth", self.AliveUnits ) self:T( self.AliveUnits )
end end
end end
end end
@ -86,16 +86,17 @@ end
--- Captures the Dead or Crash events when Units crash or are destroyed. --- 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. -- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
function MOVEMENT:OnDeadOrCrash( event ) function MOVEMENT:OnDeadOrCrash( event )
trace.f( self.ClassName, { event } ) self:T( { event } )
if event.initiator and event.initiator:getName() then if event.initiator and Object.getCategory(event.initiator) == Object.Category.UNIT then
trace.l( self.ClassName, "OnDeadOrCrash", "Dead object : " .. event.initiator:getName() ) local MovementUnit = event.initiator
local EventGroupName = Unit.getGroup(event.initiator):getName() local MovementUnitName = MovementUnit:getName()
self:T( "Dead object : " .. MovementUnitName )
for MovePrefixID, MovePrefix in pairs( self.MovePrefixes ) do 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.AliveUnits = self.AliveUnits - 1
self.MoveGroups[EventGroupName] = nil self.MoveUnits[MovementUnitName] = nil
trace.l( self.ClassName, "OnDeadOrCrash", self.AliveUnits ) self:T( self.AliveUnits )
end end
end 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. --- This function is called automatically by the MOVEMENT scheduler. A new function is scheduled when MoveScheduled is true.
function MOVEMENT:_Scheduler() 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 if self.AliveUnits > 0 then
local MoveProbability = ( self.MoveMaximum * 100 ) / self.AliveUnits 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 for MovementUnitName, MovementGroupName in pairs( self.MoveUnits ) do
local MoveGroup = Group.getByName( MoveGroupName ) local MovementGroup = Group.getByName( MovementGroupName )
if MoveGroup then if MovementGroup and MovementGroup:isExist() then
local MoveOrStop = math.random( 1, 100 ) local MoveOrStop = math.random( 1, 100 )
trace.l( self.ClassName, '_Scheduler', 'MoveOrStop = ' .. MoveOrStop ) self:T( 'MoveOrStop = ' .. MoveOrStop )
if MoveOrStop <= MoveProbability then if MoveOrStop <= MoveProbability then
trace.l( self.ClassName, '_Scheduler', 'Group continues moving = ' .. MoveGroupName ) self:T( 'Group continues moving = ' .. MovementGroupName )
trigger.action.groupContinueMoving( MoveGroup ) trigger.action.groupContinueMoving( MovementGroup )
else else
trace.l( self.ClassName, '_Scheduler', 'Group stops moving = ' .. MoveGroupName ) self:T( 'Group stops moving = ' .. MovementGroupName )
trigger.action.groupStopMoving( MoveGroup ) trigger.action.groupStopMoving( MovementGroup )
end end
else
self.MoveUnits[MovementUnitName] = nil
end end
end end
end end

View File

@ -3,6 +3,7 @@
-- @parent TASK -- @parent TASK
Include.File("Task") Include.File("Task")
Include.File("Cargo")
PICKUPTASK = { PICKUPTASK = {
ClassName = "PICKUPTASK", ClassName = "PICKUPTASK",
@ -14,87 +15,103 @@ PICKUPTASK = {
-- @tparam table{string,...}|string LandingZones Table of Zone names where Cargo is to be loaded. -- @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 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. -- @tparam number OnBoardSide Reflects from which side the cargo Group will be on-boarded on the Carrier.
function PICKUPTASK:New( LandingZones, CargoType, OnBoardSide ) function PICKUPTASK:New( CargoType, OnBoardSide )
trace.f(self.ClassName) local self = BASE:Inherit( self, TASK:New() )
self:T()
-- Child holds the inherited instance of the PICKUPTASK Class to the BASE class. -- self holds the inherited instance of the PICKUPTASK Class to the BASE class.
local Child = BASE:Inherit( self, TASK:New() )
local Valid = true 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 if Valid then
Child.Name = 'Pickup Cargo' self.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." 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."
if type( LandingZones ) == "table" then self.CargoType = CargoType
Child.LandingZones = LandingZones self.GoalVerb = CargoType .. " " .. self.GoalVerb
else self.OnBoardSide = OnBoardSide
Child.LandingZones = { LandingZones } self.IsLandingRequired = false -- required to decide whether the client needs to land or not
end self.IsSlingLoad = false -- Indicates whether the cargo is a sling load cargo
Child.CargoType = CargoType self.Stages = { STAGE_CARGO_INIT:New(), STAGE_CARGO_LOAD:New(), STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGELOAD:New(), STAGEDONE:New() }
Child.GoalVerb = CargoType.TEXT .. " " .. Child.GoalVerb self.SetStage( self, 1 )
Child.OnBoardSide = OnBoardSide
Child.Stages = { STAGEBRIEF:New(), STAGESTART:New(), STAGEROUTE:New(), STAGELANDING:New(), STAGELANDED:New(), STAGELOAD:New(), STAGEDONE:New() }
Child.SetStage( Child, 1 )
end 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 end
function PICKUPTASK:AddCargoMenus( Client, Cargos, TransportRadius ) 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 MenuAdd then
if Client._Menus[Cargo.CargoType] == nil then
if Client._Menus[CargoData.CargoType] == nil then Client._Menus[Cargo.CargoType] = {}
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
end 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 end
end end
@ -102,103 +119,36 @@ trace.f(self.ClassName, { Client, Cargos, TransportRadius } )
end end
function PICKUPTASK:RemoveCargoMenus( Client ) function PICKUPTASK:RemoveCargoMenus( Client )
trace.f(self.ClassName, { Client } ) self:T()
for MenuID, MenuData in pairs( Client._Menus ) do for MenuID, MenuData in pairs( Client._Menus ) do
for SubMenuID, SubMenuData in pairs( MenuData.PickupSubMenus ) do for SubMenuID, SubMenuData in pairs( MenuData.PickupSubMenus ) do
missionCommands.removeItemForGroup( Client:ClientGroup():getID(), SubMenuData ) missionCommands.removeItemForGroup( Client:GetClientGroupID(), SubMenuData )
trace.i( self.ClassName, "Removed PickupSubMenu " ) self:T( "Removed PickupSubMenu " )
SubMenuData = nil SubMenuData = nil
end end
if MenuData.PickupMenu then if MenuData.PickupMenu then
missionCommands.removeItemForGroup( Client:ClientGroup():getID(), MenuData.PickupMenu ) missionCommands.removeItemForGroup( Client:GetClientGroupID(), MenuData.PickupMenu )
trace.i( self.ClassName, "Removed PickupMenu " ) self:T( "Removed PickupMenu " )
MenuData.PickupMenu = nil MenuData.PickupMenu = nil
end end
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 end
function PICKUPTASK:HasFailed( ClientDead ) function PICKUPTASK:HasFailed( ClientDead )
trace.f(self.ClassName) self:T()
local TaskHasFailed = self.TaskFailed local TaskHasFailed = self.TaskFailed
return TaskHasFailed return TaskHasFailed
end 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. -- Utils- conversion, Lua utils, etc.
routines.utils = {} 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) routines.utils.toDegree = function(angle)
@ -137,91 +238,6 @@ function routines.utils.get3DDist(point1, point2)
end 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 -- From http://lua-users.org/wiki/SimpleRound
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place -- 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 end
--------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------
-- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5. -- acc- the accuracy of each easting/northing. 0, 1, 2, 3, 4, or 5.
routines.tostringMGRS = function(MGRS, acc) routines.tostringMGRS = function(MGRS, acc)
if acc == 0 then if acc == 0 then
@ -1521,85 +1540,48 @@ trace.r( "", "", { TransportZoneResult } )
end end
function routines.IsUnitInRadius( CargoUnit, ReferenceGroup, Radius ) function routines.IsUnitInRadius( CargoUnit, ReferencePosition, Radius )
trace.f() trace.f()
local Valid = true local Valid = true
-- fill-up some local variables to support further calculations to determine location of units within the zone. -- fill-up some local variables to support further calculations to determine location of units within the zone.
local CargoPos = CargoUnit:getPosition().p 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 else
Valid = false Valid = false
end end
trace.r( "", "", { Valid } )
return Valid return Valid
end end
function routines.IsPartOfGroupInRadius( CargoGroup, ReferenceGroup, Radius ) function routines.IsPartOfGroupInRadius( CargoGroup, ReferencePosition, Radius )
trace.f() trace.f()
local Valid = true local Valid = true
Valid = routines.ValidateGroup( CargoGroup, "CargoGroup", Valid ) 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 -- fill-up some local variables to support further calculations to determine location of units within the zone
local CargoUnits = CargoGroup:getUnits() local CargoUnits = CargoGroup:getUnits()
for CargoUnitId, CargoUnit in pairs( CargoUnits ) do for CargoUnitId, CargoUnit in pairs( CargoUnits ) do
local CargoUnitPos = CargoUnit:getPosition().p local CargoUnitPos = CargoUnit:getPosition().p
-- env.info( 'routines.IsPartOfGroupInRadius: CargoUnitPos.x = ' .. CargoUnitPos.x .. ' CargoUnitPos.z = ' .. CargoUnitPos.z ) -- 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 ) -- 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 else
Valid = false Valid = false
break break
end end
end end
trace.r( "", "", { Valid } )
return Valid return Valid
end 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 ) function routines.ValidateString( Variable, VariableName, Valid )
trace.f() trace.f()
@ -1866,6 +1848,23 @@ routines.ground.patrol = function(gpData, pType, form, speed)
return return
end 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 = {} } Su34Status = { status = {} }
@ -2399,7 +2398,7 @@ trace.f()
--env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight )) --env.info(( 'CarrierHeight: LandHeight = ' .. LandHeight .. ' CarrierHeight = ' .. CarrierHeight ))
return CarrierHeight - LandHeight return UnitHeight - LandHeight
end end

View File

@ -30,51 +30,48 @@ SEAD = {
-- -- Defends the Russian SA installations from SEAD attacks. -- -- 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' } ) -- 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 ) function SEAD:New( SEADGroupPrefixes )
trace.f(self.ClassName, SEADGroupPrefixes ) local self = BASE:Inherit( self, BASE:New() )
self:T( SEADGroupPrefixes )
-- Arrange meta tables
local Child = BASE:Inherit( self, BASE:New() )
if type( SEADGroupPrefixes ) == 'table' then if type( SEADGroupPrefixes ) == 'table' then
for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do for SEADGroupPrefixID, SEADGroupPrefix in pairs( SEADGroupPrefixes ) do
Child.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix self.SEADGroupPrefixes[SEADGroupPrefix] = SEADGroupPrefix
end end
else else
Child.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes self.SEADGroupNames[SEADGroupPrefixes] = SEADGroupPrefixes
end end
Child.AddEvent( Child, world.event.S_EVENT_SHOT, Child.EventShot ) self.AddEvent( self, world.event.S_EVENT_SHOT, self.EventShot )
Child.EnableEvents( Child ) self.EnableEvents( self )
return Child return self
end 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. --- 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 -- @see SEAD
function SEAD:EventShot( event ) function SEAD:EventShot( event )
trace.f( self.ClassName, { event } ) self:T( { event } )
local _grp = Unit.getGroup(event.initiator)-- Identify the group that fired local SEADUnit = event.initiator
local _groupname = _grp:getName() -- return the name of the group local SEADUnitName = SEADUnit:getName()
local _unittable = {event.initiator:getName()} -- return the name of the units in the group local SEADWeapon = event.weapon -- Identify the weapon fired
local _SEADmissile = event.weapon -- Identify the weapon fired local SEADWeaponName = SEADWeapon:getTypeName() -- return weapon type
local _SEADmissileName = _SEADmissile:getTypeName() -- return weapon type --trigger.action.outText( string.format("Alerte, depart missile " ..string.format(SEADWeaponName)), 20) --debug message
--trigger.action.outText( string.format("Alerte, depart missile " ..string.format(_SEADmissileName)), 20) --debug message
-- Start of the 2nd loop -- Start of the 2nd loop
trace.i( self.ClassName, "Missile Launched = " .. _SEADmissileName ) self:T( "Missile Launched = " .. SEADWeaponName )
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 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 _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 _targetMimname = Unit.getName(_targetMim)
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(_SEADmissile)) local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon))
local _targetMimgroupName = _targetMimgroup:getName() local _targetMimgroupName = _targetMimgroup:getName()
local _targetMimcont= _targetMimgroup:getController() local _targetMimcont= _targetMimgroup:getController()
local _targetskill = _Database.Units[_targetMimname].Template.skill local _targetskill = _Database.Units[_targetMimname].Template.skill
trace.i( self.ClassName, self.SEADGroupPrefixes ) self:T( self.SEADGroupPrefixes )
trace.i( self.ClassName, _targetMimgroupName ) self:T( _targetMimgroupName )
local SEADGroupFound = false local SEADGroupFound = false
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then if string.find( _targetMimgroupName, SEADGroupPrefix, 1, true ) then
SEADGroupFound = true SEADGroupFound = true
trace.i( self.ClassName, 'Group Found' ) self:T( 'Group Found' )
break break
end end
end end
@ -83,15 +80,15 @@ trace.f( self.ClassName, { event } )
local Skills = { "Average", "Good", "High", "Excellent" } local Skills = { "Average", "Good", "High", "Excellent" }
_targetskill = Skills[ math.random(1,4) ] _targetskill = Skills[ math.random(1,4) ]
end 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 self.TargetSkill[_targetskill] then
if (_evade > self.TargetSkill[_targetskill].Evade) then if (_evade > self.TargetSkill[_targetskill].Evade) then
trace.i( self.ClassName, string.format("Evading, target skill " ..string.format(_targetskill)) ) --debug message self:T( string.format("Evading, target skill " ..string.format(_targetskill)) ) --debug message
local _targetMim = Weapon.getTarget(_SEADmissile) local _targetMim = Weapon.getTarget(SEADWeapon)
local _targetMimname = Unit.getName(_targetMim) local _targetMimname = Unit.getName(_targetMim)
local _targetMimgroup = Unit.getGroup(Weapon.getTarget(_SEADmissile)) local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon))
local _targetMimcont= _targetMimgroup:getController() 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 SuppressedGroups1 = {} -- unit suppressed radar off for a random time
local function SuppressionEnd1(id) local function SuppressionEnd1(id)
id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) 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 -- @classmod SPAWN
-- @author Flightcontrol -- @author Flightcontrol
MOOSE_Version = "0.1.1.1"
Include.File( "Routines" ) Include.File( "Routines" )
Include.File( "Base" ) Include.File( "Base" )
Include.File( "Database" ) Include.File( "Database" )
Include.File( "Group" )
SPAWN = { SPAWN = {
ClassName = "SPAWN", ClassName = "SPAWN",
@ -23,10 +27,8 @@ SPAWN = {
-- -- NATO helicopters engaging in the battle field. -- -- NATO helicopters engaging in the battle field.
-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ) -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' )
function SPAWN:New( SpawnPrefix ) function SPAWN:New( SpawnPrefix )
trace.f(self.ClassName, SpawnPrefix)
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
self:T( SpawnPrefix)
local TemplateGroup = Group.getByName( SpawnPrefix ) local TemplateGroup = Group.getByName( SpawnPrefix )
if TemplateGroup then 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.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.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.SpawnMaxGroups = 0 -- The maximum amount of groups that can be spawned.
self.SpawnRandomize = false
else else
error( "SPAWN:New: There is no group declared in the mission editor with SpawnPrefix = '" .. SpawnPrefix .. "'" ) error( "SPAWN:New: There is no group declared in the mission editor with SpawnPrefix = '" .. SpawnPrefix .. "'" )
end end
@ -65,11 +68,12 @@ end
-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):RandomizeRoute( 2, 2, 2000 ) -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):RandomizeRoute( 2, 2, 2000 )
function SPAWN:RandomizeRoute( SpawnStartPoint, SpawnEndPoint, SpawnRadius ) 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.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.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.SpawnRadius = SpawnRadius -- The Radius of randomization of the route points from SpawnStartPoint till SpawnEndPoint.
self.SpawnRandomize = true
return self return self
end end
@ -89,7 +93,7 @@ end
-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 ) -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Schedule( 600, 0.5 )
function SPAWN:Schedule( SpawnTime, SpawnTimeVariation ) 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.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. 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() self:ScheduleStart()
end end
trace.i( self.ClassName, { self.SpawnLowTimer, self.SpawnHighTimer } ) self:T( { self.SpawnLowTimer, self.SpawnHighTimer } )
return self return self
end end
@ -111,7 +115,7 @@ end
--- Will start the SPAWNing timers. --- Will start the SPAWNing timers.
-- This function is called automatically when @{Schedule} is called. -- This function is called automatically when @{Schedule} is called.
function SPAWN:ScheduleStart() function SPAWN:ScheduleStart()
trace.f( self.ClassName ) self:T()
--local ClientUnit = #AlivePlayerUnits() --local ClientUnit = #AlivePlayerUnits()
@ -128,7 +132,7 @@ end
--- Will stop the scheduled SPAWNing activity. --- Will stop the scheduled SPAWNing activity.
function SPAWN:ScheduleStop() function SPAWN:ScheduleStop()
trace.f( self.ClassName ) self:T()
self.SpawnScheduled = false self.SpawnScheduled = false
end end
@ -146,7 +150,7 @@ end
-- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Limit( 2, 24 ) -- Spawn_BE_KA50 = SPAWN:New( 'BE KA-50@RAMP-Ground Defense' ):Limit( 2, 24 )
function SPAWN:Limit( SpawnMaxGroupsAlive, SpawnMaxGroups ) 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.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. 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 ) -- 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 ) function SPAWN:RandomizeTemplate( SpawnPrefixTable )
trace.f( self.ClassName, { SpawnPrefix, SpawnPrefixTable } ) self:T( { SpawnPrefix, SpawnPrefixTable } )
self.SpawnPrefixTable = 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() -- 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() function SPAWN:Repeat()
trace.f( self.ClassName ) self:T()
self.SpawnRepeat = true self.SpawnRepeat = true
self.RepeatOnEngineShutDown = false self.RepeatOnEngineShutDown = false
@ -209,7 +213,7 @@ end
-- @see Repeat -- @see Repeat
function SPAWN:RepeatOnLanding() function SPAWN:RepeatOnLanding()
trace.f( self.ClassName ) self:T()
self:Repeat() self:Repeat()
self.RepeatOnEngineShutDown = false self.RepeatOnEngineShutDown = false
@ -223,7 +227,7 @@ end
-- @see Repeat -- @see Repeat
function SPAWN:RepeatOnEngineShutDown() function SPAWN:RepeatOnEngineShutDown()
trace.f( self.ClassName ) self:T()
self:Repeat() self:Repeat()
self.RepeatOnEngineShutDown = true self.RepeatOnEngineShutDown = true
@ -232,15 +236,64 @@ trace.f( self.ClassName )
return self return self
end 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. --- 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, ... -- 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. -- Uses @{DATABASE} global object defined in MOOSE.
-- @treturn SPAWN -- @treturn SPAWN
function SPAWN:Spawn() function SPAWN:Spawn( SpawnGroupName )
trace.f( self.ClassName ) self:T( { self.SpawnPrefix, SpawnGroupName } )
local SpawnTemplate = self:_Prepare( true ) local SpawnTemplate = self:_Prepare( SpawnGroupName )
if self.SpawnStartPoint ~= 0 or self.SpawnEndPoint ~= 0 then 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 ) SpawnTemplate = self:_RandomizeRoute( SpawnTemplate )
end end
_Database:Spawn( SpawnTemplate ) _Database:Spawn( SpawnTemplate )
@ -257,12 +310,15 @@ end
-- @treturn SPAWN -- @treturn SPAWN
-- Uses _Database global object defined in MOOSE. -- Uses _Database global object defined in MOOSE.
function SPAWN:ReSpawn( SpawnGroupName ) function SPAWN:ReSpawn( SpawnGroupName )
trace.f( self.ClassName, { SpawnGroupName } ) self:T( { SpawnGroupName } )
local SpawnGroup = Group.getByName( SpawnGroupName ) local SpawnGroup = Group.getByName( SpawnGroupName )
SpawnGroup:destroy() if SpawnGroup then
local SpawnTemplate = self:_Prepare( false ) SpawnGroup:destroy()
-- Give the Group the original name of the Group. end
SpawnTemplate.name = SpawnGroupName
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. -- 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 ) local SpawnUnits = table.getn( SpawnTemplate.units )
for u = 1, SpawnUnits do 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. --- 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 -- @treturn SPAWN
function SPAWN:SpawnUncontrolled() function SPAWN:SpawnUncontrolled()
trace.f( self.ClassName ) self:T()
self.UnControlled = true self.UnControlled = true
local SpawnCountStart = self.SpawnCount + 1 local SpawnCountStart = self.SpawnCount + 1
for SpawnCount = SpawnCountStart, self.SpawnMaxGroups do for SpawnCount = SpawnCountStart, self.SpawnMaxGroups do
local SpawnTemplate = self:_Prepare( true ) local SpawnTemplate = self:_Prepare( )
SpawnTemplate.uncontrolled = true SpawnTemplate.uncontrolled = true
_Database:Spawn( SpawnTemplate ) _Database:Spawn( SpawnTemplate )
end 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. --- 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 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 string NewGroupName (forgot this).
-- @tparam bool LateActivate (optional) does the SPAWNing with Lateactivation on. -- @tparam bool LateActivate (optional) does the SPAWNing with Lateactivation on.
function SPAWN:FromCarrier( CarrierGroup, TargetZonePrefix, NewGroupName, LateActivate ) function SPAWN:FromHost( HostUnit, OuterRadius, InnerRadius, NewGroupName, LateActivate )
trace.f( self.ClassName, { CarrierGroup, TargetZonePrefix, NewGroupName, LateActivate } ) self:T( { HostUnit, OuterRadius, InnerRadius, NewGroupName, LateActivate } )
local SpawnTemplate 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() SpawnTemplate = self:_Prepare( NewGroupName )
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
UnitDeploy = UnitData 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
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 NewGroupName ~= nil then if LateActivate ~= nil then
SpawnTemplate.name = NewGroupName if LateActivate == true then
SpawnTemplate.lateActivation = true
SpawnTemplate.visible = true
end 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 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 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 return SpawnTemplate
end 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. --- Will SPAWN a Group within a given ZoneName.
-- @tparam string ZonePrefix is the name of the zone where the Group is to be SPAWNed. -- @tparam string ZonePrefix is the name of the zone where the Group is to be SPAWNed.
-- @treturn SpawnTemplate -- @treturn SpawnTemplate
function SPAWN:InZone( ZonePrefix ) function SPAWN:InZone( ZonePrefix, SpawnGroupName )
trace.f("Spawn", ZonePrefix ) 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 Zone = trigger.misc.getZone( ZonePrefix )
local ZonePos = {} local ZonePos = {}
@ -443,7 +617,7 @@ end
--- Gets the Group Template from the ME environment definition. --- 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. -- This method used the @{DATABASE} object, which contains ALL initial and new SPAWNed object in MOOSE.
function SPAWN:_GetTemplate( SpawnPrefix ) function SPAWN:_GetTemplate( SpawnPrefix )
trace.f( self.ClassName, SpawnPrefix ) self:T( SpawnPrefix )
local SpawnTemplate = nil local SpawnTemplate = nil
@ -457,13 +631,13 @@ trace.f( self.ClassName, SpawnPrefix )
SpawnTemplate.SpawnCategoryID = self:_GetGroupCategoryID( SpawnPrefix ) SpawnTemplate.SpawnCategoryID = self:_GetGroupCategoryID( SpawnPrefix )
SpawnTemplate.SpawnCountryID = self:_GetGroupCountryID( SpawnPrefix ) SpawnTemplate.SpawnCountryID = self:_GetGroupCountryID( SpawnPrefix )
trace.r( self.ClassName, "", { SpawnTemplate } ) self:T( { SpawnTemplate } )
return SpawnTemplate return SpawnTemplate
end end
--- Prepares the new Group Template before Spawning. --- Prepares the new Group Template before Spawning.
function SPAWN:_Prepare( SpawnIncrement ) function SPAWN:_Prepare( SpawnGroupName )
trace.f( self.ClassName ) self:T()
local SpawnCount local SpawnCount
local SpawnUnits local SpawnUnits
@ -476,11 +650,14 @@ trace.f( self.ClassName )
end end
-- Increase the spawn counter for the group -- Increase the spawn counter for the group
if SpawnIncrement == true then if SpawnGroupName then
SpawnTemplate.name = SpawnGroupName
else
self.SpawnCount = self.SpawnCount + 1 self.SpawnCount = self.SpawnCount + 1
SpawnTemplate.name = self:SpawnGroupName( self.SpawnCount )
end end
SpawnTemplate.name = string.format( self.SpawnPrefix .. '#%03d', self.SpawnCount )
SpawnTemplate.groupId = nil SpawnTemplate.groupId = nil
SpawnTemplate.lateActivation = false SpawnTemplate.lateActivation = false
if SpawnTemplate.SpawnCategoryID == Group.Category.GROUND then if SpawnTemplate.SpawnCategoryID == Group.Category.GROUND then
@ -501,32 +678,32 @@ trace.f( self.ClassName )
SpawnUnits = table.getn( SpawnTemplate.units ) SpawnUnits = table.getn( SpawnTemplate.units )
for u = 1, SpawnUnits do 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].unitId = nil
SpawnTemplate.units[u].x = SpawnTemplate.route.points[1].x SpawnTemplate.units[u].x = SpawnTemplate.route.points[1].x + math.random( -50, 50 )
SpawnTemplate.units[u].y = SpawnTemplate.route.points[1].y SpawnTemplate.units[u].y = SpawnTemplate.route.points[1].y + math.random( -50, 50 )
end end
trace.r( self.ClassName, "", SpawnTemplate.name ) self:T( SpawnTemplate.name )
return SpawnTemplate return SpawnTemplate
end end
--- Will randomize the route of the Group Template. --- Will randomize the route of the Group Template.
function SPAWN:_RandomizeRoute( SpawnTemplate ) 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 ) 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].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].y = SpawnTemplate.route.points[t].y + math.random( self.SpawnRadius * -1, self.SpawnRadius )
SpawnTemplate.route.points[t].alt = nil SpawnTemplate.route.points[t].alt = nil
--SpawnGroup.route.points[t].alt_type = 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
end end
trace.r( self.ClassName, "", SpawnTemplate.name ) self:T( SpawnTemplate.name )
return SpawnTemplate return SpawnTemplate
end end
@ -536,16 +713,16 @@ end
--- Obscolete --- Obscolete
-- @todo Need to delete this... _Database does this now ... -- @todo Need to delete this... _Database does this now ...
function SPAWN:OnBirth( event ) 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 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 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(), ".*#" ) local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then if EventPrefix == self.SpawnPrefix .. '#' then
--MessageToAll( "Mission command: unit " .. SpawnPrefix .. " spawned." , 5, EventPrefix .. '/Event') --MessageToAll( "Mission command: unit " .. SpawnPrefix .. " spawned." , 5, EventPrefix .. '/Event')
self.AliveUnits = self.AliveUnits + 1 self.AliveUnits = self.AliveUnits + 1
trace.l(self.ClassName, "OnBirth", self.AliveUnits ) self:T( self.AliveUnits )
end end
end end
end end
@ -555,17 +732,17 @@ end
--- Obscolete --- Obscolete
-- @todo Need to delete this... _Database does this now ... -- @todo Need to delete this... _Database does this now ...
function SPAWN:OnDeadOrCrash( event ) function SPAWN:OnDeadOrCrash( event )
trace.f( self.ClassName, { event } ) self:T( { event } )
if event.initiator and event.initiator:getName() then 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(), ".*#" ) local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then if EventPrefix == self.SpawnPrefix .. '#' then
-- local DestroyedUnit = Unit.getByName( EventPrefix ) -- local DestroyedUnit = Unit.getByName( EventPrefix )
-- if DestroyedUnit and DestroyedUnit.getLife() <= 1.0 then -- if DestroyedUnit and DestroyedUnit.getLife() <= 1.0 then
--MessageToAll( "Mission command: unit " .. SpawnPrefix .. " crashed." , 5, EventPrefix .. '/Event') --MessageToAll( "Mission command: unit " .. SpawnPrefix .. " crashed." , 5, EventPrefix .. '/Event')
self.AliveUnits = self.AliveUnits - 1 self.AliveUnits = self.AliveUnits - 1
trace.l( self.ClassName, "OnDeadOrCrash", self.AliveUnits ) self:T( self.AliveUnits )
-- end -- end
end end
end end
@ -575,17 +752,17 @@ end
-- This is needed to ensure that Re-SPAWNing is only done for landed AIR Groups. -- This is needed to ensure that Re-SPAWNing is only done for landed AIR Groups.
-- @todo Need to test for AIR Groups only... -- @todo Need to test for AIR Groups only...
function SPAWN:OnLand( event ) function SPAWN:OnLand( event )
trace.f( self.ClassName, { event } ) self:T( { event } )
if event.initiator and event.initiator:getName() then 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(), ".*#" ) local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then if EventPrefix == self.SpawnPrefix .. '#' then
self.Landed = true self.Landed = true
trace.l( self.ClassName, "OnLand", "self.Landed = true" ) self:T( "self.Landed = true" )
if self.Landed and self.RepeatOnLanding then if self.Landed and self.RepeatOnLanding then
local SpawnGroupName = Unit.getGroup(event.initiator):getName() local SpawnGroupName = Unit.getGroup(event.initiator):getName()
trace.l( self.ClassName, "OnLand", "ReSpawn " .. SpawnGroupName ) self:T( "ReSpawn " .. SpawnGroupName )
self:ReSpawn( SpawnGroupName ) self:ReSpawn( SpawnGroupName )
end end
end end
@ -596,13 +773,13 @@ end
-- This is needed to ensure that Re-SPAWNing only is done for landed AIR Groups. -- This is needed to ensure that Re-SPAWNing only is done for landed AIR Groups.
-- @todo Need to test for AIR Groups only... -- @todo Need to test for AIR Groups only...
function SPAWN:OnTakeOff( event ) function SPAWN:OnTakeOff( event )
trace.f( self.ClassName, { event } ) self:T( { event } )
if event.initiator and event.initiator:getName() then 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(), ".*#" ) local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then if EventPrefix == self.SpawnPrefix .. '#' then
trace.l( self.ClassName, "OnTakeOff", "self.Landed = false" ) self:T( "self.Landed = false" )
self.Landed = false self.Landed = false
end end
end end
@ -615,15 +792,15 @@ end
-- @see OnLand -- @see OnLand
-- @todo Need to test for AIR Groups only... -- @todo Need to test for AIR Groups only...
function SPAWN:OnEngineShutDown( event ) function SPAWN:OnEngineShutDown( event )
trace.f( self.ClassName, { event } ) self:T( { event } )
if event.initiator and event.initiator:getName() then 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(), ".*#" ) local EventPrefix = string.match( event.initiator:getName(), ".*#" )
if EventPrefix == self.SpawnPrefix .. '#' then if EventPrefix == self.SpawnPrefix .. '#' then
if self.Landed and self.RepeatOnEngineShutDown then if self.Landed and self.RepeatOnEngineShutDown then
local SpawnGroupName = Unit.getGroup(event.initiator):getName() local SpawnGroupName = Unit.getGroup(event.initiator):getName()
trace.l( self.ClassName, "OnEngineShutDown", "ReSpawn " .. SpawnGroupName ) self:T( "ReSpawn " .. SpawnGroupName )
self:ReSpawn( SpawnGroupName ) self:ReSpawn( SpawnGroupName )
end end
end end
@ -636,7 +813,7 @@ end
--- This function is called automatically by the Spawning scheduler. --- This function is called automatically by the Spawning scheduler.
-- It is the internal worker method SPAWNing new Groups on the defined time intervals. -- It is the internal worker method SPAWNing new Groups on the defined time intervals.
function SPAWN:_Scheduler() function SPAWN:_Scheduler()
trace.l( self.ClassName, '_Scheduler', self.SpawnPrefix ) self:T( self.SpawnPrefix )
if self.SpawnInit or self.SpawnCurrentTimer == self.SpawnSetTimer then if self.SpawnInit or self.SpawnCurrentTimer == self.SpawnSetTimer then
-- Validate if there are still groups left in the batch... -- Validate if there are still groups left in the batch...

View File

@ -27,13 +27,12 @@ STAGE = {
function STAGE:New() function STAGE:New()
trace.f(self.ClassName)
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
self:T()
return self return self
end end
function STAGE:Execute( Mission, Client, Task ) function STAGE:Execute( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = true local Valid = true
@ -41,13 +40,10 @@ trace.f(self.ClassName)
end end
function STAGE:Executing( Mission, Client, Task ) function STAGE:Executing( Mission, Client, Task )
trace.f(self.ClassName)
end end
function STAGE:Validate( Mission, Client, Task ) function STAGE:Validate( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = true local Valid = true
return Valid return Valid
@ -56,31 +52,30 @@ end
STAGEBRIEF = { STAGEBRIEF = {
ClassName = "BRIEF", ClassName = "BRIEF",
MSG = { ID = "Brief", TIME = 30 }, MSG = { ID = "Brief", TIME = 1 },
Name = "Brief", Name = "Brief",
StageBriefingTime = 0, StageBriefingTime = 0,
StageBriefingDuration = 30 StageBriefingDuration = 1
} }
function STAGEBRIEF:New() function STAGEBRIEF:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'CLIENT'
Child.StageType = 'CLIENT' return self
return Child
end end
function STAGEBRIEF:Execute( Mission, Client, Task ) function STAGEBRIEF:Execute( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
self:T()
Mission:ShowBriefing( Client ) Mission:ShowBriefing( Client )
self.StageBriefingTime = timer.getTime() self.StageBriefingTime = timer.getTime()
return Valid return Valid
end end
function STAGEBRIEF:Validate( Mission, Client, Task ) function STAGEBRIEF:Validate( Mission, Client, Task )
trace.f(self.ClassName)
local Valid = STAGE:Validate( Mission, Client, Task ) local Valid = STAGE:Validate( Mission, Client, Task )
self:T()
if timer.getTime() - self.StageBriefingTime <= self.StageBriefingDuration then if timer.getTime() - self.StageBriefingTime <= self.StageBriefingDuration then
return 0 return 0
@ -94,34 +89,33 @@ end
STAGESTART = { STAGESTART = {
ClassName = "START", ClassName = "START",
MSG = { ID = "Start", TIME = 30 }, MSG = { ID = "Start", TIME = 1 },
Name = "Start", Name = "Start",
StageStartTime = 0, StageStartTime = 0,
StageStartDuration = 30 StageStartDuration = 1
} }
function STAGESTART:New() function STAGESTART:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'CLIENT'
Child.StageType = 'CLIENT' return self
return Child
end end
function STAGESTART:Execute( Mission, Client, Task ) function STAGESTART:Execute( Mission, Client, Task )
trace.f(self.ClassName) self:T()
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
if Task.TaskBriefing then 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 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 end
self.StageStartTime = timer.getTime() self.StageStartTime = timer.getTime()
return Valid return Valid
end end
function STAGESTART:Validate( Mission, Client, Task ) function STAGESTART:Validate( Mission, Client, Task )
trace.f(self.ClassName) self:T()
local Valid = STAGE:Validate( Mission, Client, Task ) local Valid = STAGE:Validate( Mission, Client, Task )
if timer.getTime() - self.StageStartTime <= self.StageStartDuration then if timer.getTime() - self.StageStartTime <= self.StageStartDuration then
@ -135,17 +129,90 @@ trace.f(self.ClassName)
end 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 = { STAGEROUTE = {
ClassName = "STAGEROUTE", ClassName = "STAGEROUTE",
MSG = { ID = "Route", TIME = 1 }, MSG = { ID = "Route", TIME = 5 },
Frequency = STAGE.FREQUENCY.REPEAT, Frequency = STAGE.FREQUENCY.REPEAT,
Name = "Route" Name = "Route"
} }
function STAGEROUTE:New() function STAGEROUTE:New()
trace.f(self.ClassName)
-- Arrange meta tables
local self = BASE:Inherit( self, STAGE:New() ) local self = BASE:Inherit( self, STAGE:New() )
self:T()
self.StageType = 'CLIENT' self.StageType = 'CLIENT'
self.MessageSwitch = true self.MessageSwitch = true
return self return self
@ -153,19 +220,17 @@ end
function STAGEROUTE:Execute( Mission, Client, Task ) function STAGEROUTE:Execute( Mission, Client, Task )
trace.f(self.ClassName) self:T()
local Valid = BASE:Inherited(self):Execute( Mission, Client, Task ) local Valid = BASE:Inherited(self):Execute( Mission, Client, Task )
if type( Task.LandingZones) == "table" then local RouteMessage = "Fly to "
local RouteMessage = "Fly to " self:T( Task.LandingZones )
for LandingZoneID, LandingZoneName in pairs( Task.LandingZones ) do for LandingZoneID, LandingZoneName in pairs( Task.LandingZones.LandingZoneNames ) do
RouteMessage = RouteMessage .. LandingZoneName .. ' at ' .. routines.getBRStringZone( { zone = LandingZoneName, ref = Client:ClientGroup():getUnit(1):getPoint(), true, true } ) .. ' km. ' RouteMessage = RouteMessage .. LandingZoneName .. ' at ' .. routines.getBRStringZone( { zone = LandingZoneName, ref = Client:GetClientGroupUnit():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 )
end 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() Client:ShowCargo()
end end
@ -173,59 +238,32 @@ trace.f(self.ClassName)
end end
function STAGEROUTE:Validate( Mission, Client, Task ) function STAGEROUTE:Validate( Mission, Client, Task )
trace.f(self.ClassName) self:T()
local Valid = STAGE:Validate( Mission, Client, Task ) 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.CurrentLandingZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName].CargoZone
Task.CurrentLandingZoneID = routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones ) Task.CurrentCargoZone = Task.LandingZones.LandingZones[Task.CurrentLandingZoneName]
if ( Task.CurrentLandingZoneID ) then
if not Task.Signalled then if Task.CurrentCargoZone then
if not Task.Signalled then
if Task.LandingZoneSignalType then Task.Signalled = Task.CurrentCargoZone:Signal()
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
end end
end end
self.Signalled = true
return 1
end end
return 1
end
return 0
return 0
end end
STAGELANDING = { STAGELANDING = {
ClassName = "STAGELANDING", ClassName = "STAGELANDING",
MSG = { ID = "Landing", TIME = 10 }, MSG = { ID = "Landing", TIME = 10 },
@ -234,37 +272,96 @@ STAGELANDING = {
} }
function STAGELANDING:New() function STAGELANDING:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'CLIENT'
Child.StageType = 'CLIENT' return self
return Child
end end
function STAGELANDING:Execute( Mission, Client, Task ) 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 .. '.', Client:Message( "We have arrived at the landing zone.", self.MSG.TIME, Mission.Name .. "/StageArrived", "Co-Pilot: Arrived", 10 )
self.MSG.TIME, Mission.Name .. "/Stage", "Co-Pilot: Landing" )
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 end
function STAGELANDING:Validate( Mission, Client, Task ) function STAGELANDING:Validate( Mission, Client, Task )
trace.f(self.ClassName) self:T()
if routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones[Task.CurrentLandingZoneID] ) then Task.CurrentLandingZoneName = routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.LandingZones.LandingZoneNames )
else if Task.CurrentLandingZoneName then
Task.Signalled = false
Task:RemoveCargoMenus( Client ) -- Client is in de landing zone.
return -1 self:T( Task.CurrentLandingZoneName )
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
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 if Task.IsLandingRequired and Client:GetClientGroupUnit():inAir() then
else return 0
return 0 end
end
return 1 return 1
end end
STAGELANDED = { STAGELANDED = {
@ -275,46 +372,52 @@ STAGELANDED = {
} }
function STAGELANDED:New() function STAGELANDED:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'CLIENT'
Child.StageType = 'CLIENT' return self
return Child
end end
function STAGELANDED:Execute( Mission, Client, Task ) function STAGELANDED:Execute( Mission, Client, Task )
trace.f(self.ClassName) self:T()
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 if Task.IsLandingRequired then
Task:RemoveCargoMenus( Client ) Client:Message( 'We have landed within the landing zone. Use the radio menu (F10) to ' .. Task.TEXT[1] .. ' the ' .. Task.CargoType .. '.',
Task:AddCargoMenus( Client, Mission._Cargos, 250 ) 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
end end
function STAGELANDED:Validate( Mission, Client, Task ) function STAGELANDED:Validate( Mission, Client, Task )
trace.f(self.ClassName) self:T()
if routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones[Task.CurrentLandingZoneID] ) then if not routines.IsUnitInZones( Client:GetClientGroupUnit(), Task.CurrentLandingZoneName ) then
else self:T( "Client is not anymore in the landing zone, go back to stage Route, and remove cargo menus." )
Task.Signalled = false Task.Signalled = false
Task:RemoveCargoMenus( Client ) Task:RemoveCargoMenus( Client )
return -2 return -2
end end
if not Client:ClientGroup():getUnits()[1]:inAir() then if Task.IsLandingRequired and Client:GetClientGroupUnit():inAir() then
else self:T( "Client went back in the air. Go back to stage Landing." )
Task.Signalled = false Task.Signalled = false
return -1 return -1
end end
if Task.ExecuteStage == _TransportExecuteStage.EXECUTING then -- Wait until cargo is selected from the menu.
else if Task.IsLandingRequired then
return 0 if not Task.Cargo then
end return 0
end
end
return 1 return 1
end end
STAGEUNLOAD = { STAGEUNLOAD = {
@ -324,72 +427,63 @@ STAGEUNLOAD = {
} }
function STAGEUNLOAD:New() function STAGEUNLOAD:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'CLIENT'
Child.StageType = 'CLIENT' return self
return Child
end end
function STAGEUNLOAD:Execute( Mission, Client, Task ) function STAGEUNLOAD:Execute( Mission, Client, Task )
trace.f(self.ClassName) self:T()
Client:Message( 'The ' .. Task.CargoType.TEXT .. ' are being ' .. Task.TEXT[2] .. ' within the landing zone. Wait until the helicopter is ' .. Task.TEXT[3] .. '.', 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 .. "/Stage", "Co-Pilot: Unload" ) self.MSG.TIME, Mission.Name .. "/StageUnLoad", "Co-Pilot: Unload" )
Task:RemoveCargoMenus( Client ) Task:RemoveCargoMenus( Client )
end end
function STAGEUNLOAD:Executing( Mission, Client, Task ) function STAGEUNLOAD:Executing( Mission, Client, Task )
trace.f(self.ClassName) self:T()
env.info( 'STAGEUNLOAD:Executing() Task.CargoName = ' .. Task.CargoName ) env.info( 'STAGEUNLOAD:Executing() Task.Cargo.CargoName = ' .. Task.Cargo.CargoName )
local Cargo = Client:RemoveCargo( Task.CargoName )
if Cargo then local TargetZoneName
env.info( 'STAGEUNLOAD:Executing() Cargo.CargoName = ' .. Cargo.CargoName )
env.info( 'STAGEUNLOAD:Executing() Cargo.CargoGroupName = ' .. Cargo.CargoGroupName ) if Task.TargetZoneName then
env.info( 'STAGEUNLOAD:Executing() Mission._Cargos[Cargo.CargoName].CargoGroupTemplate = ' .. Mission._Cargos[Cargo.CargoName].CargoGroupTemplate ) TargetZoneName = Task.TargetZoneName
else
if Cargo.CargoType.TRANSPORT == CARGO_TRANSPORT.UNIT then TargetZoneName = Task.CurrentLandingZoneName
if Cargo.CargoName then end
if Task.TargetZoneName then
SPAWN:New( Mission._Cargos[Cargo.CargoName].CargoGroupTemplate ):FromCarrier ( Client:ClientGroup(), if Task.Cargo:UnLoad( Client, TargetZoneName ) then
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
Task.ExecuteStage = _TransportExecuteStage.SUCCESS Task.ExecuteStage = _TransportExecuteStage.SUCCESS
Client:ShowCargo() if Mission.MissionReportFlash then
Client:ShowCargo()
end
end end
end end
function STAGEUNLOAD:Validate( Mission, Client, Task ) function STAGEUNLOAD:Validate( Mission, Client, Task )
trace.f(self.ClassName) self:T()
env.info( 'STAGEUNLOAD:Validate()' ) 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 else
Task.ExecuteStage = _TransportExecuteStage.FAILED Task.ExecuteStage = _TransportExecuteStage.FAILED
Task:RemoveCargoMenus( Client ) 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" ) _TransportStageMsgTime.DONE, Mission.Name .. "/StageFailure", "Co-Pilot: Unload" )
return 1 return 1
end end
if not Client:ClientGroup():getUnits()[1]:inAir() then if not Client:GetClientGroupUnit():inAir() then
else else
Task.ExecuteStage = _TransportExecuteStage.FAILED Task.ExecuteStage = _TransportExecuteStage.FAILED
Task:RemoveCargoMenus( Client ) 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" ) _TransportStageMsgTime.DONE, Mission.Name .. "/StageFailure", "Co-Pilot: Unload" )
return 1 return 1
end end
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then 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" ) Client:Message( 'The ' .. Task.CargoType .. ' 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
Task:RemoveCargoMenus( Client ) Task:RemoveCargoMenus( Client )
Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.CargoName, 1 ) -- We set the cargo as one more goal completed in the mission. Task.MissionTask:AddGoalCompletion( Task.MissionTask.GoalVerb, Task.CargoName, 1 ) -- We set the cargo as one more goal completed in the mission.
return 1 return 1
@ -405,173 +499,131 @@ STAGELOAD = {
} }
function STAGELOAD:New() function STAGELOAD:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'CLIENT'
Child.StageType = 'CLIENT' return self
return Child
end end
function STAGELOAD:Execute( Mission, Client, Task ) function STAGELOAD:Execute( Mission, Client, Task )
trace.f(self.ClassName) self:T()
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" ) 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 -- Route the cargo to the Carrier
if Mission._Cargos[Task.CargoName].CargoType.TRANSPORT == CARGO_TRANSPORT.UNIT then Task.Cargo:OnBoard( Client, Task.CurrentCargoZone, Task.OnBoardSide )
Task:OnBoardCargo( Client:ClientGroup(), Mission._Cargos )
Task.ExecuteStage = _TransportExecuteStage.EXECUTING Task.ExecuteStage = _TransportExecuteStage.EXECUTING
else else
-- Add the group to the internal cargo; Task.ExecuteStage = _TransportExecuteStage.EXECUTING
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
end end
end end
function STAGELOAD:Executing( Mission, Client, Task ) function STAGELOAD:Executing( Mission, Client, Task )
trace.f(self.ClassName) self:T()
-- Remove the loaded object from the battle zone. -- If the Cargo is ready to be loaded, load it into the Client.
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')
-- 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 ) if not Task.IsSlingLoad then
trace.i(self.ClassName, Task.Cargo.CargoName)
-- 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" ) if Task.Cargo:OnBoarded( Client, Task.CurrentCargoZone ) then
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
Client:ShowCargo()
end
end
function STAGELOAD:Validate( Mission, Client, Task ) -- Load the Cargo onto the Client
trace.f(self.ClassName) Task.Cargo:Load( Client )
if routines.IsUnitInZones( Client:ClientGroup():getUnits()[1], Task.LandingZones[Task.CurrentLandingZoneID] ) then
-- 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 else
Task:RemoveCargoMenus( Client ) Client:Message( "Hook the " .. Task.CargoNames .. " onto the helicopter " .. Task.TEXT[3] .. " within the landing zone.",
Task.ExecuteStage = _TransportExecuteStage.FAILED _TransportStageMsgTime.EXECUTING, Mission.Name .. "/STAGELOAD.LOADING.1." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":", 10 )
Task.CargoName = nil for CargoID, Cargo in pairs( CARGOS ) do
Client:Message( "The " .. Task.CargoType.TEXT .. " loading has been aborted. You flew outside the pick-up zone while loading. ", self:T( "Cargo.CargoName = " .. Cargo.CargoName )
_TransportStageMsgTime.DONE, Mission.Name .. "/StageSuccess", "Co-Pilot: Load" )
return 1 if Cargo:IsSlingLoad() then
end local CargoStatic = StaticObject.getByName( Cargo.CargoStaticName )
if CargoStatic then
if not Client:ClientGroup():getUnits()[1]:inAir() then trace.i(self.ClassName, "Cargo is found in the DCS simulator.")
else local CargoStaticPosition = CargoStatic:getPosition().p
-- The carrier is back in the air, undo the loading process. trace.i(self.ClassName, "Cargo Position x = " .. CargoStaticPosition.x .. ", y = " .. CargoStaticPosition.y .. ", z = " .. CargoStaticPosition.z )
Task:RemoveCargoMenus( Client ) local CargoStaticHeight = routines.GetUnitHeight( CargoStatic )
Task.ExecuteStage = _TransportExecuteStage.NONE if CargoStaticHeight > 5 then
Task.CargoName = nil trace.i(self.ClassName, "Cargo is airborne.")
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. ", Cargo:StatusLoaded()
_TransportStageMsgTime.DONE, Mission.Name .. "/StageSuccess", "Co-Pilot: Load" ) Task.Cargo = Cargo
return -1 Client:Message( 'The Cargo has been successfully hooked onto the helicopter and is now being sling loaded. Fly outside the landing zone.',
end self.MSG.TIME, Mission.Name .. "/STAGELANDING.LOADING.2." .. Task.HostUnitName, Task.HostUnitName .. " (" .. Task.HostUnitTypeName .. ")" .. ":" )
Task.ExecuteStage = _TransportExecuteStage.SUCCESS
if Task.ExecuteStage == _TransportExecuteStage.SUCCESS then break
Mission._Cargos[Task.CargoName].Status = CARGOSTATUS.LOADED end
Task:RemoveCargoMenus( Client ) else
Client:Message( 'Co-Pilot: The ' .. Task.CargoType.TEXT .. ' have been sucessfully ' .. Task.TEXT[3] .. ' within the landing zone.', self:T( "Cargo not found in the DCS simulator." )
_TransportStageMsgTime.DONE, Mission.Name .. "/Stage", "Co-Pilot: Load" ) end
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
end end
end end
end end
return 1
end 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 = { STAGEDONE = {
ClassName = "STAGEDONE", ClassName = "STAGEDONE",
MSG = { ID = "Done", TIME = 10 }, MSG = { ID = "Done", TIME = 10 },
@ -579,20 +631,19 @@ STAGEDONE = {
} }
function STAGEDONE:New() function STAGEDONE:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'AI'
Child.StageType = 'AI' return self
return Child
end end
function STAGEDONE:Execute( Mission, Client, Task ) function STAGEDONE:Execute( Mission, Client, Task )
trace.f(self.ClassName) self:T()
end end
function STAGEDONE:Validate( Mission, Client, Task ) function STAGEDONE:Validate( Mission, Client, Task )
trace.f(self.ClassName) self:T()
Task:Done() Task:Done()
@ -606,24 +657,23 @@ STAGEARRIVE = {
} }
function STAGEARRIVE:New() function STAGEARRIVE:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'CLIENT'
Child.StageType = 'CLIENT' return self
return Child
end end
function STAGEARRIVE:Execute( Mission, Client, Task ) 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 end
function STAGEARRIVE:Validate( Mission, Client, Task ) 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 if ( Task.CurrentLandingZoneID ) then
else else
return -1 return -1
@ -641,11 +691,10 @@ STAGEGROUPSDESTROYED = {
} }
function STAGEGROUPSDESTROYED:New() function STAGEGROUPSDESTROYED:New()
trace.f(self.ClassName) local self = BASE:Inherit( self, STAGE:New() )
-- Arrange meta tables self:T()
local Child = BASE:Inherit( self, STAGE:New() ) self.StageType = 'AI'
Child.StageType = 'AI' return self
return Child
end end
--function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task ) --function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task )
@ -655,7 +704,7 @@ end
--end --end
function STAGEGROUPSDESTROYED:Validate( Mission, Client, Task ) function STAGEGROUPSDESTROYED:Validate( Mission, Client, Task )
trace.f(self.ClassName) self:T()
if Task.MissionTask:IsGoalReached() then if Task.MissionTask:IsGoalReached() then
return 1 return 1
@ -665,8 +714,8 @@ trace.f(self.ClassName)
end end
function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task ) function STAGEGROUPSDESTROYED:Execute( Mission, Client, Task )
trace.f(self.ClassName) self:T()
trace.i( self.ClassName, { Task.ClassName, Task.Destroyed } ) self:T( { Task.ClassName, Task.Destroyed } )
--env.info( 'Event Table Task = ' .. tostring(Task) ) --env.info( 'Event Table Task = ' .. tostring(Task) )
end end

View File

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

View File

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