Progress, got now task acceptance working

This commit is contained in:
FlightControl 2016-07-07 13:11:31 +02:00
parent bba6aa8fb6
commit c5cc069e46
18 changed files with 833 additions and 253 deletions

View File

@ -115,7 +115,6 @@ function BASE:New()
self.__index = self self.__index = self
_ClassID = _ClassID + 1 _ClassID = _ClassID + 1
self.ClassID = _ClassID self.ClassID = _ClassID
self.ClassNameAndID = string.format( '%s#%09d', self.ClassName, self.ClassID )
return self return self
end end
@ -152,7 +151,7 @@ end
-- @param #BASE self -- @param #BASE self
-- @return #string The ClassName + ClassID of the class instance. -- @return #string The ClassName + ClassID of the class instance.
function BASE:GetClassNameAndID() function BASE:GetClassNameAndID()
return self.ClassNameAndID return string.format( '%s#%09d', self.ClassName, self.ClassID )
end end
--- Get the ClassName of the class instance. --- Get the ClassName of the class instance.

View File

@ -272,6 +272,19 @@ function EVENT:OnDeadForUnit( EventDCSUnitName, EventFunction, EventSelf )
return self return self
end end
--- Set a new listener for an S_EVENT_PILOT_DEAD event.
-- @param #EVENT self
-- @param #function EventFunction The function to be called when the event occurs for the unit.
-- @param Base#BASE EventSelf
-- @return #EVENT
function EVENT:OnPilotDead( EventFunction, EventSelf )
self:F2()
self:OnEventGeneric( EventFunction, EventSelf, world.event.S_EVENT_PILOT_DEAD )
return self
end
--- Set a new listener for an S_EVENT_PILOT_DEAD event. --- Set a new listener for an S_EVENT_PILOT_DEAD event.
-- @param #EVENT self -- @param #EVENT self
-- @param #string EventDCSUnitName -- @param #string EventDCSUnitName
@ -468,7 +481,6 @@ end
--- @param #EVENT self --- @param #EVENT self
-- @param #EVENTDATA Event -- @param #EVENTDATA Event
function EVENT:onEvent( Event ) function EVENT:onEvent( Event )
self:F2( { _EVENTCODES[Event.id], Event } )
if self and self.Events and self.Events[Event.id] then if self and self.Events and self.Events[Event.id] then
if Event.initiator and Event.initiator:getCategory() == Object.Category.UNIT then if Event.initiator and Event.initiator:getCategory() == Object.Category.UNIT then
@ -500,18 +512,23 @@ function EVENT:onEvent( Event )
Event.WeaponName = Event.Weapon:getTypeName() Event.WeaponName = Event.Weapon:getTypeName()
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
end end
self:E( { _EVENTCODES[Event.id], Event.IniUnitName, Event.TgtUnitName, Event.WeaponName } ) self:E( { _EVENTCODES[Event.id], Event } )
--self:E( { _EVENTCODES[Event.id], Event.IniUnitName, Event.TgtUnitName, Event.WeaponName } )
for ClassName, EventData in pairs( self.Events[Event.id] ) do for ClassName, EventData in pairs( self.Events[Event.id] ) do
if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then if Event.IniDCSUnitName and EventData.IniUnit and EventData.IniUnit[Event.IniDCSUnitName] then
self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } ) self:E( { "Calling event function for class ", ClassName, " unit ", Event.IniDCSUnitName } )
EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventSelf, Event ) EventData.IniUnit[Event.IniDCSUnitName].EventFunction( EventData.IniUnit[Event.IniDCSUnitName].EventSelf, Event )
else else
if Event.IniDCSUnit and not EventData.IniUnit then if Event.IniDCSUnit and not EventData.IniUnit then
self:E( { "Calling event function for class ", ClassName } ) if ClassName == EventData.EventSelf:GetClassNameAndID() then
EventData.EventFunction( EventData.EventSelf, Event ) self:E( { "Calling event function for class ", ClassName } )
EventData.EventFunction( EventData.EventSelf, Event )
end
end end
end end
end end
else
self:E( { _EVENTCODES[Event.id], Event } )
end end
end end

View File

@ -70,180 +70,362 @@ function SUBMENU:New( MenuText, ParentMenu )
return Child return Child
end end
-- This local variable is used to cache the menus registered under clients. do
-- Menus don't dissapear when clients are destroyed and restarted.
-- So every menu for a client created must be tracked so that program logic accidentally does not create
-- the same menus twice during initialization logic.
-- These menu classes are handling this logic with this variable.
local _MENUCLIENTS = {}
--- The MENU_CLIENT class -- This local variable is used to cache the menus registered under clients.
-- @type MENU_CLIENT -- Menus don't dissapear when clients are destroyed and restarted.
-- @extends Menu#MENU -- So every menu for a client created must be tracked so that program logic accidentally does not create
MENU_CLIENT = { -- the same menus twice during initialization logic.
ClassName = "MENU_CLIENT" -- These menu classes are handling this logic with this variable.
} local _MENUCLIENTS = {}
--- Creates a new menu item for a group
-- @param self
-- @param Client#CLIENT MenuClient The Client owning the menu.
-- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu.
-- @return #MENU_CLIENT self
function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self:F( { MenuClient, MenuText, ParentMenu } )
self.MenuClient = MenuClient
self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
self.Menus = {} --- The MENU_CLIENT class
-- @type MENU_CLIENT
if not _MENUCLIENTS[self.MenuClientGroupID] then -- @extends Menu#MENU
_MENUCLIENTS[self.MenuClientGroupID] = {} MENU_CLIENT = {
ClassName = "MENU_CLIENT"
}
--- Creates a new menu item for a group
-- @param self
-- @param Client#CLIENT MenuClient The Client owning the menu.
-- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu.
-- @return #MENU_CLIENT self
function MENU_CLIENT:New( MenuClient, MenuText, ParentMenu )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self:F( { MenuClient, MenuText, ParentMenu } )
self.MenuClient = MenuClient
self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
self.Menus = {}
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
end
self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath )
MenuPath[MenuPathID] = self.MenuPath
self:T( { MenuClient:GetClientGroupName(), self.MenuPath } )
if ParentMenu and ParentMenu.Menus then
ParentMenu.Menus[self.MenuPath] = self
end
return self
end end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID] --- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } ) -- @return #MENU_CLIENT self
function MENU_CLIENT:RemoveSubMenus()
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText self:F( self.MenuPath )
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] ) for MenuID, Menu in pairs( self.Menus ) do
Menu:Remove()
end
end end
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
-- @return #MENU_CLIENT self
function MENU_CLIENT:Remove()
self:F( self.MenuPath )
self:RemoveSubMenus()
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
--- The MENU_CLIENT_COMMAND class
-- @type MENU_CLIENT_COMMAND
-- @extends Menu#MENU
MENU_CLIENT_COMMAND = {
ClassName = "MENU_CLIENT_COMMAND"
}
--- Creates a new radio command item for a group
-- @param self
-- @param Client#CLIENT MenuClient The Client owning the menu.
-- @param MenuText The text for the menu.
-- @param ParentMenu The parent menu.
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
-- @param CommandMenuArgument An argument for the function.
-- @return Menu#MENU_CLIENT_COMMAND self
function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self.MenuClient = MenuClient
self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, CommandMenuArgument } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
end
self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument )
MenuPath[MenuPathID] = self.MenuPath
self.CommandMenuFunction = CommandMenuFunction
self.CommandMenuArgument = CommandMenuArgument
ParentMenu.Menus[self.MenuPath] = self
return self
end
function MENU_CLIENT_COMMAND:Remove()
self:F( self.MenuPath )
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
end
self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath ) --- MENU_GROUP
MenuPath[MenuPathID] = self.MenuPath
self:T( { MenuClient:GetClientGroupName(), self.MenuPath } ) do
-- This local variable is used to cache the menus registered under clients.
-- Menus don't dissapear when clients are destroyed and restarted.
-- So every menu for a client created must be tracked so that program logic accidentally does not create
-- the same menus twice during initialization logic.
-- These menu classes are handling this logic with this variable.
local _MENUGROUPS = {}
if ParentMenu and ParentMenu.Menus then --- The MENU_GROUP class
-- @type MENU_GROUP
-- @extends Menu#MENU
MENU_GROUP = {
ClassName = "MENU_GROUP"
}
--- Creates a new menu item for a group
-- @param self
-- @param Group#GROUP MenuGroup The Group owning the menu.
-- @param #string MenuText The text for the menu.
-- @param #table ParentMenu The parent menu.
-- @return #MENU_GROUP self
function MENU_GROUP:New( MenuGroup, MenuText, ParentMenu )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self:F( { MenuGroup, MenuText, ParentMenu } )
self.MenuGroup = MenuGroup
self.MenuGroupID = MenuGroup:GetID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
self.Menus = {}
if not _MENUGROUPS[self.MenuGroupID] then
_MENUGROUPS[self.MenuGroupID] = {}
end
local MenuPath = _MENUGROUPS[self.MenuGroupID]
self:T( { MenuGroup:GetName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuGroupID, MenuPath[MenuPathID] )
end
self.MenuPath = missionCommands.addSubMenuForGroup( self.MenuGroupID, MenuText, MenuParentPath )
MenuPath[MenuPathID] = self.MenuPath
self:T( { self.MenuGroupID, self.MenuPath } )
if ParentMenu and ParentMenu.Menus then
ParentMenu.Menus[self.MenuPath] = self
end
return self
end
--- Removes the sub menus recursively of this MENU_GROUP.
-- @param #MENU_GROUP self
-- @return #MENU_GROUP self
function MENU_GROUP:RemoveSubMenus()
self:F( self.MenuPath )
for MenuID, Menu in pairs( self.Menus ) do
Menu:Remove()
end
end
--- Removes the sub menus recursively of this MENU_GROUP.
-- @param #MENU_GROUP self
-- @return #MENU_GROUP self
function MENU_GROUP:Remove()
self:F( self.MenuPath )
self:RemoveSubMenus()
if not _MENUGROUPS[self.MenuGroupID] then
_MENUGROUPS[self.MenuGroupID] = {}
end
local MenuPath = _MENUGROUPS[self.MenuGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
if self.ParentMenu then
self.ParentMenu.Menus[self.MenuPath] = nil
end
return nil
end
--- The MENU_GROUP_COMMAND class
-- @type MENU_GROUP_COMMAND
-- @extends Menu#MENU
MENU_GROUP_COMMAND = {
ClassName = "MENU_GROUP_COMMAND"
}
--- Creates a new radio command item for a group
-- @param #MENU_GROUP_COMMAND self
-- @param Group#GROUP MenuGroup The Group owning the menu.
-- @param MenuText The text for the menu.
-- @param ParentMenu The parent menu.
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
-- @param CommandMenuArgument An argument for the function.
-- @return Menu#MENU_GROUP_COMMAND self
function MENU_GROUP_COMMAND:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self.MenuGroup = MenuGroup
self.MenuGroupID = MenuGroup:GetID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
if not _MENUGROUPS[self.MenuGroupID] then
_MENUGROUPS[self.MenuGroupID] = {}
end
local MenuPath = _MENUGROUPS[self.MenuGroupID]
self:T( { MenuGroup:GetName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, CommandMenuArgument } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuGroupID, MenuPath[MenuPathID] )
end
self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroupID, MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument )
MenuPath[MenuPathID] = self.MenuPath
self.CommandMenuFunction = CommandMenuFunction
self.CommandMenuArgument = CommandMenuArgument
ParentMenu.Menus[self.MenuPath] = self ParentMenu.Menus[self.MenuPath] = self
return self
end end
return self
end function MENU_GROUP_COMMAND:Remove()
self:F( self.MenuPath )
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self if not _MENUGROUPS[self.MenuGroupID] then
-- @return #MENU_CLIENT self _MENUGROUPS[self.MenuGroupID] = {}
function MENU_CLIENT:RemoveSubMenus() end
self:F( self.MenuPath )
local MenuPath = _MENUGROUPS[self.MenuGroupID]
for MenuID, Menu in pairs( self.Menus ) do
Menu:Remove() if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end end
end end
--- Removes the sub menus recursively of this MENU_CLIENT.
-- @param #MENU_CLIENT self
-- @return #MENU_CLIENT self
function MENU_CLIENT:Remove()
self:F( self.MenuPath )
self:RemoveSubMenus()
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
--- The MENU_CLIENT_COMMAND class
-- @type MENU_CLIENT_COMMAND
-- @extends Menu#MENU
MENU_CLIENT_COMMAND = {
ClassName = "MENU_CLIENT_COMMAND"
}
--- Creates a new radio command item for a group
-- @param self
-- @param Client#CLIENT MenuClient The Client owning the menu.
-- @param MenuText The text for the menu.
-- @param ParentMenu The parent menu.
-- @param CommandMenuFunction A function that is called when the menu key is pressed.
-- @param CommandMenuArgument An argument for the function.
-- @return Menu#MENU_CLIENT_COMMAND self
function MENU_CLIENT_COMMAND:New( MenuClient, MenuText, ParentMenu, CommandMenuFunction, CommandMenuArgument )
-- Arrange meta tables
local MenuParentPath = {}
if ParentMenu ~= nil then
MenuParentPath = ParentMenu.MenuPath
end
local self = BASE:Inherit( self, MENU:New( MenuText, MenuParentPath ) )
self.MenuClient = MenuClient
self.MenuClientGroupID = MenuClient:GetClientGroupID()
self.MenuParentPath = MenuParentPath
self.MenuText = MenuText
self.ParentMenu = ParentMenu
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
self:T( { MenuClient:GetClientGroupName(), MenuPath[table.concat(MenuParentPath)], MenuParentPath, MenuText, CommandMenuFunction, CommandMenuArgument } )
local MenuPathID = table.concat(MenuParentPath) .. "/" .. MenuText
if MenuPath[MenuPathID] then
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
end
self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, CommandMenuFunction, CommandMenuArgument )
MenuPath[MenuPathID] = self.MenuPath
self.CommandMenuFunction = CommandMenuFunction
self.CommandMenuArgument = CommandMenuArgument
ParentMenu.Menus[self.MenuPath] = self
return self
end
function MENU_CLIENT_COMMAND:Remove()
self:F( self.MenuPath )
if not _MENUCLIENTS[self.MenuClientGroupID] then
_MENUCLIENTS[self.MenuClientGroupID] = {}
end
local MenuPath = _MENUCLIENTS[self.MenuClientGroupID]
if MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] then
MenuPath[table.concat(self.MenuParentPath) .. "/" .. self.MenuText] = nil
end
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), self.MenuPath )
self.ParentMenu.Menus[self.MenuPath] = nil
return nil
end
--- The MENU_COALITION class --- The MENU_COALITION class
-- @type MENU_COALITION -- @type MENU_COALITION
-- @extends Menu#MENU -- @extends Menu#MENU

View File

@ -44,7 +44,7 @@ end
-- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players. -- @param #string MissionName is the name of the mission. This name will be used to reference the status of each mission by the players.
-- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field. -- @param #string MissionPriority is a string indicating the "priority" of the Mission. f.e. "Primary", "Secondary" or "First", "Second". It is free format and up to the Mission designer to choose. There are no rules behind this field.
-- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}. -- @param #string MissionBriefing is a string indicating the mission briefing to be shown when a player joins a @{CLIENT}.
-- @param #string MissionCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"... -- @param DCSCoalitionObject#coalition DCSCoalition is a string indicating the coalition or party to which this mission belongs to. It is free format and can be chosen freely by the mission designer. Note that this field is not to be confused with the coalition concept of the ME. Examples of a Mission Coalition could be "NATO", "CCCP", "Intruders", "Terrorists"...
-- @return #MISSION self -- @return #MISSION self
-- @usage -- @usage
-- -- Declare a few missions. -- -- Declare a few missions.
@ -56,15 +56,15 @@ end
-- local Mission = MISSIONSCHEDULER.AddMission( 'SA-6 SAMs', 'Primary', 'Our intelligence reports that 3 SA-6 SAM defense batteries are located near Didmukha, Khetagurov and Berula. Eliminate the Russian SAMs.', 'NATO' ) -- local Mission = MISSIONSCHEDULER.AddMission( 'SA-6 SAMs', 'Primary', 'Our intelligence reports that 3 SA-6 SAM defense batteries are located near Didmukha, Khetagurov and Berula. Eliminate the Russian SAMs.', '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( '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, DCSCoalition )
self = MISSION:Meta() self = MISSION:Meta()
self:T({ MissionName, MissionPriority, MissionBriefing, MissionCoalition }) self:T( { MissionName, MissionPriority, MissionBriefing, DCSCoalition } )
self.Name = MissionName self.Name = MissionName
self.MissionPriority = MissionPriority self.MissionPriority = MissionPriority
self.MissionBriefing = MissionBriefing self.MissionBriefing = MissionBriefing
self.MissionCoalition = MissionCoalition self.DCSCoalition = DCSCoalition
self:SetMissionMenu() self:SetMissionMenu()
@ -97,7 +97,7 @@ end
-- @param #MISSION self -- @param #MISSION self
-- @return #MISSION self -- @return #MISSION self
function MISSION:SetMissionMenu() function MISSION:SetMissionMenu()
self.MissionMenu = MENU_COALITION:New( self.MissionCoalition, self.Name ) self.MissionMenu = MENU_COALITION:New( self.DCSCoalition, self.Name )
end end
--- Gets the mission menu for the coalition. --- Gets the mission menu for the coalition.

View File

@ -48,15 +48,16 @@ Include.File( "Detection" )
Include.File( "FAC" ) Include.File( "FAC" )
Include.File( "StateMachine" ) Include.File( "StateMachine" )
Include.File( "Process" ) Include.File( "Process" )
Include.File( "Process_SEAD" ) Include.File( "Process_Assign" )
Include.File( "Process_Route" ) Include.File( "Process_Route" )
Include.File( "Process_SEAD" )
Include.File( "Task" ) Include.File( "Task" )
Include.File( "Task_SEAD" ) Include.File( "Task_SEAD" )
-- The order of the declarations is important here. Don't touch it. -- The order of the declarations is important here. Don't touch it.
--- Declare the event dispatcher based on the EVENT class --- Declare the event dispatcher based on the EVENT class
_EVENTDISPATCHER = EVENT:New() -- #EVENT _EVENTDISPATCHER = EVENT:New() -- Event#EVENT
--- Declare the main database object, which is used internally by the MOOSE classes. --- Declare the main database object, which is used internally by the MOOSE classes.
_DATABASE = DATABASE:New() -- Database#DATABASE _DATABASE = DATABASE:New() -- Database#DATABASE

View File

@ -4,7 +4,7 @@
-- @type PROCESS -- @type PROCESS
-- @field Scheduler#SCHEDULER ProcessScheduler -- @field Scheduler#SCHEDULER ProcessScheduler
-- @field Unit#UNIT ProcessUnit -- @field Unit#UNIT ProcessUnit
-- @field Task#MISSION Task -- @field Task#TASK Task
-- @field StateMachine#STATEMACHINE_TASK Fsm -- @field StateMachine#STATEMACHINE_TASK Fsm
-- @extends Base#BASE -- @extends Base#BASE
PROCESS = { PROCESS = {
@ -25,14 +25,28 @@ function PROCESS:New( Task, ProcessUnit )
self.ProcessUnit = ProcessUnit self.ProcessUnit = ProcessUnit
self.Task = Task self.Task = Task
self.AllowEvents = true
return self return self
end end
--- @param #PROCESS self --- @param #PROCESS self
function PROCESS:NextEvent( NextEvent, ... ) function PROCESS:NextEvent( NextEvent, ... )
self:E( NextEvent ) self:F2( arg )
if self.AllowEvents == true then
self.ProcessScheduler = SCHEDULER:New( self.Fsm, NextEvent, { self, self.ProcessUnit, unpack( arg ) }, 1 )
end
end
self.ProcessScheduler = SCHEDULER:New( self.Fsm, NextEvent, { self, self.ProcessUnit, unpack( arg ) }, 1 ) --- @param #PROCESS self
function PROCESS:StopEvents( )
self:F2()
if self.ProcessScheduler then
self:E( "Stop" )
self.ProcessScheduler:Stop()
self.ProcessScheduler = nil
self.AllowEvents = false
end
end end
--- Adds a score for the PROCESS to be achieved. --- Adds a score for the PROCESS to be achieved.
@ -60,10 +74,11 @@ function PROCESS:OnStateChange( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName } ) self:E( { Event, From, To, self.ProcessUnit.UnitName } )
if self.Scores[To] then if self.Scores[To] then
self.Unit:Message( "Score:" .. self.Scores[To].ScoreText .. " " .. To , 15 )
MESSAGE:New( "Score:" .. self.Scores[To].ScoreText .. " " .. To , 15 ):ToGroup( self.ProcessUnit:GetGroup() )
local Scoring = self.Task:GetScoring() local Scoring = self.Task:GetScoring()
if Scoring then if Scoring then
Scoring:_AddTaskProcessScore( self.ProcessUnit, self.Task:GetName(), self.Scores[To].Score ) Scoring:_AddMissionTaskScore( self.Task.Mission, self.ProcessUnit, self.Scores[To].ScoreText, self.Scores[To].Score )
end end
end end
end end

View File

@ -0,0 +1,105 @@
--- @module Task_Assign
--- PROCESS_ASSIGN class
-- @type PROCESS_ASSIGN
-- @field Task#TASK_BASE Task
-- @field Unit#UNIT ProcessUnit
-- @field Zone#ZONE_BASE TargetZone
-- @extends Task2#TASK2
PROCESS_ASSIGN = {
ClassName = "PROCESS_ASSIGN",
}
--- Creates a new task assignment state machine. The process will request from the menu if it accepts the task, if not, the unit is removed from the simulator.
-- @param #PROCESS_ASSIGN self
-- @param Task#TASK Task
-- @param Unit#UNIT Unit
-- @return #PROCESS_ASSIGN self
function PROCESS_ASSIGN:New( Task, ProcessUnit, TaskBriefing )
-- Inherits from BASE
local self = BASE:Inherit( self, PROCESS:New( Task, ProcessUnit ) ) -- #PROCESS_ASSIGN
self.TaskBriefing = TaskBriefing
self.Fsm = STATEMACHINE_PROCESS:New( self, {
initial = 'UnAssigned',
events = {
{ name = 'Menu', from = 'UnAssigned', to = 'AwaitAccept' },
{ name = 'Assign', from = 'AwaitAccept', to = 'Assigned' },
{ name = 'Reject', from = 'AwaitAccept', to = 'Rejected' },
{ name = 'Fail', from = 'AwaitAccept', to = 'Rejected' },
},
callbacks = {
onMenu = self.OnMenu,
onAssign = self.OnAssign,
onReject = self.OnReject,
},
endstates = {
'Assigned', 'Rejected'
},
} )
return self
end
--- StateMachine callback function for a TASK2
-- @param #PROCESS_ASSIGN self
-- @param StateMachine#STATEMACHINE_TASK Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ASSIGN:OnMenu( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
MESSAGE:New( self.TaskBriefing .. "\nAccess the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.", 30, "Assignment" ):ToGroup( self.ProcessUnit:GetGroup() )
self.MenuText = self.Task.TaskName
local ProcessGroup = self.ProcessUnit:GetGroup()
self.Menu = MENU_GROUP:New( ProcessGroup, "Task " .. self.MenuText .. " acceptance" )
self.MenuAcceptTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Accept task " .. self.MenuText, self.Menu, self.MenuAssign, self )
self.MenuRejectTask = MENU_GROUP_COMMAND:New( ProcessGroup, "Reject task " .. self.MenuText, self.Menu, self.MenuReject, self )
end
--- Menu function.
-- @param #PROCESS_ASSIGN self
function PROCESS_ASSIGN:MenuAssign()
self:E( )
self:NextEvent( self.Fsm.Assign )
end
--- Menu function.
-- @param #PROCESS_ASSIGN self
function PROCESS_ASSIGN:MenuReject()
self:E( )
self:NextEvent( self.Fsm.Reject )
end
--- StateMachine callback function for a TASK2
-- @param #PROCESS_ASSIGN self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ASSIGN:OnAssign( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
self.Menu:Remove()
end
--- StateMachine callback function for a TASK2
-- @param #PROCESS_ASSIGN self
-- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function PROCESS_ASSIGN:OnReject( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName} )
self.Menu:Remove()
self.Task:UnAssignFromUnit( self.ProcessUnit )
self.ProcessUnit:Destroy()
end

View File

@ -1,9 +1,9 @@
--- @module Task_Route --- @module Task_Route
--- TASK2_ROUTE_CLIENT class --- PROCESS_ROUTE class
-- @type TASK2_ROUTE_CLIENT -- @type PROCESS_ROUTE
-- @field Mission#MISSION Mission -- @field Task#TASK TASK
-- @field Unit#UNIT TaskUnit -- @field Unit#UNIT ProcessUnit
-- @field Zone#ZONE_BASE TargetZone -- @field Zone#ZONE_BASE TargetZone
-- @extends Task2#TASK2 -- @extends Task2#TASK2
PROCESS_ROUTE = { PROCESS_ROUTE = {
@ -12,14 +12,14 @@ PROCESS_ROUTE = {
--- Creates a new routing state machine. The task will route a CLIENT to a ZONE until the CLIENT is within that ZONE. --- Creates a new routing state machine. The task will route a CLIENT to a ZONE until the CLIENT is within that ZONE.
-- @param #TASK2_ROUTE_CLIENT self -- @param #PROCESS_ROUTE self
-- @param Mission#MISSION Mission -- @param Task#TASK Task
-- @param Unit#UNIT Unit -- @param Unit#UNIT Unit
-- @return #TASK2_ROUTE_CLIENT self -- @return #PROCESS_ROUTE self
function PROCESS_ROUTE:New( Mission, TaskUnit, TargetZone ) function PROCESS_ROUTE:New( Task, ProcessUnit, TargetZone )
-- Inherits from BASE -- Inherits from BASE
local self = BASE:Inherit( self, TASK2:New( Mission, TaskUnit ) ) -- #TASK2_ROUTE_CLIENT local self = BASE:Inherit( self, PROCESS:New( Task, ProcessUnit ) ) -- #PROCESS_ROUTE
self.TargetZone = TargetZone self.TargetZone = TargetZone
self.DisplayInterval = 30 self.DisplayInterval = 30
@ -28,7 +28,7 @@ function PROCESS_ROUTE:New( Mission, TaskUnit, TargetZone )
self.DisplayTime = 10 -- 10 seconds is the default self.DisplayTime = 10 -- 10 seconds is the default
self.DisplayCategory = "Route" -- Route is the default display category self.DisplayCategory = "Route" -- Route is the default display category
self.Fsm = STATEMACHINE_TASK:New( self, { self.Fsm = STATEMACHINE_PROCESS:New( self, {
initial = 'UnArrived', initial = 'UnArrived',
events = { events = {
{ name = 'Route', from = 'UnArrived', to = 'Arrived' }, { name = 'Route', from = 'UnArrived', to = 'Arrived' },
@ -49,24 +49,23 @@ end
--- Task Events --- Task Events
--- StateMachine callback function for a TASK2 --- StateMachine callback function for a TASK2
-- @param #TASK2_ROUTE_CLIENT self -- @param #PROCESS_ROUTE self
-- @param StateMachine#STATEMACHINE_TASK Fsm -- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
function PROCESS_ROUTE:OnLeaveUnArrived( Fsm, Event, From, To ) function PROCESS_ROUTE:OnLeaveUnArrived( Fsm, Event, From, To )
self:E( { Event, From, To, self.TaskUnit.UnitName } )
local IsInZone = self.TaskUnit:IsInZone( self.TargetZone ) local IsInZone = self.ProcessUnit:IsInZone( self.TargetZone )
if self.DisplayCount >= self.DisplayInterval then if self.DisplayCount >= self.DisplayInterval then
if not IsInZone then if not IsInZone then
local ZoneVec2 = self.TargetZone:GetVec2() local ZoneVec2 = self.TargetZone:GetVec2()
local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y ) local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y )
local TaskUnitVec2 = self.TaskUnit:GetVec2() local TaskUnitVec2 = self.ProcessUnit:GetVec2()
local TaskUnitPointVec2 = POINT_VEC2:New( TaskUnitVec2.x, TaskUnitVec2.y ) local TaskUnitPointVec2 = POINT_VEC2:New( TaskUnitVec2.x, TaskUnitVec2.y )
local RouteText = TaskUnitPointVec2:GetBRText( ZonePointVec2 ) local RouteText = TaskUnitPointVec2:GetBRText( ZonePointVec2 )
self.TaskUnit:Message( RouteText, self.DisplayTime, self.DisplayCategory ) MESSAGE:New( RouteText, self.DisplayTime, self.DisplayCategory ):ToGroup( self.ProcessUnit:GetGroup() )
end end
self.DisplayCount = 1 self.DisplayCount = 1
else else

View File

@ -3,38 +3,38 @@
--- PROCESS_SEAD class --- PROCESS_SEAD class
-- @type PROCESS_SEAD -- @type PROCESS_SEAD
-- @field Unit#UNIT ProcessUnit -- @field Unit#UNIT ProcessUnit
-- @field Set#SET_UNIT TargetSet -- @field Set#SET_UNIT TargetSetUnit
-- @extends Process#PROCESS -- @extends Process#PROCESS
PROCESS_SEAD = { PROCESS_SEAD = {
ClassName = "PROCESS_SEAD", ClassName = "PROCESS_SEAD",
Fsm = {}, Fsm = {},
TargetSet = nil, TargetSetUnit = nil,
} }
--- Creates a new SEAD task. --- Creates a new SEAD task.
-- @param #PROCESS_SEAD self -- @param #PROCESS_SEAD self
-- @param Task#MISSION Task -- @param Task#TASK Task
-- @param Unit#UNIT ProcessUnit -- @param Unit#UNIT ProcessUnit
-- @param Set#SET_UNIT TargetSet -- @param Set#SET_UNIT TargetSetUnit
-- @return #PROCESS_SEAD self -- @return #PROCESS_SEAD self
function PROCESS_SEAD:New( Task, ProcessUnit, TargetSet ) function PROCESS_SEAD:New( Task, ProcessUnit, TargetSetUnit )
-- Inherits from BASE -- Inherits from BASE
local self = BASE:Inherit( self, PROCESS:New( Task, ProcessUnit ) ) -- #PROCESS_SEAD local self = BASE:Inherit( self, PROCESS:New( Task, ProcessUnit ) ) -- #PROCESS_SEAD
self.TargetSet = TargetSet self.TargetSetUnit = TargetSetUnit
self.Fsm = STATEMACHINE_TASK:New( self, { self.Fsm = STATEMACHINE_PROCESS:New( self, {
initial = 'Assigned', initial = 'Assigned',
events = { events = {
{ name = 'Await', from = 'Assigned', to = 'Waiting' }, { name = 'Await', from = 'Assigned', to = 'Waiting' },
{ name = 'HitTarget', from = 'Waiting', to = 'Destroy' }, { name = 'HitTarget', from = 'Waiting', to = 'Destroy' },
{ name = 'MoreTargets', from = 'Destroy', to = 'Waiting' }, { name = 'MoreTargets', from = 'Destroy', to = 'Waiting' },
{ name = 'Destroyed', from = 'Destroy', to = 'Success' }, { name = 'Destroyed', from = 'Destroy', to = 'Success' },
{ name = 'Killed', from = 'Assigned', to = 'Failed' }, { name = 'Fail', from = 'Assigned', to = 'Failed' },
{ name = 'Killed', from = 'Waiting', to = 'Failed' }, { name = 'Fail', from = 'Waiting', to = 'Failed' },
{ name = 'Killed', from = 'Destroy', to = 'Failed' }, { name = 'Fail', from = 'Destroy', to = 'Failed' },
}, },
callbacks = { callbacks = {
onAwait = self.OnAwait, onAwait = self.OnAwait,
@ -48,8 +48,6 @@ function PROCESS_SEAD:New( Task, ProcessUnit, TargetSet )
_EVENTDISPATCHER:OnHit( self.EventHit, self ) _EVENTDISPATCHER:OnHit( self.EventHit, self )
_EVENTDISPATCHER:OnDead( self.EventKilled, self )
_EVENTDISPATCHER:OnCrash( self.EventKilled, self )
return self return self
end end
@ -58,28 +56,26 @@ end
--- StateMachine callback function for a PROCESS --- StateMachine callback function for a PROCESS
-- @param #PROCESS_SEAD self -- @param #PROCESS_SEAD self
-- @param StateMachine#STATEMACHINE_TASK Fsm -- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
function PROCESS_SEAD:OnAwait( Fsm, Event, From, To ) function PROCESS_SEAD:OnAwait( Fsm, Event, From, To )
self:E( { Event, From, To, self.ProcessUnit.UnitName} ) self:E( { Event, From, To, self.ProcessUnit.UnitName} )
self.ProcessUnit:Message( "Waiting", 15 )
self:NextEvent( Fsm.Await ) self:NextEvent( Fsm.Await )
end end
--- StateMachine callback function for a PROCESS --- StateMachine callback function for a PROCESS
-- @param #PROCESS_SEAD self -- @param #PROCESS_SEAD self
-- @param StateMachine#STATEMACHINE_TASK Fsm -- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
-- @param Event#EVENTDATA Event -- @param Event#EVENTDATA Event
function PROCESS_SEAD:OnHitTarget( Fsm, Event, From, To, Event ) function PROCESS_SEAD:OnHitTarget( Fsm, Event, From, To, Event )
self.ProcessUnit:Message( "Hit Target", 15 ) if self.TargetSetUnit:Count() > 0 then
if self.TargetSet:Count() > 0 then
self:NextEvent( Fsm.MoreTargets ) self:NextEvent( Fsm.MoreTargets )
else else
self:NextEvent( Fsm.Destroyed ) self:NextEvent( Fsm.Destroyed )
@ -88,46 +84,43 @@ end
--- StateMachine callback function for a PROCESS --- StateMachine callback function for a PROCESS
-- @param #PROCESS_SEAD self -- @param #PROCESS_SEAD self
-- @param StateMachine#STATEMACHINE_TASK Fsm -- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
function PROCESS_SEAD:OnMoreTargets( Fsm, Event, From, To ) function PROCESS_SEAD:OnMoreTargets( Fsm, Event, From, To )
self.ProcessUnit:Message( "More Targets", 15 )
end end
--- StateMachine callback function for a PROCESS --- StateMachine callback function for a PROCESS
-- @param #PROCESS_SEAD self -- @param #PROCESS_SEAD self
-- @param StateMachine#STATEMACHINE_TASK Fsm -- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
-- @param Event#EVENTDATA DCSEvent -- @param Event#EVENTDATA DCSEvent
function PROCESS_SEAD:OnKilled( Fsm, Event, From, To ) function PROCESS_SEAD:OnKilled( Fsm, Event, From, To )
self.ProcessUnit:Message( "Player got killed", 15 )
self:NextEvent( Fsm.Restart ) self:NextEvent( Fsm.Restart )
end end
--- StateMachine callback function for a PROCESS --- StateMachine callback function for a PROCESS
-- @param #PROCESS_SEAD self -- @param #PROCESS_SEAD self
-- @param StateMachine#STATEMACHINE_TASK Fsm -- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
function PROCESS_SEAD:OnRestart( Fsm, Event, From, To ) function PROCESS_SEAD:OnRestart( Fsm, Event, From, To )
self.ProcessUnit:Message( "Restart SEAD Process", 15 )
self:NextEvent( Fsm.Menu ) self:NextEvent( Fsm.Menu )
end end
--- StateMachine callback function for a PROCESS --- StateMachine callback function for a PROCESS
-- @param #PROCESS_SEAD self -- @param #PROCESS_SEAD self
-- @param StateMachine#STATEMACHINE_TASK Fsm -- @param StateMachine#STATEMACHINE_PROCESS Fsm
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
@ -148,14 +141,4 @@ function PROCESS_SEAD:EventHit( Event )
end end
end end
--- @param #PROCESS_SEAD self
-- @param Event#EVENTDATA Event
function PROCESS_SEAD:EventKilled( Event )
if Event.IniUnit then
if Event.IniUnitName == self.ProcessUnit.UnitName then
self:NextEvent( self.Fsm.Killed, Event )
end
end
end

View File

@ -95,6 +95,7 @@ function SCHEDULER:Stop()
self.Repeat = false self.Repeat = false
if self.ScheduleID then if self.ScheduleID then
self:E( "Stop Schedule" )
timer.removeFunction( self.ScheduleID ) timer.removeFunction( self.ScheduleID )
end end
self.ScheduleID = nil self.ScheduleID = nil

View File

@ -263,13 +263,16 @@ end
--- Registers Scores the players completing a Mission Task. --- Registers Scores the players completing a Mission Task.
-- @param #SCORING self -- @param #SCORING self
-- @param Mission#MISSION Mission
-- @param Unit#UNIT PlayerUnit -- @param Unit#UNIT PlayerUnit
-- @param #string MissionName -- @param #string Text
-- @param #number Score -- @param #number Score
function SCORING:_AddMissionTaskScore( PlayerUnit, MissionName, Score ) function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
self:F( { PlayerUnit.UnitName, MissionName, Score } )
local PlayerName = PlayerUnit:GetPlayerName() local PlayerName = PlayerUnit:GetPlayerName()
local MissionName = Mission:GetName()
self:F( { Mission:GetName(), PlayerUnit.UnitName, PlayerName, Text, Score } )
if not self.Players[PlayerName].Mission[MissionName] then if not self.Players[PlayerName].Mission[MissionName] then
self.Players[PlayerName].Mission[MissionName] = {} self.Players[PlayerName].Mission[MissionName] = {}
@ -283,9 +286,9 @@ function SCORING:_AddMissionTaskScore( PlayerUnit, MissionName, Score )
self.Players[PlayerName].Score = self.Players[PlayerName].Score + Score self.Players[PlayerName].Score = self.Players[PlayerName].Score + Score
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
MESSAGE:New( "Player '" .. PlayerName .. "' has finished another Task in Mission '" .. MissionName .. "'. " .. MESSAGE:New( "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
Score .. " Score points added.", Score .. " points!",
20 ):ToAll() 30 ):ToAll()
self:ScoreCSV( PlayerName, "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() ) self:ScoreCSV( PlayerName, "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
end end

View File

@ -113,6 +113,8 @@ function STATEMACHINE:_create_transition(name)
local fsmparent, event = self:_isendstate( to ) local fsmparent, event = self:_isendstate( to )
if fsmparent and event then if fsmparent and event then
self:_call_handler(self["onenter" .. to] or self["on" .. to], params)
self:_call_handler(self["onafter" .. name] or self["on" .. name], params)
self:_call_handler(self["onstatechange"], params) self:_call_handler(self["onstatechange"], params)
fsmparent[event]( fsmparent ) fsmparent[event]( fsmparent )
execute = false execute = false
@ -146,11 +148,13 @@ function STATEMACHINE:_isendstate( state )
self:E( { state = state, endstates = self.endstates, endstate = self.endstates[state] } ) self:E( { state = state, endstates = self.endstates, endstate = self.endstates[state] } )
local returnevent = nil local returnevent = nil
local fromstate = fsmparent.current local fromstate = fsmparent.current
self:E( fromstate )
self:E( self.returnevents )
for _, eventname in pairs( self.returnevents ) do for _, eventname in pairs( self.returnevents ) do
local event = fsmparent.events[eventname] local event = fsmparent.events[eventname]
self:E( event ) self:E( event )
local to = event and event.map[fromstate] or event.map['*'] local to = event and event.map[fromstate] or event.map['*']
if to then if to and to == state then
return fsmparent, eventname return fsmparent, eventname
end end
end end
@ -232,3 +236,34 @@ function STATEMACHINE_PROCESS:_call_handler( handler, params )
return handler( self.Process, unpack( params ) ) return handler( self.Process, unpack( params ) )
end end
end end
--- STATEMACHINE_TASK class
-- @type STATEMACHINE_TASK
-- @field Task#TASK_BASE Task
-- @extends StateMachine#STATEMACHINE
STATEMACHINE_TASK = {
ClassName = "STATEMACHINE_TASK",
}
--- Creates a new STATEMACHINE_TASK object.
-- @param #STATEMACHINE_TASK self
-- @return #STATEMACHINE_TASK
function STATEMACHINE_TASK:New( Task, options )
local FsmTask = routines.utils.deepCopy( self ) -- Create a new self instance
local Parent = STATEMACHINE:New(options)
setmetatable( FsmTask, Parent )
FsmTask.__index = FsmTask
FsmTask["onstatechange"] = Task.OnStateChange
FsmTask.Task = Task
return FsmTask
end
function STATEMACHINE_TASK:_call_handler( handler, params )
if handler then
return handler( self.Task, unpack( params ) )
end
end

View File

@ -10,18 +10,22 @@ TASK_BASE = {
ClassName = "TASK_BASE", ClassName = "TASK_BASE",
TaskScheduler = nil, TaskScheduler = nil,
Processes = {}, Processes = {},
Players = nil,
Scores = {}, Scores = {},
} }
--- Instantiates a new TASK_BASE. Should never be used. Interface Class. --- Instantiates a new TASK_BASE. Should never be used. Interface Class.
-- @param #TASK_BASE self -- @param #TASK_BASE self
-- @return #TASK_BASE self -- @return #TASK_BASE self
function TASK_BASE:New() function TASK_BASE:New( Mission, TaskName )
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, BASE:New() )
self:F() self:F()
self.Processes = {} self.Processes = {}
self.Fsm = {} self.Fsm = {}
self.Mission = Mission
self.TaskName = TaskName
self.TaskBriefing = "You are assigned to the task: " .. self.TaskName .. "."
return self return self
end end
@ -31,7 +35,7 @@ end
-- @param Group#GROUP TaskGroup -- @param Group#GROUP TaskGroup
-- @return #TASK_BASE self -- @return #TASK_BASE self
function TASK_BASE:AssignToGroup( TaskGroup ) function TASK_BASE:AssignToGroup( TaskGroup )
self:FZ( TaskGroup:GetName() ) self:F2( TaskGroup:GetName() )
local TaskUnits = TaskGroup:GetUnits() local TaskUnits = TaskGroup:GetUnits()
for UnitID, UnitData in pairs( TaskUnits ) do for UnitID, UnitData in pairs( TaskUnits ) do
@ -44,6 +48,8 @@ function TASK_BASE:AssignToGroup( TaskGroup )
return self return self
end end
--- Add Process to @{Task} with key @{Unit} --- Add Process to @{Task} with key @{Unit}
-- @param #TASK_BASE self -- @param #TASK_BASE self
-- @param Unit#UNIT TaskUnit -- @param Unit#UNIT TaskUnit
@ -58,11 +64,19 @@ end
--- Remove Processes from @{Task} with key @{Unit} --- Remove Processes from @{Task} with key @{Unit}
-- @param #TASK_BASE self -- @param #TASK_BASE self
-- @return #TASK_BASE self -- @return #TASK_BASE self
function TASK_BASE:RemoveProcesses( TaskUnit ) function TASK_BASE:RemoveProcesses( TaskUnit, FailProcesses )
local TaskUnitName = TaskUnit:GetName() local TaskUnitName = TaskUnit:GetName()
for _, Process in pairs( self.Processes[TaskUnitName] ) do for _, ProcessData in pairs( self.Processes[TaskUnitName] ) do
local Process = ProcessData -- Process#PROCESS
if FailProcesses then
Process.Fsm:Fail()
end
Process:StopEvents()
Process = nil Process = nil
self.Processes[TaskUnitName][_] = nil
self:E( self.Processes[TaskUnitName][_] )
end end
self.Processes[TaskUnitName] = nil
end end
--- Add a FiniteStateMachine to @{Task} with key @{Unit} --- Add a FiniteStateMachine to @{Task} with key @{Unit}
@ -83,7 +97,20 @@ function TASK_BASE:RemoveStateMachines( TaskUnit )
local TaskUnitName = TaskUnit:GetName() local TaskUnitName = TaskUnit:GetName()
for _, Fsm in pairs( self.Fsm[TaskUnitName] ) do for _, Fsm in pairs( self.Fsm[TaskUnitName] ) do
Fsm = nil Fsm = nil
self.Fsm[TaskUnitName][_] = nil
self:E( self.Fsm[TaskUnitName][_] )
end end
self.Fsm[TaskUnitName] = nil
end
--- Checks if there is a FiniteStateMachine assigned to @{Unit} for @{Task}
-- @param #TASK_BASE self
-- @param Unit#UNIT TaskUnit
-- @return #TASK_BASE self
function TASK_BASE:HasStateMachine( TaskUnit )
local TaskUnitName = TaskUnit:GetName()
self:F( { TaskUnitName, self.Fsm[TaskUnitName] ~= nil } )
return ( self.Fsm[TaskUnitName] ~= nil )
end end
@ -94,10 +121,173 @@ end
-- @param Unit#UNIT TaskUnit -- @param Unit#UNIT TaskUnit
-- @return #TASK_BASE self -- @return #TASK_BASE self
function TASK_BASE:AssignToUnit( TaskUnit ) function TASK_BASE:AssignToUnit( TaskUnit )
self:F( TaskUnit:GetName() )
return nil return nil
end end
--- UnAssign the @{Task} from an alive @{Unit}.
-- @param #TASK_BASE self
-- @param Unit#UNIT TaskUnit
-- @return #TASK_BASE self
function TASK_BASE:UnAssignFromUnit( TaskUnit, FailProcesses )
self:F( TaskUnit:GetName() )
if self:HasStateMachine( TaskUnit ) == true then
self:RemoveStateMachines( TaskUnit )
self:RemoveProcesses( TaskUnit, FailProcesses )
end
return self
end
--- Register a potential new assignment for a new spawned @{Unit}.
-- Tasks only get assigned if there are players in it.
-- @param #TASK_BASE self
-- @param Event#EVENTDATA Event
-- @return #TASK_BASE self
function TASK_BASE:_EventAssignUnit( Event )
if Event.IniUnit then
self:F( Event )
local TaskUnit = Event.IniUnit
if TaskUnit:IsAlive() then
local TaskPlayerName = TaskUnit:GetPlayerName()
if TaskPlayerName ~= nil then
if not self:HasStateMachine( TaskUnit ) then
self:AssignToUnit( TaskUnit )
end
end
end
end
return nil
end
--- UnAssigns a @{Unit} that is left by a player, crashed, dead, ....
-- There are only assignments if there are players in it.
-- @param #TASK_BASE self
-- @param Event#EVENTDATA Event
-- @return #TASK_BASE self
function TASK_BASE:_EventUnAssignUnit( Event )
self:F( Event )
if Event.IniUnit then
local TaskUnit = Event.IniUnit
self:F( TaskUnit:GetName() )
self:UnAssignFromUnit( TaskUnit, true )
end
return nil
end
--- Gets the scoring of the task
-- @param #TASK_BASE self
-- @return Scoring#SCORING Scoring
function TASK_BASE:GetScoring()
return self.Mission:GetScoring()
end
--- Sets the name of the task
-- @param #TASK_BASE self
-- @param #string TaskName
-- @return Scoring#SCORING Scoring
function TASK_BASE:SetName( TaskName )
self.TaskName = TaskName
end
--- Gets the name of the task
-- @param #TASK_BASE self
-- @return Scoring#SCORING Scoring
function TASK_BASE:GetName()
return self.TaskName
end
--- Sets a @{Task} to status **Success**.
-- @param #TASK_BASE self
function TASK_BASE:StateSuccess()
self:SetState( self, "State", "Success" )
end
--- Is the @{Task} status **Success**.
-- @param #TASK_BASE self
function TASK_BASE:IsStateSuccess()
return self:GetStateString() == "Success"
end
--- Sets a @{Task} to status **Failed**.
-- @param #TASK_BASE self
function TASK_BASE:StateFailed()
self:SetState( self, "State", "Failed" )
end
--- Is the @{Task} status **Failed**.
-- @param #TASK_BASE self
function TASK_BASE:IsStateFailed()
return self:GetStateString() == "Failed"
end
--- Sets a @{Task} to status **Planned**.
-- @param #TASK_BASE self
function TASK_BASE:StatePlanned()
self:SetState( self, "State", "Planned" )
end
--- Is the @{Task} status **Planned**.
-- @param #TASK_BASE self
function TASK_BASE:IsStatePlanned()
return self:GetStateString() == "Planned"
end
--- Sets a @{Task} to status **Assigned**.
-- @param #TASK_BASE self
function TASK_BASE:StateAssigned()
self:SetState( self, "State", "Assigned" )
end
--- Is the @{Task} status **Assigned**.
-- @param #TASK_BASE self
function TASK_BASE:IsStateAssigned()
return self:GetStateString() == "Assigned"
end
--- Sets a @{Task} to status **Hold**.
-- @param #TASK_BASE self
function TASK_BASE:StateHold()
self:SetState( self, "State", "Hold" )
end
--- Is the @{Task} status **Hold**.
-- @param #TASK_BASE self
function TASK_BASE:IsStateHold()
return self:GetStateString() == "Hold"
end
--- Sets a @{Task} to status **Replanned**.
-- @param #TASK_BASE self
function TASK_BASE:StateReplanned()
self:SetState( self, "State", "Replanned" )
end
--- Is the @{Task} status **Replanned**.
-- @param #TASK_BASE self
function TASK_BASE:IsStateReplanned()
return self:GetStateString() == "Replanned"
end
--- Gets the @{Task} status.
-- @param #TASK_BASE self
function TASK_BASE:GetStateString()
return self:GetState( self, "State" )
end
--- Sets a @{Task} briefing.
-- @param #TASK_BASE self
-- @param #string TaskBriefing
-- @return self
function TASK_BASE:SetBriefing( TaskBriefing )
self.TaskBriefing = TaskBriefing
return self
end
--- @param #TASK_BASE self --- @param #TASK_BASE self
function TASK_BASE:_Schedule() function TASK_BASE:_Schedule()

View File

@ -9,15 +9,24 @@ TASK_SEAD = {
--- Instantiates a new TASK_SEAD. Should never be used. Interface Class. --- Instantiates a new TASK_SEAD. Should never be used. Interface Class.
-- @param #TASK_SEAD self -- @param #TASK_SEAD self
-- @param Mission#MISSION Mission
-- @param Set#SET_UNIT UnitSetTargets -- @param Set#SET_UNIT UnitSetTargets
-- @param Zone#ZONE_BASE TargetZone
-- @return #TASK_SEAD self -- @return #TASK_SEAD self
function TASK_SEAD:New( TargetSetUnit, TargetZone ) function TASK_SEAD:New( Mission, TargetSetUnit, TargetZone )
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, TASK_BASE:New( Mission, "SEAD" ) )
self:F() self:F()
self.TargetSetUnit= TargetSetUnit self.TargetSetUnit = TargetSetUnit
self.TargetZone = TargetZone self.TargetZone = TargetZone
_EVENTDISPATCHER:OnBirth( self._EventAssignUnit, self )
_EVENTDISPATCHER:OnPlayerEnterUnit(self._EventAssignUnit, self )
_EVENTDISPATCHER:OnPlayerLeaveUnit(self._EventUnAssignUnit, self )
_EVENTDISPATCHER:OnCrash(self._EventUnAssignUnit, self )
_EVENTDISPATCHER:OnDead(self._EventUnAssignUnit, self )
_EVENTDISPATCHER:OnPilotDead(self._EventUnAssignUnit, self )
return self return self
end end
@ -26,33 +35,55 @@ end
-- @param Unit#UNIT TaskUnit -- @param Unit#UNIT TaskUnit
-- @return #TASK_SEAD self -- @return #TASK_SEAD self
function TASK_SEAD:AssignToUnit( TaskUnit ) function TASK_SEAD:AssignToUnit( TaskUnit )
self:F( TaskUnit:GetName() )
local ProcessAssign = self:AddProcess( TaskUnit, PROCESS_ASSIGN:New( self, TaskUnit, self.TaskBriefing ) )
local ProcessRoute = self:AddProcess( TaskUnit, PROCESS_ROUTE:New( self, TaskUnit, self.TargetZone ) ) local ProcessRoute = self:AddProcess( TaskUnit, PROCESS_ROUTE:New( self, TaskUnit, self.TargetZone ) )
local ProcessSEAD = self:AddProcess( TaskUnit, PROCESS_SEAD:New( self, TaskUnit, self.TargetUnitSet ) ) local ProcessSEAD = self:AddProcess( TaskUnit, PROCESS_SEAD:New( self, TaskUnit, self.TargetSetUnit ) )
local Process = self:AddStateMachine( TaskUnit, STATEMACHINE:New( { local Process = self:AddStateMachine( TaskUnit, STATEMACHINE_TASK:New( self, {
initial = 'None', initial = 'None',
events = { events = {
{ name = 'Start', from = 'None', to = 'Assigned' }, { name = 'Next', from = 'None', to = 'Planned' },
{ name = 'Next', from = 'Unassigned', to = 'Assigned' }, { name = 'Next', from = 'Planned', to = 'Assigned' },
{ name = 'Reject', from = 'Planned', to = 'Rejected' },
{ name = 'Next', from = 'Assigned', to = 'Success' }, { name = 'Next', from = 'Assigned', to = 'Success' },
{ name = 'Fail', from = 'Assigned', to = 'Failed' }, { name = 'Fail', from = 'Assigned', to = 'Failed' },
{ name = 'Fail', from = 'Arrived', to = 'Failed' } { name = 'Fail', from = 'Arrived', to = 'Failed' }
}, },
callbacks = {
onNext = self.OnNext,
onRemove = self.OnRemove,
},
subs = { subs = {
Route = { onstateparent = 'Assigned', oneventparent = 'Start', fsm = ProcessRoute.Fsm, event = 'Route' }, Assign = { onstateparent = 'Planned', oneventparent = 'Next', fsm = ProcessAssign.Fsm, event = 'Menu', returnevents = { 'Next', 'Reject' } },
Route = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessRoute.Fsm, event = 'Route' },
Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSEAD.Fsm, event = 'Await', returnevents = { 'Next' } } Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = ProcessSEAD.Fsm, event = 'Await', returnevents = { 'Next' } }
} }
} ) ) } ) )
---Task_Client_Sead:AddScore( "Destroy", "Destroyed RADAR", 25 ) ProcessRoute:AddScore( "Failed", "failed to destroy a radar", -100 )
---Task_Client_Sead:AddScore( "Success", "Destroyed all radars!!!", 100 ) ProcessSEAD:AddScore( "Destroy", "destroyed a radar", 25 )
ProcessSEAD:AddScore( "Failed", "failed to destroy a radar", -100 )
Process:Start() Process:Next()
return self return self
end end
--- StateMachine callback function for a TASK
-- @param #TASK_SEAD self
-- @param StateMachine#STATEMACHINE_TASK Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Event#EVENTDATA Event
function TASK_SEAD:OnNext( Fsm, Event, From, To, Event )
self:SetState( self, "State", To )
end
--- @param #TASK_SEAD self --- @param #TASK_SEAD self
function TASK_SEAD:_Schedule() function TASK_SEAD:_Schedule()
self:F2() self:F2()

View File

@ -179,6 +179,24 @@ function UNIT:IsActive()
return nil return nil
end end
--- Destroys the @{Unit}.
-- @param Unit#UNIT self
-- @return #nil The DCS Unit is not existing or alive.
function UNIT:Destroy()
self:F2( self.UnitName )
local DCSUnit = self:GetDCSObject()
if DCSUnit then
DCSUnit:destroy()
end
return nil
end
--- Returns the Unit's callsign - the localized string. --- Returns the Unit's callsign - the localized string.
-- @param Unit#UNIT self -- @param Unit#UNIT self
-- @return #string The Callsign of the Unit. -- @return #string The Callsign of the Unit.

View File

@ -1,15 +1,16 @@
local Mission = MISSION:New( 'SEAD Targets', "Strategic", "SEAD the enemy", "RUSSIA" ) local Mission = MISSION:New( 'SEAD Targets', "Strategic", "SEAD the enemy", coalition.side.RED )
local Scoring = SCORING:New( "SEAD" ) local Scoring = SCORING:New( "SEAD" )
Mission:AddScoring( Scoring ) Mission:AddScoring( Scoring )
local Client = CLIENT:FindByName( "Test SEAD" ) local SEADGroup = GROUP:FindByName( "Test SEAD" )
local TargetSet = SET_UNIT:New():FilterPrefixes( "US Hawk SR" ):FilterStart() local TargetSet = SET_UNIT:New():FilterPrefixes( "US Hawk SR" ):FilterStart()
local TargetZone = ZONE:New( "Target Zone" ) local TargetZone = ZONE:New( "Target Zone" )
local Task_SEAD = TASK_SEAD:New( TargetSet, TargetZone ) local TaskSEAD = TASK_SEAD:New( Mission, TargetSet, TargetZone ):SetName( "SEAD Radars" ):AssignToGroup( SEADGroup )