mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a406604bd | ||
|
|
55cee46a8d | ||
|
|
607c52c0b7 | ||
|
|
2694321256 | ||
|
|
e8e790102a | ||
|
|
9c5561921b | ||
|
|
78fab9ab0c | ||
|
|
058c750bc6 | ||
|
|
f29da39dff | ||
|
|
624a7c70c9 | ||
|
|
0447ee2d9e | ||
|
|
456fcd38d0 | ||
|
|
a3cab7097a | ||
|
|
848e2f1294 | ||
|
|
ef4dc48ea1 | ||
|
|
2138a33292 | ||
|
|
a59343b987 | ||
|
|
a4ca4bdc99 | ||
|
|
a57b9a9081 | ||
|
|
249a6af456 | ||
|
|
18685d1a94 | ||
|
|
493b090534 | ||
|
|
389adab9b8 | ||
|
|
6360b8c58f | ||
|
|
b0818977cf | ||
|
|
32deb160ef | ||
|
|
2ba5215036 | ||
|
|
73ea4c7b32 | ||
|
|
46c37ff06a | ||
|
|
ff4708b624 | ||
|
|
82b2c84f13 | ||
|
|
48e8b1a9b3 | ||
|
|
1ad7c54ace | ||
|
|
9998c86c1f | ||
|
|
01a707ae0a | ||
|
|
570e8388fc | ||
|
|
9c5b5d4633 | ||
|
|
822bf13626 | ||
|
|
c520de0087 | ||
|
|
0e9076efa3 | ||
|
|
74cd5e3387 | ||
|
|
65c92be09e | ||
|
|
8e776cb3ab | ||
|
|
ab6cd2b751 | ||
|
|
18c3d990fc | ||
|
|
19d5cb8ecb | ||
|
|
2b56a78255 | ||
|
|
176d9df476 | ||
|
|
c94275cb8b | ||
|
|
45dbce3677 | ||
|
|
18745158a3 | ||
|
|
98c6c88391 | ||
|
|
2e4fd72781 | ||
|
|
80ced88ef1 | ||
|
|
8af3f89c14 | ||
|
|
fe3079caad | ||
|
|
61ac6b4131 | ||
|
|
36cb189512 | ||
|
|
15f9843878 | ||
|
|
67f847dd16 |
33
Moose Development/Moose/.lua-format
Normal file
33
Moose Development/Moose/.lua-format
Normal file
@@ -0,0 +1,33 @@
|
||||
# See https://github.com/Koihik/LuaFormatter
|
||||
# Use '-- LuaFormatter off' and '-- LuaFormatter on' around code blocks to inhibit formatting
|
||||
|
||||
column_limit: 500
|
||||
indent_width: 2
|
||||
use_tab: false
|
||||
continuation_indent_width: 2
|
||||
keep_simple_control_block_one_line: false
|
||||
keep_simple_function_one_line: false
|
||||
align_args: true
|
||||
break_after_functioncall_lp: false
|
||||
break_before_functioncall_rp: false
|
||||
align_parameter: true
|
||||
chop_down_parameter: true
|
||||
break_after_functiondef_lp: false
|
||||
break_before_functiondef_rp: false
|
||||
align_table_field: true
|
||||
break_after_table_lb: true
|
||||
break_before_table_rb: true
|
||||
chop_down_table: true
|
||||
chop_down_kv_table: true
|
||||
column_table_limit: 500
|
||||
table_sep: ','
|
||||
extra_sep_at_table_end: true
|
||||
break_after_operator: true
|
||||
single_quote_to_double_quote: false
|
||||
double_quote_to_single_quote: false
|
||||
spaces_before_call: 1
|
||||
spaces_inside_functiondef_parens: true
|
||||
spaces_inside_functioncall_parens: true
|
||||
spaces_inside_table_braces: true
|
||||
spaces_around_equals_in_field: true
|
||||
line_breaks_after_function_body: 1
|
||||
File diff suppressed because it is too large
Load Diff
@@ -585,7 +585,7 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||
|
||||
if AIGroup and AIGroup:IsAlive() then
|
||||
|
||||
self:I( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
|
||||
self:T( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
|
||||
|
||||
self:ClearTargetDistance()
|
||||
--AIGroup:ClearTasks()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-- * The construction and inheritance of MOOSE classes.
|
||||
-- * The class naming and numbering system.
|
||||
-- * The class hierarchy search system.
|
||||
-- * The tracing of information or objects during mission execution for debuggin purposes.
|
||||
-- * The tracing of information or objects during mission execution for debugging purposes.
|
||||
-- * The subscription to DCS events for event handling in MOOSE objects.
|
||||
-- * Object inspection.
|
||||
--
|
||||
@@ -49,7 +49,8 @@ local _ClassID = 0
|
||||
-- # 2. Trace information for debugging.
|
||||
--
|
||||
-- The BASE class contains trace methods to trace progress within a mission execution of a certain object.
|
||||
-- These trace methods are inherited by each MOOSE class interiting BASE, soeach object created from derived class from BASE can use the tracing methods to trace its execution.
|
||||
-- These trace methods are inherited by each MOOSE class inheriting BASE, thus all objects created from
|
||||
-- a class derived from BASE can use the tracing methods to trace its execution.
|
||||
--
|
||||
-- Any type of information can be passed to these tracing methods. See the following examples:
|
||||
--
|
||||
@@ -111,7 +112,6 @@ local _ClassID = 0
|
||||
--
|
||||
-- The method @{#BASE.IsTrace}() will validate if tracing is activated or not.
|
||||
--
|
||||
--
|
||||
-- # 3. DCS simulator Event Handling.
|
||||
--
|
||||
-- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator,
|
||||
@@ -157,8 +157,6 @@ local _ClassID = 0
|
||||
-- self:SmokeBlue()
|
||||
-- end
|
||||
--
|
||||
--
|
||||
--
|
||||
-- See the @{Event} module for more information about event handling.
|
||||
--
|
||||
-- # 4. Class identification methods.
|
||||
@@ -203,13 +201,12 @@ BASE = {
|
||||
Scheduler = nil,
|
||||
}
|
||||
|
||||
|
||||
--- @field #BASE.__
|
||||
BASE.__ = {}
|
||||
|
||||
--- @field #BASE._
|
||||
BASE._ = {
|
||||
Schedules = {} --- Contains the Schedulers Active
|
||||
Schedules = {}, --- Contains the Schedulers Active
|
||||
}
|
||||
|
||||
--- The Formation Class
|
||||
@@ -217,11 +214,9 @@ BASE._ = {
|
||||
-- @field Cone A cone formation.
|
||||
FORMATION = {
|
||||
Cone = "Cone",
|
||||
Vee = "Vee"
|
||||
Vee = "Vee",
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- BASE constructor.
|
||||
--
|
||||
-- This is an example how to use the BASE:New() constructor in a new class definition when inheriting from BASE.
|
||||
@@ -236,16 +231,16 @@ FORMATION = {
|
||||
function BASE:New()
|
||||
local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
||||
|
||||
_ClassID = _ClassID + 1
|
||||
self.ClassID = _ClassID
|
||||
_ClassID = _ClassID + 1
|
||||
self.ClassID = _ClassID
|
||||
|
||||
-- This is for "private" methods...
|
||||
-- When a __ is passed to a method as "self", the __index will search for the method on the public method list too!
|
||||
-- if rawget( self, "__" ) then
|
||||
--setmetatable( self, { __index = self.__ } )
|
||||
-- end
|
||||
-- This is for "private" methods...
|
||||
-- When a __ is passed to a method as "self", the __index will search for the method on the public method list too!
|
||||
-- if rawget( self, "__" ) then
|
||||
-- setmetatable( self, { __index = self.__ } )
|
||||
-- end
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- This is the worker method to inherit from a parent class.
|
||||
@@ -256,26 +251,25 @@ end
|
||||
function BASE:Inherit( Child, Parent )
|
||||
|
||||
-- Create child.
|
||||
local Child = routines.utils.deepCopy( Child )
|
||||
local Child = routines.utils.deepCopy( Child )
|
||||
|
||||
if Child ~= nil then
|
||||
if Child ~= nil then
|
||||
|
||||
-- This is for "private" methods...
|
||||
-- When a __ is passed to a method as "self", the __index will search for the method on the public method list of the same object too!
|
||||
-- This is for "private" methods...
|
||||
-- When a __ is passed to a method as "self", the __index will search for the method on the public method list of the same object too!
|
||||
if rawget( Child, "__" ) then
|
||||
setmetatable( Child, { __index = Child.__ } )
|
||||
setmetatable( Child, { __index = Child.__ } )
|
||||
setmetatable( Child.__, { __index = Parent } )
|
||||
else
|
||||
setmetatable( Child, { __index = Parent } )
|
||||
end
|
||||
|
||||
--Child:_SetDestructor()
|
||||
end
|
||||
-- Child:_SetDestructor()
|
||||
end
|
||||
|
||||
return Child
|
||||
return Child
|
||||
end
|
||||
|
||||
|
||||
local function getParent( Child )
|
||||
local Parent = nil
|
||||
|
||||
@@ -291,7 +285,6 @@ local function getParent( Child )
|
||||
return Parent
|
||||
end
|
||||
|
||||
|
||||
--- This is the worker method to retrieve the Parent class.
|
||||
-- Note that the Parent class must be passed to call the parent class method.
|
||||
--
|
||||
@@ -304,19 +297,18 @@ end
|
||||
-- @return #BASE
|
||||
function BASE:GetParent( Child, FromClass )
|
||||
|
||||
|
||||
local Parent
|
||||
-- BASE class has no parent
|
||||
if Child.ClassName == 'BASE' then
|
||||
Parent = nil
|
||||
else
|
||||
|
||||
--self:E({FromClass = FromClass})
|
||||
--self:E({Child = Child.ClassName})
|
||||
-- self:E({FromClass = FromClass})
|
||||
-- self:E({Child = Child.ClassName})
|
||||
if FromClass then
|
||||
while( Child.ClassName ~= "BASE" and Child.ClassName ~= FromClass.ClassName ) do
|
||||
while (Child.ClassName ~= "BASE" and Child.ClassName ~= FromClass.ClassName) do
|
||||
Child = getParent( Child )
|
||||
--self:E({Child.ClassName})
|
||||
-- self:E({Child.ClassName})
|
||||
end
|
||||
end
|
||||
if Child.ClassName == 'BASE' then
|
||||
@@ -325,7 +317,7 @@ function BASE:GetParent( Child, FromClass )
|
||||
Parent = getParent( Child )
|
||||
end
|
||||
end
|
||||
--self:E({Parent.ClassName})
|
||||
-- self:E({Parent.ClassName})
|
||||
return Parent
|
||||
end
|
||||
|
||||
@@ -354,11 +346,11 @@ function BASE:IsInstanceOf( ClassName )
|
||||
-- Get the name of the Moose class as a string
|
||||
ClassName = ClassName.ClassName
|
||||
|
||||
-- className is neither a string nor a Moose class, throw an error
|
||||
-- className is neither a string nor a Moose class, throw an error
|
||||
else
|
||||
|
||||
-- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall
|
||||
local err_str = 'className parameter should be a string; parameter received: '..type( ClassName )
|
||||
local err_str = 'className parameter should be a string; parameter received: ' .. type( ClassName )
|
||||
self:E( err_str )
|
||||
-- error( err_str )
|
||||
return false
|
||||
@@ -372,7 +364,7 @@ function BASE:IsInstanceOf( ClassName )
|
||||
return true
|
||||
end
|
||||
|
||||
local Parent = getParent(self)
|
||||
local Parent = getParent( self )
|
||||
|
||||
while Parent do
|
||||
|
||||
@@ -419,7 +411,6 @@ do -- Event Handling
|
||||
return _EVENTDISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- Get the Class @{Event} processing Priority.
|
||||
-- The Event processing Priority is a number from 1 to 10,
|
||||
-- reflecting the order of the classes subscribed to the Event to be processed.
|
||||
@@ -474,35 +465,35 @@ do -- Event Handling
|
||||
|
||||
-- Event handling function prototypes
|
||||
|
||||
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or autocannon based weapon, those are handled by EVENT.ShootingStart.
|
||||
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or auto cannon based weapon, those are handled by EVENT.ShootingStart.
|
||||
-- @function [parent=#BASE] OnEventShot
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs whenever an object is hit by a weapon.
|
||||
-- initiator : The unit object the fired the weapon
|
||||
-- weapon: Weapon object that hit the target
|
||||
-- initiator : The unit object the fired the weapon.
|
||||
-- weapon: Weapon object that hit the target.
|
||||
-- target: The Object that was hit.
|
||||
-- @function [parent=#BASE] OnEventHit
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an aircraft takes off from an airbase, farp, or ship.
|
||||
-- initiator : The unit that tookoff
|
||||
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships
|
||||
-- initiator : The unit that took off.
|
||||
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships.
|
||||
-- @function [parent=#BASE] OnEventTakeoff
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when an aircraft lands at an airbase, farp or ship
|
||||
-- initiator : The unit that has landed
|
||||
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships
|
||||
-- initiator : The unit that has landed.
|
||||
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships.
|
||||
-- @function [parent=#BASE] OnEventLand
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any aircraft crashes into the ground and is completely destroyed.
|
||||
-- initiator : The unit that has crashed
|
||||
-- initiator : The unit that has crashed.
|
||||
-- @function [parent=#BASE] OnEventCrash
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
@@ -538,18 +529,18 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a ground unit captures either an airbase or a farp.
|
||||
-- initiator : The unit that captured the base
|
||||
-- initiator : The unit that captured the base.
|
||||
-- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction.
|
||||
-- @function [parent=#BASE] OnEventBaseCaptured
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a mission starts
|
||||
--- Occurs when a mission starts.
|
||||
-- @function [parent=#BASE] OnEventMissionStart
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when a mission ends
|
||||
--- Occurs when a mission ends.
|
||||
-- @function [parent=#BASE] OnEventMissionEnd
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
@@ -561,25 +552,25 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any object is spawned into the mission.
|
||||
-- initiator : The unit that was spawned
|
||||
-- initiator : The unit that was spawned.
|
||||
-- @function [parent=#BASE] OnEventBirth
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any system fails on a human controlled aircraft.
|
||||
-- initiator : The unit that had the failure
|
||||
-- initiator : The unit that had the failure.
|
||||
-- @function [parent=#BASE] OnEventHumanFailure
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any aircraft starts its engines.
|
||||
-- initiator : The unit that is starting its engines.
|
||||
-- initiator : The unit that is starting its engines..
|
||||
-- @function [parent=#BASE] OnEventEngineStartup
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any aircraft shuts down its engines.
|
||||
-- initiator : The unit that is stopping its engines.
|
||||
-- initiator : The unit that is stopping its engines..
|
||||
-- @function [parent=#BASE] OnEventEngineShutdown
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
@@ -596,7 +587,7 @@ do -- Event Handling
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), autocannons, and machine guns.
|
||||
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), auto cannons, and machine guns.
|
||||
-- initiator : The unit that is doing the shooting.
|
||||
-- target: The unit that is being targeted.
|
||||
-- @function [parent=#BASE] OnEventShootingStart
|
||||
@@ -627,7 +618,6 @@ do -- Event Handling
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
|
||||
--- Unknown precisely what creates this event, likely tied into newer damage model. Will update this page when new information become available.
|
||||
--
|
||||
-- * initiator: The unit that had the failure.
|
||||
@@ -644,7 +634,7 @@ do -- Event Handling
|
||||
|
||||
--- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs.
|
||||
--
|
||||
-- * initiator: The unit that killed the target
|
||||
-- * initiator: The unit that killed the target.
|
||||
-- * target: Target Object
|
||||
-- * weapon: Weapon Object
|
||||
--
|
||||
@@ -706,7 +696,6 @@ do -- Event Handling
|
||||
-- @param #BASE self
|
||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||
|
||||
|
||||
--- Occurs when a player enters a slot and takes control of an aircraft.
|
||||
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
|
||||
-- initiator : The unit that is being taken control of.
|
||||
@@ -716,7 +705,6 @@ do -- Event Handling
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Creation of a Birth Event.
|
||||
-- @param #BASE self
|
||||
-- @param DCS#Time EventTime The time stamp of the event.
|
||||
@@ -725,18 +713,18 @@ end
|
||||
-- @param place
|
||||
-- @param subplace
|
||||
function BASE:CreateEventBirth( EventTime, Initiator, IniUnitName, place, subplace )
|
||||
self:F( { EventTime, Initiator, IniUnitName, place, subplace } )
|
||||
self:F( { EventTime, Initiator, IniUnitName, place, subplace } )
|
||||
|
||||
local Event = {
|
||||
id = world.event.S_EVENT_BIRTH,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
IniUnitName = IniUnitName,
|
||||
place = place,
|
||||
subplace = subplace
|
||||
}
|
||||
local Event = {
|
||||
id = world.event.S_EVENT_BIRTH,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
IniUnitName = IniUnitName,
|
||||
place = place,
|
||||
subplace = subplace,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a Crash Event.
|
||||
@@ -744,15 +732,15 @@ end
|
||||
-- @param DCS#Time EventTime The time stamp of the event.
|
||||
-- @param DCS#Object Initiator The initiating object of the event.
|
||||
function BASE:CreateEventCrash( EventTime, Initiator )
|
||||
self:F( { EventTime, Initiator } )
|
||||
self:F( { EventTime, Initiator } )
|
||||
|
||||
local Event = {
|
||||
id = world.event.S_EVENT_CRASH,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
}
|
||||
local Event = {
|
||||
id = world.event.S_EVENT_CRASH,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a Dead Event.
|
||||
@@ -766,7 +754,7 @@ function BASE:CreateEventDead( EventTime, Initiator )
|
||||
id = world.event.S_EVENT_DEAD,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
@@ -782,7 +770,7 @@ function BASE:CreateEventRemoveUnit( EventTime, Initiator )
|
||||
id = EVENTS.RemoveUnit,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
@@ -798,56 +786,56 @@ function BASE:CreateEventTakeoff( EventTime, Initiator )
|
||||
id = world.event.S_EVENT_TAKEOFF,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event.
|
||||
-- @param #BASE self
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
|
||||
function BASE:CreateEventPlayerEnterAircraft( PlayerUnit )
|
||||
self:F( { PlayerUnit } )
|
||||
--- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event.
|
||||
-- @param #BASE self
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
|
||||
function BASE:CreateEventPlayerEnterAircraft( PlayerUnit )
|
||||
self:F( { PlayerUnit } )
|
||||
|
||||
local Event = {
|
||||
id = EVENTS.PlayerEnterAircraft,
|
||||
time = timer.getTime(),
|
||||
initiator = PlayerUnit:GetDCSObject()
|
||||
}
|
||||
local Event = {
|
||||
id = EVENTS.PlayerEnterAircraft,
|
||||
time = timer.getTime(),
|
||||
initiator = PlayerUnit:GetDCSObject(),
|
||||
}
|
||||
|
||||
world.onEvent(Event)
|
||||
end
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
-- TODO: Complete DCS#Event structure.
|
||||
--- The main event handling function... This function captures all events generated for the class.
|
||||
-- @param #BASE self
|
||||
-- @param DCS#Event event
|
||||
function BASE:onEvent(event)
|
||||
function BASE:onEvent( event )
|
||||
|
||||
if self then
|
||||
if self then
|
||||
|
||||
for EventID, EventObject in pairs(self.Events) do
|
||||
if EventObject.EventEnabled then
|
||||
for EventID, EventObject in pairs( self.Events ) do
|
||||
if EventObject.EventEnabled then
|
||||
|
||||
if event.id == EventObject.Event then
|
||||
if event.id == EventObject.Event then
|
||||
|
||||
if self == EventObject.Self then
|
||||
if self == EventObject.Self then
|
||||
|
||||
if event.initiator and event.initiator:isExist() then
|
||||
event.IniUnitName = event.initiator:getName()
|
||||
end
|
||||
if event.initiator and event.initiator:isExist() then
|
||||
event.IniUnitName = event.initiator:getName()
|
||||
end
|
||||
|
||||
if event.target and event.target:isExist() then
|
||||
event.TgtUnitName = event.target:getName()
|
||||
end
|
||||
if event.target and event.target:isExist() then
|
||||
event.TgtUnitName = event.target:getName()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do -- Scheduling
|
||||
@@ -865,23 +853,23 @@ do -- Scheduling
|
||||
local ObjectName = "-"
|
||||
ObjectName = self.ClassName .. self.ClassID
|
||||
|
||||
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
||||
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
||||
|
||||
if not self.Scheduler then
|
||||
self.Scheduler = SCHEDULER:New( self )
|
||||
end
|
||||
|
||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||
self,
|
||||
SchedulerFunction,
|
||||
{ ... },
|
||||
Start,
|
||||
nil,
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
self,
|
||||
SchedulerFunction,
|
||||
{ ... },
|
||||
Start,
|
||||
nil,
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||
self._.Schedules[#self._.Schedules + 1] = ScheduleID
|
||||
|
||||
return self._.Schedules[#self._.Schedules]
|
||||
end
|
||||
@@ -909,17 +897,17 @@ do -- Scheduling
|
||||
end
|
||||
|
||||
local ScheduleID = self.Scheduler:Schedule(
|
||||
self,
|
||||
SchedulerFunction,
|
||||
{ ... },
|
||||
Start,
|
||||
Repeat,
|
||||
RandomizeFactor,
|
||||
Stop,
|
||||
4
|
||||
)
|
||||
self,
|
||||
SchedulerFunction,
|
||||
{ ... },
|
||||
Start,
|
||||
Repeat,
|
||||
RandomizeFactor,
|
||||
Stop,
|
||||
4
|
||||
)
|
||||
|
||||
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||
self._.Schedules[#self._.Schedules + 1] = ScheduleID
|
||||
|
||||
return self._.Schedules[#self._.Schedules]
|
||||
end
|
||||
@@ -938,9 +926,8 @@ do -- Scheduling
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Set a state or property of the Object given a Key and a Value.
|
||||
-- Note that if the Object is destroyed, nillified or garbage collected, then the Values and Keys will also be gone.
|
||||
-- Note that if the Object is destroyed, set to nil, or garbage collected, then the Values and Keys will also be gone.
|
||||
-- @param #BASE self
|
||||
-- @param Object The object that will hold the Value set by the Key.
|
||||
-- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type!
|
||||
@@ -956,9 +943,8 @@ function BASE:SetState( Object, Key, Value )
|
||||
return self.States[ClassNameAndID][Key]
|
||||
end
|
||||
|
||||
|
||||
--- Get a Value given a Key from the Object.
|
||||
-- Note that if the Object is destroyed, nillified or garbage collected, then the Values and Keys will also be gone.
|
||||
-- Note that if the Object is destroyed, set to nil, or garbage collected, then the Values and Keys will also be gone.
|
||||
-- @param #BASE self
|
||||
-- @param Object The object that holds the Value set by the Key.
|
||||
-- @param Key The key that is used to retrieve the value. Note that the key can be a #string, but it can also be any other type!
|
||||
@@ -1010,8 +996,6 @@ function BASE:TraceOff()
|
||||
self:TraceOnOff( false )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Set trace on or off
|
||||
-- Note that when trace is off, no BASE.Debug statement is performed, increasing performance!
|
||||
-- When Moose is loaded statically, (as one file), tracing is switched off by default.
|
||||
@@ -1020,28 +1004,29 @@ end
|
||||
-- @param #BASE self
|
||||
-- @param #boolean TraceOnOff Switch the tracing on or off.
|
||||
-- @usage
|
||||
-- -- Switch the tracing On
|
||||
-- BASE:TraceOnOff( true )
|
||||
--
|
||||
-- -- Switch the tracing Off
|
||||
-- BASE:TraceOnOff( false )
|
||||
-- -- Switch the tracing On
|
||||
-- BASE:TraceOnOff( true )
|
||||
--
|
||||
-- -- Switch the tracing Off
|
||||
-- BASE:TraceOnOff( false )
|
||||
--
|
||||
function BASE:TraceOnOff( TraceOnOff )
|
||||
if TraceOnOff==false then
|
||||
if TraceOnOff == false then
|
||||
self:I( "Tracing in MOOSE is OFF" )
|
||||
_TraceOnOff = false
|
||||
else
|
||||
self:I( "Tracing in MOOSE is ON" )
|
||||
self:I( "Tracing in MOOSE is ON" )
|
||||
_TraceOnOff = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Enquires if tracing is on (for the class).
|
||||
-- @param #BASE self
|
||||
-- @return #boolean
|
||||
function BASE:IsTrace()
|
||||
|
||||
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
||||
if BASE.Debug and (_TraceAll == true) or (_TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName]) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -1061,8 +1046,8 @@ end
|
||||
-- @param #boolean TraceAll true = trace all methods in MOOSE.
|
||||
function BASE:TraceAll( TraceAll )
|
||||
|
||||
if TraceAll==false then
|
||||
_TraceAll=false
|
||||
if TraceAll == false then
|
||||
_TraceAll = false
|
||||
else
|
||||
_TraceAll = true
|
||||
end
|
||||
@@ -1101,7 +1086,7 @@ end
|
||||
-- @param Arguments A #table or any field.
|
||||
function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||
|
||||
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
||||
if BASE.Debug and (_TraceAll == true) or (_TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName]) then
|
||||
|
||||
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
|
||||
@@ -1120,7 +1105,7 @@ function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1140,7 +1125,6 @@ function BASE:F( Arguments )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Trace a function call level 2. Must be at the beginning of the function logic.
|
||||
-- @param #BASE self
|
||||
-- @param Arguments A #table or any field.
|
||||
@@ -1176,28 +1160,28 @@ end
|
||||
-- @param Arguments A #table or any field.
|
||||
function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
|
||||
|
||||
if BASE.Debug and ( _TraceAll == true ) or ( _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName] ) then
|
||||
if BASE.Debug and (_TraceAll == true) or (_TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName]) then
|
||||
|
||||
local DebugInfoCurrent = DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = DebugInfoFromParam and DebugInfoFromParam or BASE.Debug.getinfo( 3, "l" )
|
||||
|
||||
local Function = "function"
|
||||
if DebugInfoCurrent.name then
|
||||
Function = DebugInfoCurrent.name
|
||||
end
|
||||
local Function = "function"
|
||||
if DebugInfoCurrent.name then
|
||||
Function = DebugInfoCurrent.name
|
||||
end
|
||||
|
||||
if _TraceAll == true or _TraceClass[self.ClassName] or _TraceClassMethod[self.ClassName].Method[Function] then
|
||||
local LineCurrent = 0
|
||||
if DebugInfoCurrent.currentline then
|
||||
LineCurrent = DebugInfoCurrent.currentline
|
||||
end
|
||||
local LineFrom = 0
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
local LineFrom = 0
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s", LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Trace a function logic level 1. Can be anywhere within the function logic.
|
||||
@@ -1215,7 +1199,6 @@ function BASE:T( Arguments )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Trace a function logic level 2. Can be anywhere within the function logic.
|
||||
-- @param #BASE self
|
||||
-- @param Arguments A #table or any field.
|
||||
@@ -1252,28 +1235,27 @@ end
|
||||
function BASE:E( Arguments )
|
||||
|
||||
if BASE.Debug then
|
||||
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||
local DebugInfoCurrent = BASE.Debug.getinfo( 2, "nl" )
|
||||
local DebugInfoFrom = BASE.Debug.getinfo( 3, "l" )
|
||||
|
||||
local Function = "function"
|
||||
if DebugInfoCurrent.name then
|
||||
Function = DebugInfoCurrent.name
|
||||
end
|
||||
local Function = "function"
|
||||
if DebugInfoCurrent.name then
|
||||
Function = DebugInfoCurrent.name
|
||||
end
|
||||
|
||||
local LineCurrent = DebugInfoCurrent.currentline
|
||||
local LineCurrent = DebugInfoCurrent.currentline
|
||||
local LineFrom = -1
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
if DebugInfoFrom then
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
else
|
||||
env.info( string.format( "%1s:%30s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Log an information which will be traced always. Can be anywhere within the function logic.
|
||||
-- @param #BASE self
|
||||
-- @param Arguments A #table or any field.
|
||||
@@ -1294,26 +1276,23 @@ function BASE:I( Arguments )
|
||||
LineFrom = DebugInfoFrom.currentline
|
||||
end
|
||||
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)", LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
else
|
||||
env.info( string.format( "%1s:%30s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
env.info( string.format( "%1s:%30s%05d(%s)", "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- old stuff
|
||||
|
||||
--function BASE:_Destructor()
|
||||
-- function BASE:_Destructor()
|
||||
-- --self:E("_Destructor")
|
||||
--
|
||||
-- --self:EventRemoveAll()
|
||||
--end
|
||||
|
||||
-- end
|
||||
|
||||
-- THIS IS WHY WE NEED LUA 5.2 ...
|
||||
--function BASE:_SetDestructor()
|
||||
-- function BASE:_SetDestructor()
|
||||
--
|
||||
-- -- TODO: Okay, this is really technical...
|
||||
-- -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
|
||||
@@ -1334,4 +1313,4 @@ end
|
||||
-- -- will be invoked and the destructor called
|
||||
-- rawset( self, '__proxy', proxy )
|
||||
--
|
||||
--end
|
||||
-- end
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will receive radio capabilities.
|
||||
-- @extends Core.Base#BASE
|
||||
BEACON = {
|
||||
ClassName = "BEACON",
|
||||
ClassName = "BEACON",
|
||||
Positionable = nil,
|
||||
name = nil,
|
||||
name = nil,
|
||||
}
|
||||
|
||||
--- Beacon types supported by DCS.
|
||||
@@ -95,11 +95,11 @@ BEACON.Type={
|
||||
-- @field #number TACAN TACtical Air Navigation system on ground.
|
||||
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
|
||||
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
|
||||
-- @field #number VOR Very High Frequency Omni-Directional Range
|
||||
-- @field #number VOR Very High Frequency Omnidirectional Range
|
||||
-- @field #number ILS_LOCALIZER ILS localizer
|
||||
-- @field #number ILS_GLIDESLOPE ILS glideslope.
|
||||
-- @field #number ILS_GLIDESLOPE ILS glide slope.
|
||||
-- @field #number PRGM_LOCALIZER PRGM localizer.
|
||||
-- @field #number PRGM_GLIDESLOPE PRGM glideslope.
|
||||
-- @field #number PRGM_GLIDESLOPE PRGM glide slope.
|
||||
-- @field #number BROADCAST_STATION Broadcast station.
|
||||
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
||||
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
|
||||
@@ -131,28 +131,27 @@ BEACON.System={
|
||||
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
|
||||
-- @param #BEACON self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
||||
-- @return #BEACON Beacon object or #nil if the positionable is invalid.
|
||||
function BEACON:New(Positionable)
|
||||
-- @return #BEACON Beacon object or #nil if the POSITIONABLE is invalid.
|
||||
function BEACON:New( Positionable )
|
||||
|
||||
-- Inherit BASE.
|
||||
local self=BASE:Inherit(self, BASE:New()) --#BEACON
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #BEACON
|
||||
|
||||
-- Debug.
|
||||
self:F(Positionable)
|
||||
self:F( Positionable )
|
||||
|
||||
-- Set positionable.
|
||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
|
||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure POSITIONABLE is valid
|
||||
self.Positionable = Positionable
|
||||
self.name=Positionable:GetName()
|
||||
self:I(string.format("New BEACON %s", tostring(self.name)))
|
||||
self.name = Positionable:GetName()
|
||||
self:I( string.format( "New BEACON %s", tostring( self.name ) ) )
|
||||
return self
|
||||
end
|
||||
|
||||
self:E({"The passed positionable is invalid, no BEACON created", Positionable})
|
||||
self:E( { "The passed POSITIONABLE is invalid, no BEACON created", Positionable } )
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Activates a TACAN BEACON.
|
||||
-- @param #BEACON self
|
||||
-- @param #number Channel TACAN channel, i.e. the "10" part in "10Y".
|
||||
@@ -162,51 +161,53 @@ end
|
||||
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||
-- @return #BEACON self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Let's create a TACAN Beacon for a tanker
|
||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
||||
--
|
||||
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
|
||||
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
||||
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
|
||||
--
|
||||
function BEACON:ActivateTACAN( Channel, Mode, Message, Bearing, Duration )
|
||||
self:T( { channel = Channel, mode = Mode, callsign = Message, bearing = Bearing, duration = Duration } )
|
||||
|
||||
-- Get frequency.
|
||||
local Frequency=UTILS.TACANToFrequency(Channel, Mode)
|
||||
local Frequency = UTILS.TACANToFrequency( Channel, Mode )
|
||||
|
||||
-- Check.
|
||||
if not Frequency then
|
||||
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
|
||||
self:E( { "The passed TACAN channel is invalid, the BEACON is not emitting" } )
|
||||
return self
|
||||
end
|
||||
|
||||
-- Beacon type.
|
||||
local Type=BEACON.Type.TACAN
|
||||
local Type = BEACON.Type.TACAN
|
||||
|
||||
-- Beacon system.
|
||||
local System=BEACON.System.TACAN
|
||||
local System = BEACON.System.TACAN
|
||||
|
||||
-- Check if unit is an aircraft and set system accordingly.
|
||||
local AA=self.Positionable:IsAir()
|
||||
local AA = self.Positionable:IsAir()
|
||||
if AA then
|
||||
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
||||
System = 5 -- NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
||||
-- Check if "Y" mode is selected for aircraft.
|
||||
if Mode~="Y" then
|
||||
self:E({"WARNING: The POSITIONABLE you want to attach the AA Tacan Beacon is an aircraft: Mode should Y !The BEACON is not emitting.", self.Positionable})
|
||||
if Mode ~= "Y" then
|
||||
self:E( { "WARNING: The POSITIONABLE you want to attach the AA TACAN Beacon is an aircraft: Mode should Y! The BEACON is not emitting.", self.Positionable } )
|
||||
end
|
||||
end
|
||||
|
||||
-- Attached unit.
|
||||
local UnitID=self.Positionable:GetID()
|
||||
local UnitID = self.Positionable:GetID()
|
||||
|
||||
-- Debug.
|
||||
self:I({string.format("BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring(self.name), Channel, Mode, Message, tostring(Bearing), tostring(Duration))})
|
||||
self:I( { string.format( "BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring( self.name ), Channel, Mode, Message, tostring( Bearing ), tostring( Duration ) ) } )
|
||||
|
||||
-- Start beacon.
|
||||
self.Positionable:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing)
|
||||
self.Positionable:CommandActivateBeacon( Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing )
|
||||
|
||||
-- Stop sheduler.
|
||||
-- Stop scheduler.
|
||||
if Duration then
|
||||
self.Positionable:DeactivateBeacon(Duration)
|
||||
self.Positionable:DeactivateBeacon( Duration )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -218,21 +219,21 @@ end
|
||||
-- @param #string Callsign The Message that is going to be coded in Morse and broadcasted by the beacon.
|
||||
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||
-- @return #BEACON self
|
||||
function BEACON:ActivateICLS(Channel, Callsign, Duration)
|
||||
self:F({Channel=Channel, Callsign=Callsign, Duration=Duration})
|
||||
function BEACON:ActivateICLS( Channel, Callsign, Duration )
|
||||
self:F( { Channel = Channel, Callsign = Callsign, Duration = Duration } )
|
||||
|
||||
-- Attached unit.
|
||||
local UnitID=self.Positionable:GetID()
|
||||
local UnitID = self.Positionable:GetID()
|
||||
|
||||
-- Debug
|
||||
self:T2({"ICLS BEACON started!"})
|
||||
self:T2( { "ICLS BEACON started!" } )
|
||||
|
||||
-- Start beacon.
|
||||
self.Positionable:CommandActivateICLS(Channel, UnitID, Callsign)
|
||||
self.Positionable:CommandActivateICLS( Channel, UnitID, Callsign )
|
||||
|
||||
-- Stop sheduler
|
||||
-- Stop scheduler
|
||||
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
self.Positionable:DeactivateBeacon(Duration)
|
||||
self.Positionable:DeactivateBeacon( Duration )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -246,24 +247,26 @@ end
|
||||
-- @param #number BeaconDuration How long will the beacon last in seconds. Omit for forever.
|
||||
-- @return #BEACON self
|
||||
-- @usage
|
||||
--
|
||||
-- -- Let's create a TACAN Beacon for a tanker
|
||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
||||
--
|
||||
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
||||
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
||||
--
|
||||
function BEACON:AATACAN( TACANChannel, Message, Bearing, BeaconDuration )
|
||||
self:F( { TACANChannel, Message, Bearing, BeaconDuration } )
|
||||
|
||||
local IsValid = true
|
||||
|
||||
if not self.Positionable:IsAir() then
|
||||
self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting", self.Positionable})
|
||||
self:E( { "The POSITIONABLE you want to attach the AA TACAN Beacon is not an aircraft! The BEACON is not emitting", self.Positionable } )
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
local Frequency = self:_TACANToFrequency(TACANChannel, "Y")
|
||||
local Frequency = self:_TACANToFrequency( TACANChannel, "Y" )
|
||||
if not Frequency then
|
||||
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
|
||||
self:E( { "The passed TACAN channel is invalid, the BEACON is not emitting" } )
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
@@ -277,22 +280,21 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
end
|
||||
|
||||
if IsValid then -- Starts the BEACON
|
||||
self:T2({"AA TACAN BEACON started !"})
|
||||
self.Positionable:SetCommand({
|
||||
self:T2( { "AA TACAN BEACON started !" } )
|
||||
self.Positionable:SetCommand( {
|
||||
id = "ActivateBeacon",
|
||||
params = {
|
||||
type = 4,
|
||||
system = System,
|
||||
callsign = Message,
|
||||
frequency = Frequency,
|
||||
}
|
||||
})
|
||||
},
|
||||
} )
|
||||
|
||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
SCHEDULER:New(nil,
|
||||
function()
|
||||
SCHEDULER:New( nil, function()
|
||||
self:StopAATACAN()
|
||||
end, {}, BeaconDuration)
|
||||
end, {}, BeaconDuration )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -305,18 +307,16 @@ end
|
||||
function BEACON:StopAATACAN()
|
||||
self:F()
|
||||
if not self.Positionable then
|
||||
self:E({"Start the beacon first before stoping it !"})
|
||||
self:E( { "Start the beacon first before stopping it!" } )
|
||||
else
|
||||
self.Positionable:SetCommand({
|
||||
self.Positionable:SetCommand( {
|
||||
id = 'DeactivateBeacon',
|
||||
params = {
|
||||
}
|
||||
})
|
||||
params = {},
|
||||
} )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Activates a general pupose Radio Beacon
|
||||
--- Activates a general purpose Radio Beacon
|
||||
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
|
||||
-- Although any frequency could be used, only 2 DCS Modules can home on radio beacons at the time of writing : the Huey and the Mi-8.
|
||||
-- They can home in on these specific frequencies :
|
||||
@@ -342,54 +342,53 @@ end
|
||||
--
|
||||
-- -- Set the beacon and start it
|
||||
-- UnitBeacon:RadioBeacon("MySoundFileSOS.ogg", 40, radio.modulation.FM, 20, 5*60)
|
||||
function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDuration)
|
||||
self:F({FileName, Frequency, Modulation, Power, BeaconDuration})
|
||||
function BEACON:RadioBeacon( FileName, Frequency, Modulation, Power, BeaconDuration )
|
||||
self:F( { FileName, Frequency, Modulation, Power, BeaconDuration } )
|
||||
local IsValid = false
|
||||
|
||||
-- Check the filename
|
||||
if type(FileName) == "string" then
|
||||
if FileName:find(".ogg") or FileName:find(".wav") then
|
||||
if not FileName:find("l10n/DEFAULT/") then
|
||||
if type( FileName ) == "string" then
|
||||
if FileName:find( ".ogg" ) or FileName:find( ".wav" ) then
|
||||
if not FileName:find( "l10n/DEFAULT/" ) then
|
||||
FileName = "l10n/DEFAULT/" .. FileName
|
||||
end
|
||||
IsValid = true
|
||||
end
|
||||
end
|
||||
if not IsValid then
|
||||
self:E({"File name invalid. Maybe something wrong with the extension ? ", FileName})
|
||||
self:E( { "File name invalid. Maybe something wrong with the extension? ", FileName } )
|
||||
end
|
||||
|
||||
-- Check the Frequency
|
||||
if type(Frequency) ~= "number" and IsValid then
|
||||
self:E({"Frequency invalid. ", Frequency})
|
||||
if type( Frequency ) ~= "number" and IsValid then
|
||||
self:E( { "Frequency invalid. ", Frequency } )
|
||||
IsValid = false
|
||||
end
|
||||
Frequency = Frequency * 1000000 -- Conversion to Hz
|
||||
|
||||
-- Check the modulation
|
||||
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then --TODO Maybe make this future proof if ED decides to add an other modulation ?
|
||||
self:E({"Modulation is invalid. Use DCS's enum radio.modulation.", Modulation})
|
||||
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then -- TODO: Maybe make this future proof if ED decides to add an other modulation ?
|
||||
self:E( { "Modulation is invalid. Use DCS's enum radio.modulation.", Modulation } )
|
||||
IsValid = false
|
||||
end
|
||||
|
||||
-- Check the Power
|
||||
if type(Power) ~= "number" and IsValid then
|
||||
self:E({"Power is invalid. ", Power})
|
||||
if type( Power ) ~= "number" and IsValid then
|
||||
self:E( { "Power is invalid. ", Power } )
|
||||
IsValid = false
|
||||
end
|
||||
Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
|
||||
Power = math.floor( math.abs( Power ) ) -- TODO: Find what is the maximum power allowed by DCS and limit power to that
|
||||
|
||||
if IsValid then
|
||||
self:T2({"Activating Beacon on ", Frequency, Modulation})
|
||||
self:T2( { "Activating Beacon on ", Frequency, Modulation } )
|
||||
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID
|
||||
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID))
|
||||
trigger.action.radioTransmission( FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring( self.ID ) )
|
||||
|
||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
SCHEDULER:New( nil,
|
||||
function()
|
||||
self:StopRadioBeacon()
|
||||
end, {}, BeaconDuration)
|
||||
end
|
||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||
SCHEDULER:New( nil, function()
|
||||
self:StopRadioBeacon()
|
||||
end, {}, BeaconDuration )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -399,7 +398,7 @@ end
|
||||
function BEACON:StopRadioBeacon()
|
||||
self:F()
|
||||
-- The unique name of the transmission is the class ID
|
||||
trigger.action.stopRadioTransmission(tostring(self.ID))
|
||||
trigger.action.stopRadioTransmission( tostring( self.ID ) )
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -407,21 +406,21 @@ end
|
||||
-- @param #BEACON self
|
||||
-- @param #number TACANChannel
|
||||
-- @param #string TACANMode
|
||||
-- @return #number Frequecy
|
||||
-- @return #number Frequency
|
||||
-- @return #nil if parameters are invalid
|
||||
function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
|
||||
self:F3({TACANChannel, TACANMode})
|
||||
function BEACON:_TACANToFrequency( TACANChannel, TACANMode )
|
||||
self:F3( { TACANChannel, TACANMode } )
|
||||
|
||||
if type(TACANChannel) ~= "number" then
|
||||
if type( TACANChannel ) ~= "number" then
|
||||
if TACANMode ~= "X" and TACANMode ~= "Y" then
|
||||
return nil -- error in arguments
|
||||
end
|
||||
end
|
||||
|
||||
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
||||
-- I have no idea what it does but it seems to work
|
||||
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
||||
-- I have no idea what it does but it seems to work
|
||||
local A = 1151 -- 'X', channel >= 64
|
||||
local B = 64 -- channel >= 64
|
||||
local B = 64 -- channel >= 64
|
||||
|
||||
if TACANChannel < 64 then
|
||||
B = 1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
||||
-- 
|
||||
--
|
||||
-- Within a running mission, various DCS events occur. Units are dynamically created, crash, die, shoot stuff, get hit etc.
|
||||
-- This module provides a mechanism to dispatch those events occuring within your running mission, to the different objects orchestrating your mission.
|
||||
-- This module provides a mechanism to dispatch those events occurring within your running mission, to the different objects orchestrating your mission.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
@@ -141,7 +141,6 @@
|
||||
-- EventData.IniUnit:SmokeGreen()
|
||||
-- end
|
||||
--
|
||||
--
|
||||
-- Find below an overview which events populate which information categories:
|
||||
--
|
||||
-- 
|
||||
@@ -172,7 +171,6 @@
|
||||
-- @module Core.Event
|
||||
-- @image Core_Event.JPG
|
||||
|
||||
|
||||
--- @type EVENT
|
||||
-- @field #EVENT.Events Events
|
||||
-- @extends Core.Base#BASE
|
||||
@@ -194,7 +192,6 @@ world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
|
||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
||||
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
|
||||
|
||||
|
||||
--- The different types of events supported by MOOSE.
|
||||
-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method.
|
||||
-- @type EVENTS
|
||||
@@ -227,13 +224,13 @@ EVENTS = {
|
||||
MarkChange = world.event.S_EVENT_MARK_CHANGE,
|
||||
MarkRemoved = world.event.S_EVENT_MARK_REMOVED,
|
||||
-- Moose Events
|
||||
NewCargo = world.event.S_EVENT_NEW_CARGO,
|
||||
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
|
||||
NewZone = world.event.S_EVENT_NEW_ZONE,
|
||||
DeleteZone = world.event.S_EVENT_DELETE_ZONE,
|
||||
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
|
||||
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
|
||||
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
||||
NewCargo = world.event.S_EVENT_NEW_CARGO,
|
||||
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
|
||||
NewZone = world.event.S_EVENT_NEW_ZONE,
|
||||
DeleteZone = world.event.S_EVENT_DELETE_ZONE,
|
||||
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
|
||||
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
|
||||
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
||||
PlayerEnterAircraft = world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT,
|
||||
-- Added with DCS 2.5.6
|
||||
DetailedFailure = world.event.S_EVENT_DETAILED_FAILURE or -1, --We set this to -1 for backward compatibility to DCS 2.5.5 and earlier
|
||||
@@ -304,8 +301,6 @@ EVENTS = {
|
||||
-- @field Core.ZONE#ZONE Zone The zone object.
|
||||
-- @field #string ZoneName The name of the zone.
|
||||
|
||||
|
||||
|
||||
local _EVENTMETA = {
|
||||
[world.event.S_EVENT_SHOT] = {
|
||||
Order = 1,
|
||||
@@ -562,7 +557,6 @@ local _EVENTMETA = {
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
--- The Events structure
|
||||
-- @type EVENT.Events
|
||||
-- @field #number IniUnit
|
||||
@@ -576,12 +570,11 @@ function EVENT:New()
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
|
||||
-- Add world event handler.
|
||||
self.EventHandler = world.addEventHandler(self)
|
||||
self.EventHandler = world.addEventHandler( self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Initializes the Events structure for the event.
|
||||
-- @param #EVENT self
|
||||
-- @param DCS#world.event EventID Event ID.
|
||||
@@ -595,7 +588,7 @@ function EVENT:Init( EventID, EventClass )
|
||||
self.Events[EventID] = {}
|
||||
end
|
||||
|
||||
-- Each event has a subtable of EventClasses, ordered by EventPriority.
|
||||
-- Each event has a sub-table of EventClasses, ordered by EventPriority.
|
||||
local EventPriority = EventClass:GetEventPriority()
|
||||
|
||||
if not self.Events[EventID][EventPriority] then
|
||||
@@ -603,7 +596,7 @@ function EVENT:Init( EventID, EventClass )
|
||||
end
|
||||
|
||||
if not self.Events[EventID][EventPriority][EventClass] then
|
||||
self.Events[EventID][EventPriority][EventClass] = {}
|
||||
self.Events[EventID][EventPriority][EventClass] = {}
|
||||
end
|
||||
|
||||
return self.Events[EventID][EventPriority][EventClass]
|
||||
@@ -614,7 +607,7 @@ end
|
||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||
-- @param DCS#world.event EventID Event ID.
|
||||
-- @return #EVENT self
|
||||
function EVENT:RemoveEvent( EventClass, EventID )
|
||||
function EVENT:RemoveEvent( EventClass, EventID )
|
||||
|
||||
-- Debug info.
|
||||
self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
|
||||
@@ -638,7 +631,7 @@ end
|
||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||
-- @param DCS#world.event EventID Event ID.
|
||||
-- @return #EVENT.Events
|
||||
function EVENT:Reset( EventObject ) --R2.1
|
||||
function EVENT:Reset( EventObject ) -- R2.1
|
||||
|
||||
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
|
||||
|
||||
@@ -657,12 +650,11 @@ function EVENT:Reset( EventObject ) --R2.1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.Base#BASE EventClass The self class object for which the events are removed.
|
||||
-- @return #EVENT self
|
||||
function EVENT:RemoveAll(EventClass)
|
||||
function EVENT:RemoveAll( EventClass )
|
||||
|
||||
local EventClassName = EventClass:GetClassNameAndID()
|
||||
|
||||
@@ -676,8 +668,6 @@ function EVENT:RemoveAll(EventClass)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Create an OnDead event handler for a group
|
||||
-- @param #EVENT self
|
||||
-- @param #table EventTemplate
|
||||
@@ -709,7 +699,6 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set a new listener for an `S_EVENT_X` event for a UNIT.
|
||||
-- @param #EVENT self
|
||||
-- @param #string UnitName The name of the UNIT.
|
||||
@@ -797,7 +786,6 @@ do -- OnDead
|
||||
|
||||
end
|
||||
|
||||
|
||||
do -- OnLand
|
||||
|
||||
--- Create an OnLand event handler for a group
|
||||
@@ -864,7 +852,7 @@ do -- Event Creation
|
||||
id = EVENTS.NewCargo,
|
||||
time = timer.getTime(),
|
||||
cargo = Cargo,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
@@ -879,7 +867,7 @@ do -- Event Creation
|
||||
id = EVENTS.DeleteCargo,
|
||||
time = timer.getTime(),
|
||||
cargo = Cargo,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
@@ -894,7 +882,7 @@ do -- Event Creation
|
||||
id = EVENTS.NewZone,
|
||||
time = timer.getTime(),
|
||||
zone = Zone,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
@@ -909,7 +897,7 @@ do -- Event Creation
|
||||
id = EVENTS.DeleteZone,
|
||||
time = timer.getTime(),
|
||||
zone = Zone,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
@@ -924,12 +912,11 @@ do -- Event Creation
|
||||
id = EVENTS.NewZoneGoal,
|
||||
time = timer.getTime(),
|
||||
ZoneGoal = ZoneGoal,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
|
||||
--- Creation of a ZoneGoal Deletion Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
@@ -940,12 +927,11 @@ do -- Event Creation
|
||||
id = EVENTS.DeleteZoneGoal,
|
||||
time = timer.getTime(),
|
||||
ZoneGoal = ZoneGoal,
|
||||
}
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
|
||||
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
||||
@@ -955,8 +941,8 @@ do -- Event Creation
|
||||
local Event = {
|
||||
id = EVENTS.PlayerEnterUnit,
|
||||
time = timer.getTime(),
|
||||
initiator = PlayerUnit:GetDCSObject()
|
||||
}
|
||||
initiator = PlayerUnit:GetDCSObject(),
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
@@ -970,8 +956,8 @@ do -- Event Creation
|
||||
local Event = {
|
||||
id = EVENTS.PlayerEnterAircraft,
|
||||
time = timer.getTime(),
|
||||
initiator = PlayerUnit:GetDCSObject()
|
||||
}
|
||||
initiator = PlayerUnit:GetDCSObject(),
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
@@ -993,14 +979,13 @@ function EVENT:onEvent( Event )
|
||||
return errmsg
|
||||
end
|
||||
|
||||
|
||||
-- Get event meta data.
|
||||
local EventMeta = _EVENTMETA[Event.id]
|
||||
|
||||
-- Check if this is a known event?
|
||||
if EventMeta then
|
||||
|
||||
if self and self.Events and self.Events[Event.id] and self.MissionEnd==false and (Event.initiator~=nil or (Event.initiator==nil and Event.id~=EVENTS.PlayerLeaveUnit)) then
|
||||
if self and self.Events and self.Events[Event.id] and self.MissionEnd == false and (Event.initiator ~= nil or (Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit)) then
|
||||
|
||||
if Event.id and Event.id == EVENTS.MissionEnd then
|
||||
self.MissionEnd = true
|
||||
@@ -1024,9 +1009,9 @@ function EVENT:onEvent( Event )
|
||||
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
|
||||
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
||||
--if Event.IniGroup then
|
||||
Event.IniGroupName = Event.IniDCSGroupName
|
||||
--end
|
||||
-- if Event.IniGroup then
|
||||
Event.IniGroupName = Event.IniDCSGroupName
|
||||
-- end
|
||||
end
|
||||
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
@@ -1036,23 +1021,23 @@ function EVENT:onEvent( Event )
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.STATIC then
|
||||
|
||||
if Event.id==31 then
|
||||
if Event.id == 31 then
|
||||
|
||||
-- Event.initiator is a Static object representing the pilot. But getName() errors due to DCS bug.
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
local ID=Event.initiator.id_
|
||||
Event.IniDCSUnitName = string.format("Ejected Pilot ID %s", tostring(ID))
|
||||
local ID = Event.initiator.id_
|
||||
Event.IniDCSUnitName = string.format( "Ejected Pilot ID %s", tostring( ID ) )
|
||||
Event.IniUnitName = Event.IniDCSUnitName
|
||||
Event.IniCoalition = 0
|
||||
Event.IniCategory = 0
|
||||
Event.IniCategory = 0
|
||||
Event.IniTypeName = "Ejected Pilot"
|
||||
elseif Event.id == 33 then -- ejection seat discarded
|
||||
elseif Event.id == 33 then -- ejection seat discarded
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
local ID=Event.initiator.id_
|
||||
Event.IniDCSUnitName = string.format("Ejection Seat ID %s", tostring(ID))
|
||||
local ID = Event.initiator.id_
|
||||
Event.IniDCSUnitName = string.format( "Ejection Seat ID %s", tostring( ID ) )
|
||||
Event.IniUnitName = Event.IniDCSUnitName
|
||||
Event.IniCoalition = 0
|
||||
Event.IniCategory = 0
|
||||
Event.IniCategory = 0
|
||||
Event.IniTypeName = "Ejection Seat"
|
||||
else
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
@@ -1088,7 +1073,7 @@ function EVENT:onEvent( Event )
|
||||
Event.IniDCSUnit = Event.initiator
|
||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||
Event.IniUnitName = Event.IniDCSUnitName
|
||||
Event.IniUnit = AIRBASE:FindByName(Event.IniDCSUnitName)
|
||||
Event.IniUnit = AIRBASE:FindByName( Event.IniDCSUnitName )
|
||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||
@@ -1109,9 +1094,9 @@ function EVENT:onEvent( Event )
|
||||
if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then
|
||||
Event.TgtDCSGroupName = Event.TgtDCSGroup:getName()
|
||||
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
||||
--if Event.TgtGroup then
|
||||
Event.TgtGroupName = Event.TgtDCSGroupName
|
||||
--end
|
||||
-- if Event.TgtGroup then
|
||||
Event.TgtGroupName = Event.TgtDCSGroupName
|
||||
-- end
|
||||
end
|
||||
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
|
||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||
@@ -1130,18 +1115,18 @@ function EVENT:onEvent( Event )
|
||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||
else
|
||||
Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id))
|
||||
Event.TgtDCSUnitName = string.format( "No target object for Event ID %s", tostring( Event.id ) )
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
Event.TgtUnit = nil
|
||||
Event.TgtCoalition = 0
|
||||
Event.TgtCategory = 0
|
||||
if Event.id == 6 then
|
||||
Event.TgtTypeName = "Ejected Pilot"
|
||||
Event.TgtDCSUnitName = string.format("Ejected Pilot ID %s", tostring(Event.IniDCSUnitName))
|
||||
Event.TgtDCSUnitName = string.format( "Ejected Pilot ID %s", tostring( Event.IniDCSUnitName ) )
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
elseif Event.id == 33 then
|
||||
Event.TgtTypeName = "Ejection Seat"
|
||||
Event.TgtDCSUnitName = string.format("Ejection Seat ID %s", tostring(Event.IniDCSUnitName))
|
||||
Event.TgtDCSUnitName = string.format( "Ejection Seat ID %s", tostring( Event.IniDCSUnitName ) )
|
||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||
else
|
||||
Event.TgtTypeName = "Static"
|
||||
@@ -1167,29 +1152,29 @@ function EVENT:onEvent( Event )
|
||||
Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon:getCoalition()
|
||||
Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon:getDesc().category
|
||||
Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName()
|
||||
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
|
||||
-- Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
|
||||
end
|
||||
|
||||
-- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase.
|
||||
if Event.place then
|
||||
if Event.id==EVENTS.LandingAfterEjection then
|
||||
if Event.id == EVENTS.LandingAfterEjection then
|
||||
-- Place is here the UNIT of which the pilot ejected.
|
||||
--local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :(
|
||||
-- local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :(
|
||||
-- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground.
|
||||
--Event.Place=UNIT:Find(Event.place)
|
||||
-- Event.Place=UNIT:Find(Event.place)
|
||||
else
|
||||
Event.Place=AIRBASE:Find(Event.place)
|
||||
Event.PlaceName=Event.Place:GetName()
|
||||
Event.Place = AIRBASE:Find( Event.place )
|
||||
Event.PlaceName = Event.Place:GetName()
|
||||
end
|
||||
end
|
||||
|
||||
-- Mark points.
|
||||
if Event.idx then
|
||||
Event.MarkID=Event.idx
|
||||
Event.MarkVec3=Event.pos
|
||||
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
||||
Event.MarkText=Event.text
|
||||
Event.MarkCoalition=Event.coalition
|
||||
Event.MarkID = Event.idx
|
||||
Event.MarkVec3 = Event.pos
|
||||
Event.MarkCoordinate = COORDINATE:NewFromVec3( Event.pos )
|
||||
Event.MarkText = Event.text
|
||||
Event.MarkCoalition = Event.coalition
|
||||
Event.MarkGroupID = Event.groupID
|
||||
end
|
||||
|
||||
@@ -1218,9 +1203,9 @@ function EVENT:onEvent( Event )
|
||||
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
|
||||
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
|
||||
|
||||
--if Event.IniObjectCategory ~= Object.Category.STATIC then
|
||||
-- if Event.IniObjectCategory ~= Object.Category.STATIC then
|
||||
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
||||
--end
|
||||
-- end
|
||||
|
||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
||||
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
||||
@@ -1237,8 +1222,8 @@ function EVENT:onEvent( Event )
|
||||
|
||||
local UnitName = EventClass:GetName()
|
||||
|
||||
if ( EventMeta.Side == "I" and UnitName == Event.IniDCSUnitName ) or
|
||||
( EventMeta.Side == "T" and UnitName == Event.TgtDCSUnitName ) then
|
||||
if (EventMeta.Side == "I" and UnitName == Event.IniDCSUnitName) or
|
||||
(EventMeta.Side == "T" and UnitName == Event.TgtDCSUnitName) then
|
||||
|
||||
-- First test if a EventFunction is Set, otherwise search for the default function
|
||||
if EventData.EventFunction then
|
||||
@@ -1247,15 +1232,14 @@ function EVENT:onEvent( Event )
|
||||
self:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
||||
end
|
||||
|
||||
local Result, Value = xpcall(
|
||||
function()
|
||||
return EventData.EventFunction( EventClass, Event )
|
||||
end, ErrorHandler )
|
||||
local Result, Value = xpcall( function()
|
||||
return EventData.EventFunction( EventClass, Event )
|
||||
end, ErrorHandler )
|
||||
|
||||
else
|
||||
|
||||
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
||||
local EventFunction = EventClass[ EventMeta.Event ]
|
||||
local EventFunction = EventClass[EventMeta.Event]
|
||||
if EventFunction and type( EventFunction ) == "function" then
|
||||
|
||||
-- Now call the default event function.
|
||||
@@ -1263,10 +1247,9 @@ function EVENT:onEvent( Event )
|
||||
self:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
||||
end
|
||||
|
||||
local Result, Value = xpcall(
|
||||
function()
|
||||
return EventFunction( EventClass, Event )
|
||||
end, ErrorHandler )
|
||||
local Result, Value = xpcall( function()
|
||||
return EventFunction( EventClass, Event )
|
||||
end, ErrorHandler )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1290,8 +1273,8 @@ function EVENT:onEvent( Event )
|
||||
-- We can get the name of the EventClass, which is now always a GROUP object.
|
||||
local GroupName = EventClass:GetName()
|
||||
|
||||
if ( EventMeta.Side == "I" and GroupName == Event.IniDCSGroupName ) or
|
||||
( EventMeta.Side == "T" and GroupName == Event.TgtDCSGroupName ) then
|
||||
if (EventMeta.Side == "I" and GroupName == Event.IniDCSGroupName) or
|
||||
(EventMeta.Side == "T" and GroupName == Event.TgtDCSGroupName) then
|
||||
|
||||
-- First test if a EventFunction is Set, otherwise search for the default function
|
||||
if EventData.EventFunction then
|
||||
@@ -1300,15 +1283,14 @@ function EVENT:onEvent( Event )
|
||||
self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
||||
end
|
||||
|
||||
local Result, Value = xpcall(
|
||||
function()
|
||||
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||
end, ErrorHandler )
|
||||
local Result, Value = xpcall( function()
|
||||
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||
end, ErrorHandler )
|
||||
|
||||
else
|
||||
|
||||
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
||||
local EventFunction = EventClass[ EventMeta.Event ]
|
||||
local EventFunction = EventClass[EventMeta.Event]
|
||||
if EventFunction and type( EventFunction ) == "function" then
|
||||
|
||||
-- Now call the default event function.
|
||||
@@ -1316,16 +1298,15 @@ function EVENT:onEvent( Event )
|
||||
self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
|
||||
end
|
||||
|
||||
local Result, Value = xpcall(
|
||||
function()
|
||||
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||
end, ErrorHandler )
|
||||
local Result, Value = xpcall( function()
|
||||
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||
end, ErrorHandler )
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
|
||||
--self:RemoveEvent( EventClass, Event.id )
|
||||
-- self:RemoveEvent( EventClass, Event.id )
|
||||
end
|
||||
else
|
||||
|
||||
@@ -1340,14 +1321,13 @@ function EVENT:onEvent( Event )
|
||||
if Event.IniObjectCategory ~= 3 then
|
||||
self:F2( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
||||
end
|
||||
local Result, Value = xpcall(
|
||||
function()
|
||||
return EventData.EventFunction( EventClass, Event )
|
||||
end, ErrorHandler )
|
||||
local Result, Value = xpcall( function()
|
||||
return EventData.EventFunction( EventClass, Event )
|
||||
end, ErrorHandler )
|
||||
else
|
||||
|
||||
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
||||
local EventFunction = EventClass[ EventMeta.Event ]
|
||||
local EventFunction = EventClass[EventMeta.Event]
|
||||
if EventFunction and type( EventFunction ) == "function" then
|
||||
|
||||
-- Now call the default event function.
|
||||
@@ -1355,11 +1335,10 @@ function EVENT:onEvent( Event )
|
||||
self:F2( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
||||
end
|
||||
|
||||
local Result, Value = xpcall(
|
||||
function()
|
||||
local Result, Value = EventFunction( EventClass, Event )
|
||||
return Result, Value
|
||||
end, ErrorHandler )
|
||||
local Result, Value = xpcall( function()
|
||||
local Result, Value = EventFunction( EventClass, Event )
|
||||
return Result, Value
|
||||
end, ErrorHandler )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1383,7 +1362,7 @@ function EVENT:onEvent( Event )
|
||||
self:T( { EventMeta.Text, Event } )
|
||||
end
|
||||
else
|
||||
self:E(string.format("WARNING: Could not get EVENTMETA data for event ID=%d! Is this an unknown/new DCS event?", tostring(Event.id)))
|
||||
self:E( string.format( "WARNING: Could not get EVENTMETA data for event ID=%d! Is this an unknown/new DCS event?", tostring( Event.id ) ) )
|
||||
end
|
||||
|
||||
Event = nil
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
--
|
||||
-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections.
|
||||
--
|
||||
-- ##__Dislaimer:__
|
||||
-- ##__Disclaimer:__
|
||||
-- The FSM class development is based on a finite state machine implementation made by Conroy Kyle.
|
||||
-- The state machine can be found on [github](https://github.com/kyleconroy/lua-state-machine)
|
||||
-- I've reworked this development (taken the concept), and created a **hierarchical state machine** out of it, embedded within the DCS simulator.
|
||||
@@ -69,7 +69,6 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions: **funkyfranky**
|
||||
--
|
||||
@@ -89,7 +88,6 @@ do -- FSM
|
||||
-- @field #string current Current state name.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
--- A Finite State Machine (FSM) models a process flow that transitions between various **States** through triggered **Events**.
|
||||
--
|
||||
-- A FSM can only be in one of a finite number of states.
|
||||
@@ -145,12 +143,12 @@ do -- FSM
|
||||
-- Most of the time, these Event Triggers are used within the Transition Handler methods, so that a workflow is created running through the state machine.
|
||||
--
|
||||
-- As explained above, a FSM supports **Linear State Transitions** and **Hierarchical State Transitions**, and both can be mixed to make a comprehensive FSM implementation.
|
||||
-- The below documentation has a seperate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**.
|
||||
-- The below documentation has a separate chapter explaining both transition modes, taking into account the **Transition Rules**, **Transition Handlers** and **Event Triggers**.
|
||||
--
|
||||
-- ## FSM Linear Transitions
|
||||
--
|
||||
-- Linear Transitions are Transition Rules allowing an FSM to transition from one or multiple possible **From** state(s) towards a **To** state upon a Triggered **Event**.
|
||||
-- The Lineair transition rule evaluation will always be done from the **current state** of the FSM.
|
||||
-- The Linear transition rule evaluation will always be done from the **current state** of the FSM.
|
||||
-- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop.
|
||||
--
|
||||
-- ### FSM Transition Rules
|
||||
@@ -185,7 +183,7 @@ do -- FSM
|
||||
-- * The From states can be **a table of strings**, indicating that the transition rule will be valid **if the current state** of the FSM will be **one of the given From states**.
|
||||
-- * The From state can be a **"*"**, indicating that **the transition rule will always be valid**, regardless of the current state of the FSM.
|
||||
--
|
||||
-- The below code snippet shows how the two last lines can be rewritten and consensed.
|
||||
-- The below code snippet shows how the two last lines can be rewritten and condensed.
|
||||
--
|
||||
-- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" )
|
||||
--
|
||||
@@ -221,7 +219,7 @@ do -- FSM
|
||||
-- * The method **FSM:Event()** triggers an Event that will be processed **synchronously** or **immediately**.
|
||||
-- * The method **FSM:__Event( __seconds__ )** triggers an Event that will be processed **asynchronously** over time, waiting __x seconds__.
|
||||
--
|
||||
-- The destinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time.
|
||||
-- The distinction between these 2 Event Trigger methods are important to understand. An asynchronous call will "log" the Event Trigger to be executed at a later time.
|
||||
-- Processing will just continue. Synchronous Event Trigger methods are useful to change states of the FSM immediately, but may have a larger processing impact.
|
||||
--
|
||||
-- The following example provides a little demonstration on the difference between synchronous and asynchronous Event Triggering.
|
||||
@@ -345,7 +343,6 @@ do -- FSM
|
||||
-- ===
|
||||
--
|
||||
-- @field #FSM
|
||||
--
|
||||
FSM = {
|
||||
ClassName = "FSM",
|
||||
}
|
||||
@@ -379,7 +376,6 @@ do -- FSM
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Sets the start state of the FSM.
|
||||
-- @param #FSM self
|
||||
-- @param #string State A string defining the start state.
|
||||
@@ -388,7 +384,6 @@ do -- FSM
|
||||
self.current = State
|
||||
end
|
||||
|
||||
|
||||
--- Returns the start state of the FSM.
|
||||
-- @param #FSM self
|
||||
-- @return #string A string containing the start state.
|
||||
@@ -416,7 +411,6 @@ do -- FSM
|
||||
self:_eventmap( self.Events, Transition )
|
||||
end
|
||||
|
||||
|
||||
--- Returns a table of the transition rules defined within the FSM.
|
||||
-- @param #FSM self
|
||||
-- @return #table Transitions.
|
||||
@@ -450,7 +444,6 @@ do -- FSM
|
||||
return Process
|
||||
end
|
||||
|
||||
|
||||
--- Returns a table of the SubFSM rules defined within the FSM.
|
||||
-- @param #FSM self
|
||||
-- @return #table Sub processes.
|
||||
@@ -499,7 +492,6 @@ do -- FSM
|
||||
return self._EndStates or {}
|
||||
end
|
||||
|
||||
|
||||
--- Adds a score for the FSM to be achieved.
|
||||
-- @param #FSM self
|
||||
-- @param #string State is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).
|
||||
@@ -563,27 +555,27 @@ do -- FSM
|
||||
|
||||
end
|
||||
|
||||
--- Event map.
|
||||
--- Event map.
|
||||
-- @param #FSM self
|
||||
-- @param #table Events Events.
|
||||
-- @param #table EventStructure Event structure.
|
||||
function FSM:_eventmap( Events, EventStructure )
|
||||
|
||||
local Event = EventStructure.Event
|
||||
local __Event = "__" .. EventStructure.Event
|
||||
local Event = EventStructure.Event
|
||||
local __Event = "__" .. EventStructure.Event
|
||||
|
||||
self[Event] = self[Event] or self:_create_transition(Event)
|
||||
self[__Event] = self[__Event] or self:_delayed_transition(Event)
|
||||
self[Event] = self[Event] or self:_create_transition( Event )
|
||||
self[__Event] = self[__Event] or self:_delayed_transition( Event )
|
||||
|
||||
-- Debug message.
|
||||
self:T2( "Added methods: " .. Event .. ", " .. __Event )
|
||||
-- Debug message.
|
||||
self:T2( "Added methods: " .. Event .. ", " .. __Event )
|
||||
|
||||
Events[Event] = self.Events[Event] or { map = {} }
|
||||
self:_add_to_map( Events[Event].map, EventStructure )
|
||||
Events[Event] = self.Events[Event] or { map = {} }
|
||||
self:_add_to_map( Events[Event].map, EventStructure )
|
||||
|
||||
end
|
||||
|
||||
--- Sub maps.
|
||||
--- Sub maps.
|
||||
-- @param #FSM self
|
||||
-- @param #table subs Subs.
|
||||
-- @param #table sub Sub.
|
||||
@@ -613,7 +605,7 @@ do -- FSM
|
||||
-- @param #string EventName Event name.
|
||||
-- @return Value.
|
||||
function FSM:_call_handler( step, trigger, params, EventName )
|
||||
--env.info(string.format("FF T=%.3f _call_handler step=%s, trigger=%s, event=%s", timer.getTime(), step, trigger, EventName))
|
||||
-- env.info(string.format("FF T=%.3f _call_handler step=%s, trigger=%s, event=%s", timer.getTime(), step, trigger, EventName))
|
||||
|
||||
local handler = step .. trigger
|
||||
|
||||
@@ -644,10 +636,12 @@ do -- FSM
|
||||
return errmsg
|
||||
end
|
||||
|
||||
--return self[handler](self, unpack( params ))
|
||||
-- return self[handler](self, unpack( params ))
|
||||
|
||||
-- Protected call.
|
||||
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
||||
local Result, Value = xpcall( function()
|
||||
return self[handler]( self, unpack( params ) )
|
||||
end, ErrorHandler )
|
||||
return Value
|
||||
end
|
||||
|
||||
@@ -671,17 +665,16 @@ do -- FSM
|
||||
local From = self.current
|
||||
|
||||
-- Parameters.
|
||||
local Params = { From, EventName, To, ... }
|
||||
local Params = { From, EventName, To, ... }
|
||||
|
||||
|
||||
if self["onleave".. From] or
|
||||
self["OnLeave".. From] or
|
||||
self["onbefore".. EventName] or
|
||||
self["OnBefore".. EventName] or
|
||||
self["onafter".. EventName] or
|
||||
self["OnAfter".. EventName] or
|
||||
self["onenter".. To] or
|
||||
self["OnEnter".. To] then
|
||||
if self["onleave" .. From] or
|
||||
self["OnLeave" .. From] or
|
||||
self["onbefore" .. EventName] or
|
||||
self["OnBefore" .. EventName] or
|
||||
self["onafter" .. EventName] or
|
||||
self["OnAfter" .. EventName] or
|
||||
self["onenter" .. To] or
|
||||
self["OnEnter" .. To] then
|
||||
|
||||
if self:_call_handler( "onbefore", EventName, Params, EventName ) == false then
|
||||
self:T( "*** FSM *** Cancel" .. " *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** onbefore" .. EventName )
|
||||
@@ -716,11 +709,11 @@ do -- FSM
|
||||
end
|
||||
|
||||
if ClassName == "FSM_CONTROLLABLE" then
|
||||
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
|
||||
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
|
||||
end
|
||||
|
||||
if ClassName == "FSM_PROCESS" then
|
||||
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
|
||||
self:T( "*** FSM *** Transit *** " .. self.current .. " --> " .. EventName .. " --> " .. To .. " *** Task: " .. self.Task:GetName() .. ", TaskUnit: " .. self.Controllable.ControllableName .. " *** " )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -733,10 +726,10 @@ do -- FSM
|
||||
|
||||
for _, sub in pairs( subtable ) do
|
||||
|
||||
--if sub.nextevent then
|
||||
-- if sub.nextevent then
|
||||
-- self:F2( "nextevent = " .. sub.nextevent )
|
||||
-- self[sub.nextevent]( self )
|
||||
--end
|
||||
-- end
|
||||
|
||||
self:T( "*** FSM *** Sub *** " .. sub.StartEvent )
|
||||
|
||||
@@ -753,11 +746,11 @@ do -- FSM
|
||||
|
||||
self:T( "*** FSM *** End *** " .. Event )
|
||||
|
||||
self:_call_handler("onenter", To, Params, EventName )
|
||||
self:_call_handler("OnEnter", To, Params, EventName )
|
||||
self:_call_handler("onafter", EventName, Params, EventName )
|
||||
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||
self:_call_handler("onstate", "change", Params, EventName )
|
||||
self:_call_handler( "onenter", To, Params, EventName )
|
||||
self:_call_handler( "OnEnter", To, Params, EventName )
|
||||
self:_call_handler( "onafter", EventName, Params, EventName )
|
||||
self:_call_handler( "OnAfter", EventName, Params, EventName )
|
||||
self:_call_handler( "onstate", "change", Params, EventName )
|
||||
|
||||
fsmparent[Event]( fsmparent )
|
||||
|
||||
@@ -766,13 +759,13 @@ do -- FSM
|
||||
|
||||
if execute then
|
||||
|
||||
self:_call_handler("onafter", EventName, Params, EventName )
|
||||
self:_call_handler("OnAfter", EventName, Params, EventName )
|
||||
self:_call_handler( "onafter", EventName, Params, EventName )
|
||||
self:_call_handler( "OnAfter", EventName, Params, EventName )
|
||||
|
||||
self:_call_handler("onenter", To, Params, EventName )
|
||||
self:_call_handler("OnEnter", To, Params, EventName )
|
||||
self:_call_handler( "onenter", To, Params, EventName )
|
||||
self:_call_handler( "OnEnter", To, Params, EventName )
|
||||
|
||||
self:_call_handler("onstate", "change", Params, EventName )
|
||||
self:_call_handler( "onstate", "change", Params, EventName )
|
||||
|
||||
end
|
||||
else
|
||||
@@ -809,16 +802,16 @@ do -- FSM
|
||||
self._EventSchedules[EventName] = CallID
|
||||
|
||||
-- Debug output.
|
||||
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||
self:T2( string.format( "NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring( CallID ) ) )
|
||||
else
|
||||
self:T2(string.format("NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds))
|
||||
self:T2( string.format( "NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds ) )
|
||||
-- reschedule
|
||||
end
|
||||
else
|
||||
|
||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||
|
||||
self:T2(string.format("Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||
self:T2( string.format( "Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring( CallID ) ) )
|
||||
end
|
||||
else
|
||||
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
||||
@@ -835,7 +828,9 @@ do -- FSM
|
||||
-- @param #string EventName Event name.
|
||||
-- @return #function Function.
|
||||
function FSM:_create_transition( EventName )
|
||||
return function( self, ... ) return self._handler( self, EventName , ... ) end
|
||||
return function( self, ... )
|
||||
return self._handler( self, EventName, ... )
|
||||
end
|
||||
end
|
||||
|
||||
--- Go sub.
|
||||
@@ -862,16 +857,16 @@ do -- FSM
|
||||
local FSMParent = self.fsmparent
|
||||
|
||||
if FSMParent and self.endstates[Current] then
|
||||
--self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
|
||||
-- self:T( { state = Current, endstates = self.endstates, endstate = self.endstates[Current] } )
|
||||
FSMParent.current = Current
|
||||
local ParentFrom = FSMParent.current
|
||||
--self:T( { ParentFrom, self.ReturnEvents } )
|
||||
-- self:T( { ParentFrom, self.ReturnEvents } )
|
||||
local Event = self.ReturnEvents[Current]
|
||||
--self:T( { Event } )
|
||||
-- self:T( { Event } )
|
||||
if Event then
|
||||
return FSMParent, Event
|
||||
else
|
||||
--self:T( { "Could not find parent event name for state ", ParentFrom } )
|
||||
-- self:T( { "Could not find parent event name for state ", ParentFrom } )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -883,17 +878,17 @@ do -- FSM
|
||||
-- @param #table Map Map.
|
||||
-- @param #table Event Event table.
|
||||
function FSM:_add_to_map( Map, Event )
|
||||
self:F3( { Map, Event } )
|
||||
self:F3( { Map, Event } )
|
||||
|
||||
if type(Event.From) == 'string' then
|
||||
Map[Event.From] = Event.To
|
||||
if type( Event.From ) == 'string' then
|
||||
Map[Event.From] = Event.To
|
||||
else
|
||||
for _, From in ipairs(Event.From) do
|
||||
Map[From] = Event.To
|
||||
for _, From in ipairs( Event.From ) do
|
||||
Map[From] = Event.To
|
||||
end
|
||||
end
|
||||
|
||||
self:T3( { Map, Event } )
|
||||
self:T3( { Map, Event } )
|
||||
end
|
||||
|
||||
--- Get current state.
|
||||
@@ -922,7 +917,7 @@ do -- FSM
|
||||
-- @param #FSM self
|
||||
-- @param #string State State name.
|
||||
-- @param #boolean If true, FSM is in this state.
|
||||
function FSM:is(state)
|
||||
function FSM:is( state )
|
||||
return self.current == state
|
||||
end
|
||||
|
||||
@@ -931,11 +926,11 @@ do -- FSM
|
||||
-- @param #string e Event name.
|
||||
-- @return #boolean If true, FSM can do the event.
|
||||
-- @return #string To state.
|
||||
function FSM:can(e)
|
||||
function FSM:can( e )
|
||||
|
||||
local Event = self.Events[e]
|
||||
|
||||
--self:F3( { self.current, Event } )
|
||||
-- self:F3( { self.current, Event } )
|
||||
|
||||
local To = Event and Event.map[self.current] or Event.map['*']
|
||||
|
||||
@@ -946,8 +941,8 @@ do -- FSM
|
||||
-- @param #FSM self
|
||||
-- @param #string e Event name.
|
||||
-- @return #boolean If true, FSM cannot do the event.
|
||||
function FSM:cannot(e)
|
||||
return not self:can(e)
|
||||
function FSM:cannot( e )
|
||||
return not self:can( e )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1036,7 +1031,7 @@ do -- FSM_CONTROLLABLE
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function FSM_CONTROLLABLE:OnAfterStop(Controllable,From,Event,To)
|
||||
function FSM_CONTROLLABLE:OnAfterStop( Controllable, From, Event, To )
|
||||
|
||||
-- Clear all pending schedules
|
||||
self.CallScheduler:Clear()
|
||||
@@ -1047,7 +1042,7 @@ do -- FSM_CONTROLLABLE
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE FSMControllable
|
||||
-- @return #FSM_CONTROLLABLE
|
||||
function FSM_CONTROLLABLE:SetControllable( FSMControllable )
|
||||
--self:F( FSMControllable:GetName() )
|
||||
-- self:F( FSMControllable:GetName() )
|
||||
self.Controllable = FSMControllable
|
||||
end
|
||||
|
||||
@@ -1075,9 +1070,11 @@ do -- FSM_CONTROLLABLE
|
||||
if self[handler] then
|
||||
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** TaskUnit: " .. self.Controllable:GetName() )
|
||||
self._EventSchedules[EventName] = nil
|
||||
local Result, Value = xpcall( function() return self[handler]( self, self.Controllable, unpack( params ) ) end, ErrorHandler )
|
||||
local Result, Value = xpcall( function()
|
||||
return self[handler]( self, self.Controllable, unpack( params ) )
|
||||
end, ErrorHandler )
|
||||
return Value
|
||||
--return self[handler]( self, self.Controllable, unpack( params ) )
|
||||
-- return self[handler]( self, self.Controllable, unpack( params ) )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1089,16 +1086,13 @@ do -- FSM_PROCESS
|
||||
-- @field Tasking.Task#TASK Task
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
|
||||
--- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #FSM_PROCESS FSM_PROCESS
|
||||
--
|
||||
FSM_PROCESS = {
|
||||
ClassName = "FSM_PROCESS",
|
||||
}
|
||||
FSM_PROCESS = { ClassName = "FSM_PROCESS" }
|
||||
|
||||
--- Creates a new FSM_PROCESS object.
|
||||
-- @param #FSM_PROCESS self
|
||||
@@ -1107,7 +1101,7 @@ do -- FSM_PROCESS
|
||||
|
||||
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS
|
||||
|
||||
--self:F( Controllable )
|
||||
-- self:F( Controllable )
|
||||
|
||||
self:Assign( Controllable, Task )
|
||||
|
||||
@@ -1139,10 +1133,12 @@ do -- FSM_PROCESS
|
||||
self._EventSchedules[EventName] = nil
|
||||
local Result, Value
|
||||
if self.Controllable and self.Controllable:IsAlive() == true then
|
||||
Result, Value = xpcall( function() return self[handler]( self, self.Controllable, self.Task, unpack( params ) ) end, ErrorHandler )
|
||||
Result, Value = xpcall( function()
|
||||
return self[handler]( self, self.Controllable, self.Task, unpack( params ) )
|
||||
end, ErrorHandler )
|
||||
end
|
||||
return Value
|
||||
--return self[handler]( self, self.Controllable, unpack( params ) )
|
||||
-- return self[handler]( self, self.Controllable, unpack( params ) )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1152,7 +1148,6 @@ do -- FSM_PROCESS
|
||||
function FSM_PROCESS:Copy( Controllable, Task )
|
||||
self:T( { self:GetClassNameAndID() } )
|
||||
|
||||
|
||||
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
|
||||
|
||||
NewFsm:Assign( Controllable, Task )
|
||||
@@ -1170,7 +1165,7 @@ do -- FSM_PROCESS
|
||||
|
||||
-- Copy Processes
|
||||
for ProcessID, Process in pairs( self:GetProcesses() ) do
|
||||
--self:E( { Process:GetName() } )
|
||||
-- self:E( { Process:GetName() } )
|
||||
local FsmProcess = NewFsm:AddProcess( Process.From, Process.Event, Process.fsm:Copy( Controllable, Task ), Process.ReturnEvents )
|
||||
end
|
||||
|
||||
@@ -1244,7 +1239,7 @@ do -- FSM_PROCESS
|
||||
return self:GetTask():GetMission():GetCommandCenter()
|
||||
end
|
||||
|
||||
-- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP.
|
||||
-- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP.
|
||||
|
||||
--- Send a message of the @{Task} to the Group of the Unit.
|
||||
-- @param #FSM_PROCESS self
|
||||
@@ -1263,32 +1258,29 @@ do -- FSM_PROCESS
|
||||
CC:MessageToGroup( Message, TaskGroup )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Assign the process to a @{Wrapper.Unit} and activate the process.
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Task.Tasking#TASK Task
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @return #FSM_PROCESS self
|
||||
function FSM_PROCESS:Assign( ProcessUnit, Task )
|
||||
--self:T( { Task:GetName(), ProcessUnit:GetName() } )
|
||||
-- self:T( { Task:GetName(), ProcessUnit:GetName() } )
|
||||
|
||||
self:SetControllable( ProcessUnit )
|
||||
self:SetTask( Task )
|
||||
|
||||
--self.ProcessGroup = ProcessUnit:GetGroup()
|
||||
-- self.ProcessGroup = ProcessUnit:GetGroup()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-- function FSM_PROCESS:onenterAssigned( ProcessUnit, Task, From, Event, To )
|
||||
--
|
||||
-- if From( "Planned" ) then
|
||||
-- self:T( "*** FSM *** Assign *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
|
||||
-- self.Task:Assign()
|
||||
-- end
|
||||
-- end
|
||||
-- function FSM_PROCESS:onenterAssigned( ProcessUnit, Task, From, Event, To )
|
||||
--
|
||||
-- if From( "Planned" ) then
|
||||
-- self:T( "*** FSM *** Assign *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
|
||||
-- self.Task:Assign()
|
||||
-- end
|
||||
-- end
|
||||
|
||||
function FSM_PROCESS:onenterFailed( ProcessUnit, Task, From, Event, To )
|
||||
self:T( "*** FSM *** Failed *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
|
||||
@@ -1296,7 +1288,6 @@ do -- FSM_PROCESS
|
||||
self.Task:Fail()
|
||||
end
|
||||
|
||||
|
||||
--- StateMachine callback function for a FSM_PROCESS
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
@@ -1309,10 +1300,10 @@ do -- FSM_PROCESS
|
||||
self:T( "*** FSM *** Change *** " .. Task:GetName() .. "/" .. ProcessUnit:GetName() .. " *** " .. From .. " --> " .. Event .. " --> " .. To )
|
||||
end
|
||||
|
||||
-- if self:IsTrace() then
|
||||
-- MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll()
|
||||
-- self:F2( { Scores = self._Scores, To = To } )
|
||||
-- end
|
||||
-- if self:IsTrace() then
|
||||
-- MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll()
|
||||
-- self:F2( { Scores = self._Scores, To = To } )
|
||||
-- end
|
||||
|
||||
-- TODO: This needs to be reworked with a callback functions allocated within Task, and set within the mission script from the Task Objects...
|
||||
if self._Scores[To] then
|
||||
@@ -1374,8 +1365,10 @@ do -- FSM_TASK
|
||||
if self[handler] then
|
||||
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] .. " *** Task: " .. self.TaskName )
|
||||
self._EventSchedules[EventName] = nil
|
||||
--return self[handler]( self, unpack( params ) )
|
||||
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
|
||||
-- return self[handler]( self, unpack( params ) )
|
||||
local Result, Value = xpcall( function()
|
||||
return self[handler]( self, unpack( params ) )
|
||||
end, ErrorHandler )
|
||||
return Value
|
||||
end
|
||||
end
|
||||
@@ -1389,14 +1382,12 @@ do -- FSM_SET
|
||||
-- @field Core.Set#SET_BASE Set
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
--- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
||||
-- for multiple objects or the position of the state machine in the process.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- @field #FSM_SET FSM_SET
|
||||
--
|
||||
FSM_SET = {
|
||||
ClassName = "FSM_SET",
|
||||
}
|
||||
@@ -1434,8 +1425,8 @@ do -- FSM_SET
|
||||
return self.Controllable
|
||||
end
|
||||
|
||||
function FSM_SET:_call_handler( step, trigger, params, EventName )
|
||||
local handler = step .. trigger
|
||||
function FSM_SET:_call_handler( step, trigger, params, EventName )
|
||||
local handler = step .. trigger
|
||||
if self[handler] then
|
||||
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] )
|
||||
self._EventSchedules[EventName] = nil
|
||||
|
||||
@@ -22,13 +22,11 @@
|
||||
-- @module Core.Goal
|
||||
-- @image Core_Goal.JPG
|
||||
|
||||
|
||||
do -- Goal
|
||||
|
||||
--- @type GOAL
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
--- Models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- # 1. GOAL constructor
|
||||
@@ -105,9 +103,8 @@ do -- Goal
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
|
||||
self:SetStartState( "Pending" )
|
||||
self:AddTransition( "*", "Achieved", "Achieved" )
|
||||
self:AddTransition( "*", "Achieved", "Achieved" )
|
||||
|
||||
--- Achieved Handler OnBefore for GOAL
|
||||
-- @function [parent=#GOAL] OnBeforeAchieved
|
||||
@@ -138,25 +135,22 @@ do -- Goal
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Add a new contribution by a player.
|
||||
-- @param #GOAL self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
function GOAL:AddPlayerContribution( PlayerName )
|
||||
self:F({PlayerName})
|
||||
self:F( { PlayerName } )
|
||||
self.Players[PlayerName] = self.Players[PlayerName] or 0
|
||||
self.Players[PlayerName] = self.Players[PlayerName] + 1
|
||||
self.TotalContributions = self.TotalContributions + 1
|
||||
end
|
||||
|
||||
|
||||
--- @param #GOAL self
|
||||
-- @param #number Player contribution.
|
||||
function GOAL:GetPlayerContribution( PlayerName )
|
||||
return self.Players[PlayerName] or 0
|
||||
end
|
||||
|
||||
|
||||
--- Get the players who contributed to achieve the goal.
|
||||
-- The result is a list of players, sorted by the name of the players.
|
||||
-- @param #GOAL self
|
||||
@@ -165,7 +159,6 @@ do -- Goal
|
||||
return self.Players or {}
|
||||
end
|
||||
|
||||
|
||||
--- Gets the total contributions that happened to achieve the goal.
|
||||
-- The result is a number.
|
||||
-- @param #GOAL self
|
||||
@@ -174,8 +167,6 @@ do -- Goal
|
||||
return self.TotalContributions or 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Validates if the goal is achieved.
|
||||
-- @param #GOAL self
|
||||
-- @return #boolean true if the goal is achieved.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
-- * Only create or delete menus when required, and keep existing menus persistent.
|
||||
-- * Update menu structures.
|
||||
-- * Refresh menu structures intelligently, based on a time stamp of updates.
|
||||
-- - Delete obscolete menus.
|
||||
-- - Delete obsolete menus.
|
||||
-- - Create new one where required.
|
||||
-- - Don't touch the existing ones.
|
||||
-- * Provide a variable amount of parameters to menus.
|
||||
@@ -23,7 +23,7 @@
|
||||
-- * Provide a great tool to manage menus in your code.
|
||||
--
|
||||
-- DCS Menus can be managed using the MENU classes.
|
||||
-- The advantage of using MENU classes is that it hides the complexity of dealing with menu management in more advanced scanerios where you need to
|
||||
-- The advantage of using MENU classes is that it hides the complexity of dealing with menu management in more advanced scenarios where you need to
|
||||
-- set menus and later remove them, and later set them again. You'll find while using use normal DCS scripting functions, that setting and removing
|
||||
-- menus is not a easy feat if you have complex menu hierarchies defined.
|
||||
-- Using the MOOSE menu classes, the removal and refreshing of menus are nicely being handled within these classes, and becomes much more easy.
|
||||
@@ -53,7 +53,6 @@
|
||||
-- @module Core.Menu
|
||||
-- @image Core_Menu.JPG
|
||||
|
||||
|
||||
MENU_INDEX = {}
|
||||
MENU_INDEX.MenuMission = {}
|
||||
MENU_INDEX.MenuMission.Menus = {}
|
||||
@@ -64,8 +63,6 @@ MENU_INDEX.Coalition[coalition.side.RED] = {}
|
||||
MENU_INDEX.Coalition[coalition.side.RED].Menus = {}
|
||||
MENU_INDEX.Group = {}
|
||||
|
||||
|
||||
|
||||
function MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||
|
||||
local Path = ParentMenu and "@" .. table.concat( ParentMenu.MenuPath or {}, "@" ) or ""
|
||||
@@ -98,29 +95,25 @@ function MENU_INDEX:ParentPath( ParentMenu, MenuText )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function MENU_INDEX:PrepareMission()
|
||||
self.MenuMission.Menus = self.MenuMission.Menus or {}
|
||||
self.MenuMission.Menus = self.MenuMission.Menus or {}
|
||||
end
|
||||
|
||||
|
||||
function MENU_INDEX:PrepareCoalition( CoalitionSide )
|
||||
self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {}
|
||||
self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {}
|
||||
self.Coalition[CoalitionSide] = self.Coalition[CoalitionSide] or {}
|
||||
self.Coalition[CoalitionSide].Menus = self.Coalition[CoalitionSide].Menus or {}
|
||||
end
|
||||
|
||||
---
|
||||
-- @param Wrapper.Group#GROUP Group
|
||||
function MENU_INDEX:PrepareGroup( Group )
|
||||
if Group and Group:IsAlive() ~= nil then -- something was changed here!
|
||||
if Group and Group:IsAlive() ~= nil then -- something was changed here!
|
||||
local GroupName = Group:GetName()
|
||||
self.Group[GroupName] = self.Group[GroupName] or {}
|
||||
self.Group[GroupName].Menus = self.Group[GroupName].Menus or {}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function MENU_INDEX:HasMissionMenu( Path )
|
||||
|
||||
return self.MenuMission.Menus[Path]
|
||||
@@ -136,8 +129,6 @@ function MENU_INDEX:ClearMissionMenu( Path )
|
||||
self.MenuMission.Menus[Path] = nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
function MENU_INDEX:HasCoalitionMenu( Coalition, Path )
|
||||
|
||||
return self.Coalition[Coalition].Menus[Path]
|
||||
@@ -153,8 +144,6 @@ function MENU_INDEX:ClearCoalitionMenu( Coalition, Path )
|
||||
self.Coalition[Coalition].Menus[Path] = nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
function MENU_INDEX:HasGroupMenu( Group, Path )
|
||||
if Group and Group:IsAlive() then
|
||||
local MenuGroupName = Group:GetName()
|
||||
@@ -166,7 +155,7 @@ end
|
||||
function MENU_INDEX:SetGroupMenu( Group, Path, Menu )
|
||||
|
||||
local MenuGroupName = Group:GetName()
|
||||
Group:F({MenuGroupName=MenuGroupName,Path=Path})
|
||||
Group:F( { MenuGroupName = MenuGroupName, Path = Path } )
|
||||
self.Group[MenuGroupName].Menus[Path] = Menu
|
||||
end
|
||||
|
||||
@@ -178,36 +167,29 @@ end
|
||||
|
||||
function MENU_INDEX:Refresh( Group )
|
||||
|
||||
for MenuID, Menu in pairs( self.MenuMission.Menus ) do
|
||||
Menu:Refresh()
|
||||
end
|
||||
for MenuID, Menu in pairs( self.MenuMission.Menus ) do
|
||||
Menu:Refresh()
|
||||
end
|
||||
|
||||
for MenuID, Menu in pairs( self.Coalition[coalition.side.BLUE].Menus ) do
|
||||
Menu:Refresh()
|
||||
end
|
||||
for MenuID, Menu in pairs( self.Coalition[coalition.side.BLUE].Menus ) do
|
||||
Menu:Refresh()
|
||||
end
|
||||
|
||||
for MenuID, Menu in pairs( self.Coalition[coalition.side.RED].Menus ) do
|
||||
Menu:Refresh()
|
||||
end
|
||||
for MenuID, Menu in pairs( self.Coalition[coalition.side.RED].Menus ) do
|
||||
Menu:Refresh()
|
||||
end
|
||||
|
||||
local GroupName = Group:GetName()
|
||||
for MenuID, Menu in pairs( self.Group[GroupName].Menus ) do
|
||||
Menu:Refresh()
|
||||
end
|
||||
local GroupName = Group:GetName()
|
||||
for MenuID, Menu in pairs( self.Group[GroupName].Menus ) do
|
||||
Menu:Refresh()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
do -- MENU_BASE
|
||||
|
||||
--- @type MENU_BASE
|
||||
-- @extends Base#BASE
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Defines the main MENU class where other MENU classes are derived from.
|
||||
-- This is an abstract class, so don't use it.
|
||||
@@ -216,10 +198,10 @@ do -- MENU_BASE
|
||||
ClassName = "MENU_BASE",
|
||||
MenuPath = nil,
|
||||
MenuText = "",
|
||||
MenuParentPath = nil
|
||||
MenuParentPath = nil,
|
||||
}
|
||||
|
||||
--- Consructor
|
||||
--- Constructor
|
||||
-- @param #MENU_BASE
|
||||
-- @return #MENU_BASE
|
||||
function MENU_BASE:New( MenuText, ParentMenu )
|
||||
@@ -229,13 +211,13 @@ do -- MENU_BASE
|
||||
MenuParentPath = ParentMenu.MenuPath
|
||||
end
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
|
||||
self.MenuPath = nil
|
||||
self.MenuText = MenuText
|
||||
self.ParentMenu = ParentMenu
|
||||
self.MenuParentPath = MenuParentPath
|
||||
self.Path = ( self.ParentMenu and "@" .. table.concat( self.MenuParentPath or {}, "@" ) or "" ) .. "@" .. self.MenuText
|
||||
self.MenuPath = nil
|
||||
self.MenuText = MenuText
|
||||
self.ParentMenu = ParentMenu
|
||||
self.MenuParentPath = MenuParentPath
|
||||
self.Path = (self.ParentMenu and "@" .. table.concat( self.MenuParentPath or {}, "@" ) or "") .. "@" .. self.MenuText
|
||||
self.Menus = {}
|
||||
self.MenuCount = 0
|
||||
self.MenuStamp = timer.getTime()
|
||||
@@ -246,7 +228,7 @@ do -- MENU_BASE
|
||||
self.ParentMenu.Menus[MenuText] = self
|
||||
end
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
function MENU_BASE:SetParentMenu( MenuText, Menu )
|
||||
@@ -262,7 +244,7 @@ do -- MENU_BASE
|
||||
self.ParentMenu.Menus[MenuText] = nil
|
||||
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1
|
||||
if self.ParentMenu.MenuCount == 0 then
|
||||
--self.ParentMenu:Remove()
|
||||
-- self.ParentMenu:Remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -272,12 +254,11 @@ do -- MENU_BASE
|
||||
-- @param #boolean RemoveParent If true, the parent menu is automatically removed when this menu is the last child menu of that parent @{Menu}.
|
||||
-- @return #MENU_BASE
|
||||
function MENU_BASE:SetRemoveParent( RemoveParent )
|
||||
--self:F( { RemoveParent } )
|
||||
-- self:F( { RemoveParent } )
|
||||
self.MenuRemoveParent = RemoveParent
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Gets a @{Menu} from a parent @{Menu}
|
||||
-- @param #MENU_BASE self
|
||||
-- @param #string MenuText The text of the child menu.
|
||||
@@ -295,7 +276,6 @@ do -- MENU_BASE
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Gets a menu stamp for later prevention of menu removal.
|
||||
-- @param #MENU_BASE self
|
||||
-- @return MenuStamp
|
||||
@@ -303,7 +283,6 @@ do -- MENU_BASE
|
||||
return timer.getTime()
|
||||
end
|
||||
|
||||
|
||||
--- Sets a time stamp for later prevention of menu removal.
|
||||
-- @param #MENU_BASE self
|
||||
-- @param MenuStamp
|
||||
@@ -346,7 +325,7 @@ do -- MENU_COMMAND_BASE
|
||||
-- @return #MENU_COMMAND_BASE
|
||||
function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments )
|
||||
|
||||
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE
|
||||
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE
|
||||
|
||||
-- When a menu function goes into error, DCS displays an obscure menu message.
|
||||
-- This error handler catches the menu error and displays the full call stack.
|
||||
@@ -367,7 +346,7 @@ do -- MENU_COMMAND_BASE
|
||||
local Status, Result = xpcall( MenuFunction, ErrorHandler )
|
||||
end
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- This sets the new command function of a menu,
|
||||
@@ -394,7 +373,6 @@ do -- MENU_COMMAND_BASE
|
||||
|
||||
end
|
||||
|
||||
|
||||
do -- MENU_MISSION
|
||||
|
||||
--- @type MENU_MISSION
|
||||
@@ -406,13 +384,13 @@ do -- MENU_MISSION
|
||||
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}.
|
||||
-- @field #MENU_MISSION
|
||||
MENU_MISSION = {
|
||||
ClassName = "MENU_MISSION"
|
||||
ClassName = "MENU_MISSION",
|
||||
}
|
||||
|
||||
--- MENU_MISSION constructor. Creates a new MENU_MISSION object and creates the menu for a complete mission file.
|
||||
-- @param #MENU_MISSION self
|
||||
-- @param #string MenuText The text for the menu.
|
||||
-- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other).
|
||||
-- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the parent menu of DCS world (under F10 other).
|
||||
-- @return #MENU_MISSION
|
||||
function MENU_MISSION:New( MenuText, ParentMenu )
|
||||
|
||||
@@ -470,7 +448,7 @@ do -- MENU_MISSION
|
||||
if MissionMenu == self then
|
||||
self:RemoveSubMenus()
|
||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
|
||||
self:F( { Text = self.MenuText, Path = self.MenuPath } )
|
||||
if self.MenuPath ~= nil then
|
||||
missionCommands.removeItem( self.MenuPath )
|
||||
@@ -487,8 +465,6 @@ do -- MENU_MISSION
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
do -- MENU_MISSION_COMMAND
|
||||
@@ -503,7 +479,7 @@ do -- MENU_MISSION_COMMAND
|
||||
--
|
||||
-- @field #MENU_MISSION_COMMAND
|
||||
MENU_MISSION_COMMAND = {
|
||||
ClassName = "MENU_MISSION_COMMAND"
|
||||
ClassName = "MENU_MISSION_COMMAND",
|
||||
}
|
||||
|
||||
--- MENU_MISSION constructor. Creates a new radio command item for a complete mission file, which can invoke a function with parameters.
|
||||
@@ -556,7 +532,7 @@ do -- MENU_MISSION_COMMAND
|
||||
|
||||
if MissionMenu == self then
|
||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
|
||||
self:F( { Text = self.MenuText, Path = self.MenuPath } )
|
||||
if self.MenuPath ~= nil then
|
||||
missionCommands.removeItem( self.MenuPath )
|
||||
@@ -575,8 +551,6 @@ do -- MENU_MISSION_COMMAND
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
do -- MENU_COALITION
|
||||
|
||||
--- @type MENU_COALITION
|
||||
@@ -627,14 +601,14 @@ do -- MENU_COALITION
|
||||
--
|
||||
-- @field #MENU_COALITION
|
||||
MENU_COALITION = {
|
||||
ClassName = "MENU_COALITION"
|
||||
ClassName = "MENU_COALITION",
|
||||
}
|
||||
|
||||
--- MENU_COALITION constructor. Creates a new MENU_COALITION object and creates the menu for a complete coalition.
|
||||
-- @param #MENU_COALITION self
|
||||
-- @param DCS#coalition.side Coalition The coalition owning the menu.
|
||||
-- @param #string MenuText The text for the menu.
|
||||
-- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the perent menu of DCS world (under F10 other).
|
||||
-- @param #table ParentMenu The parent menu. This parameter can be ignored if you want the menu to be located at the parent menu of DCS world (under F10 other).
|
||||
-- @return #MENU_COALITION self
|
||||
function MENU_COALITION:New( Coalition, MenuText, ParentMenu )
|
||||
|
||||
@@ -693,7 +667,7 @@ do -- MENU_COALITION
|
||||
if CoalitionMenu == self then
|
||||
self:RemoveSubMenus()
|
||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
|
||||
self:F( { Coalition = self.Coalition, Text = self.MenuText, Path = self.MenuPath } )
|
||||
if self.MenuPath ~= nil then
|
||||
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
|
||||
@@ -712,8 +686,6 @@ do -- MENU_COALITION
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
do -- MENU_COALITION_COMMAND
|
||||
|
||||
--- @type MENU_COALITION_COMMAND
|
||||
@@ -726,7 +698,7 @@ do -- MENU_COALITION_COMMAND
|
||||
--
|
||||
-- @field #MENU_COALITION_COMMAND
|
||||
MENU_COALITION_COMMAND = {
|
||||
ClassName = "MENU_COALITION_COMMAND"
|
||||
ClassName = "MENU_COALITION_COMMAND",
|
||||
}
|
||||
|
||||
--- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters.
|
||||
@@ -760,7 +732,6 @@ do -- MENU_COALITION_COMMAND
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Refreshes a radio item for a coalition
|
||||
-- @param #MENU_COALITION_COMMAND self
|
||||
-- @return #MENU_COALITION_COMMAND
|
||||
@@ -784,7 +755,7 @@ do -- MENU_COALITION_COMMAND
|
||||
|
||||
if CoalitionMenu == self then
|
||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
|
||||
self:F( { Coalition = self.Coalition, Text = self.MenuText, Path = self.MenuPath } )
|
||||
if self.MenuPath ~= nil then
|
||||
missionCommands.removeItemForCoalition( self.Coalition, self.MenuPath )
|
||||
@@ -803,7 +774,6 @@ do -- MENU_COALITION_COMMAND
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- MENU_GROUP
|
||||
|
||||
do
|
||||
@@ -817,7 +787,6 @@ do
|
||||
--- @type MENU_GROUP
|
||||
-- @extends Core.Menu#MENU_BASE
|
||||
|
||||
|
||||
--- Manages the main menus for @{Wrapper.Group}s.
|
||||
--
|
||||
-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference.
|
||||
@@ -875,7 +844,7 @@ do
|
||||
--
|
||||
-- @field #MENU_GROUP
|
||||
MENU_GROUP = {
|
||||
ClassName = "MENU_GROUP"
|
||||
ClassName = "MENU_GROUP",
|
||||
}
|
||||
|
||||
--- MENU_GROUP constructor. Creates a new radio menu item for a group.
|
||||
@@ -938,7 +907,6 @@ do
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Removes the main menu and sub menus recursively of this MENU_GROUP.
|
||||
-- @param #MENU_GROUP self
|
||||
-- @param MenuStamp
|
||||
@@ -953,7 +921,7 @@ do
|
||||
if GroupMenu == self then
|
||||
self:RemoveSubMenus( MenuStamp, MenuTag )
|
||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
|
||||
if self.MenuPath ~= nil then
|
||||
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
|
||||
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||
@@ -971,7 +939,6 @@ do
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @type MENU_GROUP_COMMAND
|
||||
-- @extends Core.Menu#MENU_COMMAND_BASE
|
||||
|
||||
@@ -981,7 +948,7 @@ do
|
||||
--
|
||||
-- @field #MENU_GROUP_COMMAND
|
||||
MENU_GROUP_COMMAND = {
|
||||
ClassName = "MENU_GROUP_COMMAND"
|
||||
ClassName = "MENU_GROUP_COMMAND",
|
||||
}
|
||||
|
||||
--- Creates a new radio command item for a group
|
||||
@@ -1043,9 +1010,9 @@ do
|
||||
|
||||
if GroupMenu == self then
|
||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
|
||||
if self.MenuPath ~= nil then
|
||||
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
|
||||
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
|
||||
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||
end
|
||||
MENU_INDEX:ClearGroupMenu( self.Group, Path )
|
||||
@@ -1069,7 +1036,6 @@ do
|
||||
--- @type MENU_GROUP_DELAYED
|
||||
-- @extends Core.Menu#MENU_BASE
|
||||
|
||||
|
||||
--- The MENU_GROUP_DELAYED class manages the main menus for groups.
|
||||
-- You can add menus with the @{#MENU_GROUP.New} method, which constructs a MENU_GROUP object and returns you the object reference.
|
||||
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_GROUP.Remove}.
|
||||
@@ -1079,7 +1045,7 @@ do
|
||||
--
|
||||
-- @field #MENU_GROUP_DELAYED
|
||||
MENU_GROUP_DELAYED = {
|
||||
ClassName = "MENU_GROUP_DELAYED"
|
||||
ClassName = "MENU_GROUP_DELAYED",
|
||||
}
|
||||
|
||||
--- MENU_GROUP_DELAYED constructor. Creates a new radio menu item for a group.
|
||||
@@ -1116,7 +1082,6 @@ do
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Refreshes a new radio item for a group and submenus
|
||||
-- @param #MENU_GROUP_DELAYED self
|
||||
-- @return #MENU_GROUP_DELAYED
|
||||
@@ -1135,7 +1100,6 @@ do
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Refreshes a new radio item for a group and submenus
|
||||
-- @param #MENU_GROUP_DELAYED self
|
||||
-- @return #MENU_GROUP_DELAYED
|
||||
@@ -1167,7 +1131,6 @@ do
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Removes the main menu and sub menus recursively of this MENU_GROUP.
|
||||
-- @param #MENU_GROUP_DELAYED self
|
||||
-- @param MenuStamp
|
||||
@@ -1182,7 +1145,7 @@ do
|
||||
if GroupMenu == self then
|
||||
self:RemoveSubMenus( MenuStamp, MenuTag )
|
||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
|
||||
if self.MenuPath ~= nil then
|
||||
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
|
||||
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||
@@ -1200,7 +1163,6 @@ do
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @type MENU_GROUP_COMMAND_DELAYED
|
||||
-- @extends Core.Menu#MENU_COMMAND_BASE
|
||||
|
||||
@@ -1211,7 +1173,7 @@ do
|
||||
--
|
||||
-- @field #MENU_GROUP_COMMAND_DELAYED
|
||||
MENU_GROUP_COMMAND_DELAYED = {
|
||||
ClassName = "MENU_GROUP_COMMAND_DELAYED"
|
||||
ClassName = "MENU_GROUP_COMMAND_DELAYED",
|
||||
}
|
||||
|
||||
--- Creates a new radio command item for a group
|
||||
@@ -1292,7 +1254,7 @@ do
|
||||
|
||||
if GroupMenu == self then
|
||||
if not MenuStamp or self.MenuStamp ~= MenuStamp then
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if (not MenuTag) or (MenuTag and self.MenuTag and MenuTag == self.MenuTag) then
|
||||
if self.MenuPath ~= nil then
|
||||
self:F( { Group = self.GroupID, Text = self.MenuText, Path = self.MenuPath } )
|
||||
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
--
|
||||
-- @field #MESSAGE
|
||||
MESSAGE = {
|
||||
ClassName = "MESSAGE",
|
||||
MessageCategory = 0,
|
||||
MessageID = 0,
|
||||
ClassName = "MESSAGE",
|
||||
MessageCategory = 0,
|
||||
MessageID = 0,
|
||||
}
|
||||
|
||||
--- Message Types
|
||||
@@ -68,10 +68,9 @@ MESSAGE.Type = {
|
||||
Information = "Information",
|
||||
Briefing = "Briefing Report",
|
||||
Overview = "Overview Report",
|
||||
Detailed = "Detailed Report"
|
||||
Detailed = "Detailed Report",
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
||||
-- @param self
|
||||
-- @param #string MessageText is the text of the Message.
|
||||
@@ -80,25 +79,26 @@ MESSAGE.Type = {
|
||||
-- @param #boolean ClearScreen (optional) Clear all previous messages if true.
|
||||
-- @return #MESSAGE
|
||||
-- @usage
|
||||
-- -- Create a series of new Messages.
|
||||
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
|
||||
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
|
||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
|
||||
--
|
||||
-- -- Create a series of new Messages.
|
||||
-- -- MessageAll is meant to be sent to all players, for 25 seconds, and is classified as "Score".
|
||||
-- -- MessageRED is meant to be sent to the RED players only, for 10 seconds, and is classified as "End of Mission", with ID "Win".
|
||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||
-- -- MessageClient1 is meant to be sent to a Client, for 25 seconds, and is classified as "Score", with ID "Score".
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", 25, "End of Mission" )
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", 25, "Penalty" )
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", 25, "Score" )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", 25, "Score")
|
||||
--
|
||||
function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen )
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F( { MessageText, MessageDuration, MessageCategory } )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F( { MessageText, MessageDuration, MessageCategory } )
|
||||
|
||||
self.MessageType = nil
|
||||
|
||||
-- When no MessageCategory is given, we don't show it as a title...
|
||||
if MessageCategory and MessageCategory ~= "" then
|
||||
if MessageCategory:sub(-1) ~= "\n" then
|
||||
if MessageCategory and MessageCategory ~= "" then
|
||||
if MessageCategory:sub( -1 ) ~= "\n" then
|
||||
self.MessageCategory = MessageCategory .. ": "
|
||||
else
|
||||
self.MessageCategory = MessageCategory:sub( 1, -2 ) .. ":\n"
|
||||
@@ -107,23 +107,22 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory, ClearScreen
|
||||
self.MessageCategory = ""
|
||||
end
|
||||
|
||||
self.ClearScreen=false
|
||||
if ClearScreen~=nil then
|
||||
self.ClearScreen=ClearScreen
|
||||
self.ClearScreen = false
|
||||
if ClearScreen ~= nil then
|
||||
self.ClearScreen = ClearScreen
|
||||
end
|
||||
|
||||
self.MessageDuration = MessageDuration or 5
|
||||
self.MessageTime = timer.getTime()
|
||||
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
|
||||
self.MessageDuration = MessageDuration or 5
|
||||
self.MessageTime = timer.getTime()
|
||||
self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
|
||||
|
||||
self.MessageSent = false
|
||||
self.MessageGroup = false
|
||||
self.MessageCoalition = false
|
||||
self.MessageSent = false
|
||||
self.MessageGroup = false
|
||||
self.MessageCoalition = false
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Creates a new MESSAGE object of a certain type.
|
||||
-- Note that these MESSAGE objects are not yet displayed on the display panel.
|
||||
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
||||
@@ -134,10 +133,12 @@ end
|
||||
-- @param #boolean ClearScreen (optional) Clear all previous messages.
|
||||
-- @return #MESSAGE
|
||||
-- @usage
|
||||
--
|
||||
-- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information )
|
||||
-- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information )
|
||||
-- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update )
|
||||
-- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update )
|
||||
--
|
||||
function MESSAGE:NewType( MessageText, MessageType, ClearScreen )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
@@ -145,69 +146,67 @@ function MESSAGE:NewType( MessageText, MessageType, ClearScreen )
|
||||
|
||||
self.MessageType = MessageType
|
||||
|
||||
self.ClearScreen=false
|
||||
if ClearScreen~=nil then
|
||||
self.ClearScreen=ClearScreen
|
||||
self.ClearScreen = false
|
||||
if ClearScreen ~= nil then
|
||||
self.ClearScreen = ClearScreen
|
||||
end
|
||||
|
||||
self.MessageTime = timer.getTime()
|
||||
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
|
||||
self.MessageText = MessageText:gsub( "^\n", "", 1 ):gsub( "\n$", "", 1 )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Clears all previous messages from the screen before the new message is displayed. Not that this must come before all functions starting with ToX(), e.g. ToAll(), ToGroup() etc.
|
||||
-- @param #MESSAGE self
|
||||
-- @return #MESSAGE
|
||||
function MESSAGE:Clear()
|
||||
self:F()
|
||||
self.ClearScreen=true
|
||||
self.ClearScreen = true
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player".
|
||||
-- @param #MESSAGE self
|
||||
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
|
||||
-- @param Core.Settings#SETTINGS Settings Settings used to display the message.
|
||||
-- @return #MESSAGE
|
||||
-- @usage
|
||||
-- -- Send the 2 messages created with the @{New} method to the Client Group.
|
||||
-- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1.
|
||||
-- ClientGroup = Group.getByName( "ClientGroup" )
|
||||
--
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- or
|
||||
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- or
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
|
||||
-- MessageClient1:ToClient( ClientGroup )
|
||||
-- MessageClient2:ToClient( ClientGroup )
|
||||
-- -- Send the 2 messages created with the @{New} method to the Client Group.
|
||||
-- -- Note that the Message of MessageClient2 is overwriting the Message of MessageClient1.
|
||||
-- ClientGroup = Group.getByName( "ClientGroup" )
|
||||
--
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- or
|
||||
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||
-- or
|
||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" )
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
|
||||
-- MessageClient1:ToClient( ClientGroup )
|
||||
-- MessageClient2:ToClient( ClientGroup )
|
||||
--
|
||||
function MESSAGE:ToClient( Client, Settings )
|
||||
self:F( Client )
|
||||
self:F( Client )
|
||||
|
||||
if Client and Client:GetClientGroupID() then
|
||||
if Client and Client:GetClientGroupID() then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
local Settings = Settings or (Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
local ClientGroupID = Client:GetClientGroupID()
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||
end
|
||||
end
|
||||
local ClientGroupID = Client:GetClientGroupID()
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to a Group.
|
||||
@@ -220,14 +219,14 @@ function MESSAGE:ToGroup( Group, Settings )
|
||||
if Group then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
local Settings = Settings or (Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -237,38 +236,42 @@ end
|
||||
-- @param #MESSAGE self
|
||||
-- @return #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()
|
||||
--
|
||||
-- -- 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()
|
||||
self:F()
|
||||
self:F()
|
||||
|
||||
self:ToCoalition( coalition.side.BLUE )
|
||||
self:ToCoalition( coalition.side.BLUE )
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to the Red Coalition.
|
||||
-- @param #MESSAGE self
|
||||
-- @return #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( )
|
||||
self:F()
|
||||
--
|
||||
-- -- 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()
|
||||
self:F()
|
||||
|
||||
self:ToCoalition( coalition.side.RED )
|
||||
self:ToCoalition( coalition.side.RED )
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to a Coalition.
|
||||
@@ -277,15 +280,17 @@ end
|
||||
-- @param Core.Settings#SETTINGS Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE Message object.
|
||||
-- @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" ):ToCoalition( coalition.side.RED )
|
||||
-- or
|
||||
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
|
||||
-- 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:ToCoalition( coalition.side.RED )
|
||||
--
|
||||
-- -- 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" ):ToCoalition( coalition.side.RED )
|
||||
-- or
|
||||
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
|
||||
-- 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:ToCoalition( coalition.side.RED )
|
||||
--
|
||||
function MESSAGE:ToCoalition( CoalitionSide, Settings )
|
||||
self:F( CoalitionSide )
|
||||
self:F( CoalitionSide )
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||
@@ -293,14 +298,14 @@ function MESSAGE:ToCoalition( CoalitionSide, Settings )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
if CoalitionSide then
|
||||
if CoalitionSide then
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sends a MESSAGE to a Coalition if the given Condition is true.
|
||||
@@ -323,14 +328,16 @@ end
|
||||
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
|
||||
-- @return #MESSAGE
|
||||
-- @usage
|
||||
-- -- Send a message created to all players.
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
|
||||
-- or
|
||||
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
|
||||
-- or
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
|
||||
-- MessageAll:ToAll()
|
||||
function MESSAGE:ToAll(Settings)
|
||||
--
|
||||
-- -- Send a message created to all players.
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
|
||||
-- or
|
||||
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
|
||||
-- or
|
||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
|
||||
-- MessageAll:ToAll()
|
||||
--
|
||||
function MESSAGE:ToAll( Settings )
|
||||
self:F()
|
||||
|
||||
if self.MessageType then
|
||||
@@ -340,14 +347,13 @@ function MESSAGE:ToAll(Settings)
|
||||
end
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
||||
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Sends a MESSAGE to all players if the given Condition is true.
|
||||
-- @param #MESSAGE self
|
||||
-- @return #MESSAGE
|
||||
@@ -357,5 +363,5 @@ function MESSAGE:ToAllIf( Condition )
|
||||
self:ToAll()
|
||||
end
|
||||
|
||||
return self
|
||||
return self
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,6 @@
|
||||
-- @module Core.Report
|
||||
-- @image Core_Report.JPG
|
||||
|
||||
|
||||
--- @type REPORT
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
@@ -45,28 +44,26 @@ end
|
||||
--- Has the REPORT Text?
|
||||
-- @param #REPORT self
|
||||
-- @return #boolean
|
||||
function REPORT:HasText() --R2.1
|
||||
function REPORT:HasText() -- R2.1
|
||||
|
||||
return #self.Report > 0
|
||||
end
|
||||
|
||||
|
||||
--- Set indent of a REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #number Indent
|
||||
-- @return #REPORT
|
||||
function REPORT:SetIndent( Indent ) --R2.1
|
||||
function REPORT:SetIndent( Indent ) -- R2.1
|
||||
self.Indent = Indent
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Add a new line to a REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Text
|
||||
-- @return #REPORT
|
||||
function REPORT:Add( Text )
|
||||
self.Report[#self.Report+1] = Text
|
||||
self.Report[#self.Report + 1] = Text
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -76,17 +73,17 @@ end
|
||||
-- @param #string Separator (optional) The start of each report line can begin with an optional separator character. This can be a "-", or "#", or "*". You're free to choose what you find the best.
|
||||
-- @return #REPORT
|
||||
function REPORT:AddIndent( Text, Separator )
|
||||
self.Report[#self.Report+1] = ( ( Separator and Separator .. string.rep( " ", self.Indent - 1 ) ) or string.rep(" ", self.Indent ) ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
|
||||
self.Report[#self.Report + 1] = ((Separator and Separator .. string.rep( " ", self.Indent - 1 )) or string.rep( " ", self.Indent )) .. Text:gsub( "\n", "\n" .. string.rep( " ", self.Indent ) )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Produces the text of the report, taking into account an optional delimeter, which is \n by default.
|
||||
--- Produces the text of the report, taking into account an optional delimiter, which is \n by default.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Delimiter (optional) A delimiter text.
|
||||
-- @return #string The report text.
|
||||
function REPORT:Text( Delimiter )
|
||||
Delimiter = Delimiter or "\n"
|
||||
local ReportText = ( self.Title ~= "" and self.Title .. Delimiter or self.Title ) .. table.concat( self.Report, Delimiter ) or ""
|
||||
local ReportText = (self.Title ~= "" and self.Title .. Delimiter or self.Title) .. table.concat( self.Report, Delimiter ) or ""
|
||||
return ReportText
|
||||
end
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
-- - When a SCHEDULER object is not attached to another object (that is, it's first :Schedule() parameter is nil), then the SCHEDULER object is _persistent_ within memory.
|
||||
-- - When a SCHEDULER object *is* attached to another object, then the SCHEDULER object is _not persistent_ within memory after a garbage collection!
|
||||
--
|
||||
-- The none persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collectged, when the parent object is also desroyed or nillified and garbage collected.
|
||||
-- The non-persistency of SCHEDULERS attached to objects is required to allow SCHEDULER objects to be garbage collected when the parent object is destroyed, or set to nil and garbage collected.
|
||||
-- Even when there are pending timer scheduled functions to be executed for the SCHEDULER object,
|
||||
-- these will not be executed anymore when the SCHEDULER object has been destroyed.
|
||||
--
|
||||
@@ -38,7 +38,7 @@
|
||||
-- @type SCHEDULEDISPATCHER
|
||||
-- @field #string ClassName Name of the class.
|
||||
-- @field #number CallID Call ID counter.
|
||||
-- @field #table PersistentSchedulers Persistant schedulers.
|
||||
-- @field #table PersistentSchedulers Persistent schedulers.
|
||||
-- @field #table ObjectSchedulers Schedulers that only exist as long as the master object exists.
|
||||
-- @field #table Schedule Meta table setmetatable( {}, { __mode = "k" } ).
|
||||
-- @extends Core.Base#BASE
|
||||
@@ -46,11 +46,11 @@
|
||||
--- The SCHEDULEDISPATCHER structure
|
||||
-- @type SCHEDULEDISPATCHER
|
||||
SCHEDULEDISPATCHER = {
|
||||
ClassName = "SCHEDULEDISPATCHER",
|
||||
CallID = 0,
|
||||
PersistentSchedulers = {},
|
||||
ObjectSchedulers = {},
|
||||
Schedule = nil,
|
||||
ClassName = "SCHEDULEDISPATCHER",
|
||||
CallID = 0,
|
||||
PersistentSchedulers = {},
|
||||
ObjectSchedulers = {},
|
||||
Schedule = nil,
|
||||
}
|
||||
|
||||
--- Player data table holding all important parameters of each player.
|
||||
@@ -58,7 +58,7 @@ SCHEDULEDISPATCHER = {
|
||||
-- @field #function Function The schedule function to be called.
|
||||
-- @field #table Arguments Schedule function arguments.
|
||||
-- @field #number Start Start time in seconds.
|
||||
-- @field #number Repeat Repeat time intervall in seconds.
|
||||
-- @field #number Repeat Repeat time interval in seconds.
|
||||
-- @field #number Randomize Randomization factor [0,1].
|
||||
-- @field #number Stop Stop time in seconds.
|
||||
-- @field #number StartTime Time in seconds when the scheduler is created.
|
||||
@@ -77,7 +77,7 @@ end
|
||||
|
||||
--- Add a Schedule to the ScheduleDispatcher.
|
||||
-- The development of this method was really tidy.
|
||||
-- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is nillified.
|
||||
-- It is constructed as such that a garbage collection is executed on the weak tables, when the Scheduler is set to nil.
|
||||
-- Nothing of this code should be modified without testing it thoroughly.
|
||||
-- @param #SCHEDULEDISPATCHER self
|
||||
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
|
||||
@@ -85,7 +85,7 @@ end
|
||||
-- @param #table ScheduleArguments Table of arguments passed to the ScheduleFunction.
|
||||
-- @param #number Start Start time in seconds.
|
||||
-- @param #number Repeat Repeat interval in seconds.
|
||||
-- @param #number Randomize Radomization factor [0,1].
|
||||
-- @param #number Randomize Randomization factor [0,1].
|
||||
-- @param #number Stop Stop time in seconds.
|
||||
-- @param #number TraceLevel Trace level [0,3].
|
||||
-- @param Core.Fsm#FSM Fsm Finite state model.
|
||||
@@ -97,9 +97,9 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
self.CallID = self.CallID + 1
|
||||
|
||||
-- Create ID.
|
||||
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or ""
|
||||
local CallID = self.CallID .. "#" .. (Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "") or ""
|
||||
|
||||
self:T2(string.format("Adding schedule #%d CallID=%s", self.CallID, CallID))
|
||||
self:T2( string.format( "Adding schedule #%d CallID=%s", self.CallID, CallID ) )
|
||||
|
||||
-- Initialize PersistentSchedulers
|
||||
self.PersistentSchedulers = self.PersistentSchedulers or {}
|
||||
@@ -110,7 +110,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
|
||||
if Scheduler.MasterObject then
|
||||
self.ObjectSchedulers[CallID] = Scheduler
|
||||
self:F3( { CallID = CallID, ObjectScheduler = tostring(self.ObjectSchedulers[CallID]), MasterObject = tostring(Scheduler.MasterObject) } )
|
||||
self:F3( { CallID = CallID, ObjectScheduler = tostring( self.ObjectSchedulers[CallID] ), MasterObject = tostring( Scheduler.MasterObject ) } )
|
||||
else
|
||||
self.PersistentSchedulers[CallID] = Scheduler
|
||||
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
|
||||
@@ -118,16 +118,15 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
|
||||
self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } )
|
||||
self.Schedule[Scheduler] = self.Schedule[Scheduler] or {}
|
||||
self.Schedule[Scheduler][CallID] = {} --#SCHEDULEDISPATCHER.ScheduleData
|
||||
self.Schedule[Scheduler][CallID] = {} -- #SCHEDULEDISPATCHER.ScheduleData
|
||||
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
|
||||
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
|
||||
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
|
||||
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + (Start or 0)
|
||||
self.Schedule[Scheduler][CallID].Start = Start + 0.1
|
||||
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
|
||||
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
|
||||
self.Schedule[Scheduler][CallID].Stop = Stop
|
||||
|
||||
|
||||
-- This section handles the tracing of the scheduled calls.
|
||||
-- Because these calls will be executed with a delay, we inspect the place where these scheduled calls are initiated.
|
||||
-- The Info structure contains the output of the debug.getinfo() calls, which inspects the call stack for the function name, line number and source name.
|
||||
@@ -149,7 +148,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
-- Therefore, in the call stack, at the TraceLevel these functions are mentioned as "tail calls", and the Info.name field will be nil as a result.
|
||||
-- To obtain the correct function name for FSM object calls, the function is mentioned in the call stack at a higher stack level.
|
||||
-- So when function name stored in Info.name is nil, then I inspect the function name within the call stack one level higher.
|
||||
-- So this little piece of code does its magic wonderfully, preformance overhead is neglectible, as scheduled calls don't happen that often.
|
||||
-- So this little piece of code does its magic wonderfully, performance overhead is negligible, as scheduled calls don't happen that often.
|
||||
|
||||
local Info = {}
|
||||
|
||||
@@ -181,24 +180,24 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
return errmsg
|
||||
end
|
||||
|
||||
-- Get object or persistant scheduler object.
|
||||
local Scheduler = self.ObjectSchedulers[CallID] --Core.Scheduler#SCHEDULER
|
||||
-- Get object or persistent scheduler object.
|
||||
local Scheduler = self.ObjectSchedulers[CallID] -- Core.Scheduler#SCHEDULER
|
||||
if not Scheduler then
|
||||
Scheduler = self.PersistentSchedulers[CallID]
|
||||
end
|
||||
|
||||
--self:T3( { Scheduler = Scheduler } )
|
||||
-- self:T3( { Scheduler = Scheduler } )
|
||||
|
||||
if Scheduler then
|
||||
|
||||
local MasterObject = tostring(Scheduler.MasterObject)
|
||||
local MasterObject = tostring( Scheduler.MasterObject )
|
||||
|
||||
-- Schedule object.
|
||||
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
|
||||
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
||||
|
||||
--self:T3( { Schedule = Schedule } )
|
||||
-- self:T3( { Schedule = Schedule } )
|
||||
|
||||
local SchedulerObject = Scheduler.MasterObject --Scheduler.SchedulerObject Now is this the Maste or Scheduler object?
|
||||
local SchedulerObject = Scheduler.MasterObject -- Scheduler.SchedulerObject Now is this the Master or Scheduler object?
|
||||
local ShowTrace = Scheduler.ShowTrace
|
||||
|
||||
local ScheduleFunction = Schedule.Function
|
||||
@@ -209,11 +208,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
local Stop = Schedule.Stop or 0
|
||||
local ScheduleID = Schedule.ScheduleID
|
||||
|
||||
|
||||
local Prefix = ( Repeat == 0 ) and "--->" or "+++>"
|
||||
local Prefix = (Repeat == 0) and "--->" or "+++>"
|
||||
|
||||
local Status, Result
|
||||
--self:E( { SchedulerObject = SchedulerObject } )
|
||||
-- self:E( { SchedulerObject = SchedulerObject } )
|
||||
if SchedulerObject then
|
||||
local function Timer()
|
||||
if ShowTrace then
|
||||
@@ -236,14 +234,13 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
local StartTime = Schedule.StartTime
|
||||
|
||||
-- Debug info.
|
||||
self:F3( { CallID=CallID, ScheduleID=ScheduleID, Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
|
||||
self:F3( { CallID = CallID, ScheduleID = ScheduleID, Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
|
||||
|
||||
if Status and ((Result == nil) or (Result and Result ~= false)) then
|
||||
|
||||
if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then
|
||||
|
||||
if Repeat ~= 0 and ( ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) ) then
|
||||
local ScheduleTime = CurrentTime + Repeat + math.random(- ( Randomize * Repeat / 2 ), ( Randomize * Repeat / 2 )) + 0.0001 -- Accuracy
|
||||
--self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
|
||||
if Repeat ~= 0 and ((Stop == 0) or (Stop ~= 0 and CurrentTime <= StartTime + Stop)) then
|
||||
local ScheduleTime = CurrentTime + Repeat + math.random( -(Randomize * Repeat / 2), (Randomize * Repeat / 2) ) + 0.0001 -- Accuracy
|
||||
-- self:T3( { Repeat = CallID, CurrentTime, ScheduleTime, ScheduleArguments } )
|
||||
return ScheduleTime -- returns the next time the function needs to be called.
|
||||
else
|
||||
self:Stop( Scheduler, CallID )
|
||||
@@ -287,21 +284,21 @@ function SCHEDULEDISPATCHER:Start( Scheduler, CallID, Info )
|
||||
|
||||
if CallID then
|
||||
|
||||
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
|
||||
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
||||
|
||||
-- Only start when there is no ScheduleID defined!
|
||||
-- This prevents to "Start" the scheduler twice with the same CallID...
|
||||
if not Schedule.ScheduleID then
|
||||
|
||||
-- Current time in seconds.
|
||||
local Tnow=timer.getTime()
|
||||
local Tnow = timer.getTime()
|
||||
|
||||
Schedule.StartTime = Tnow -- Set the StartTime field to indicate when the scheduler started.
|
||||
Schedule.StartTime = Tnow -- Set the StartTime field to indicate when the scheduler started.
|
||||
|
||||
-- Start DCS schedule function https://wiki.hoggitworld.com/view/DCS_func_scheduleFunction
|
||||
Schedule.ScheduleID = timer.scheduleFunction(Schedule.CallHandler, { CallID = CallID, Info = Info }, Tnow + Schedule.Start)
|
||||
Schedule.ScheduleID = timer.scheduleFunction( Schedule.CallHandler, { CallID = CallID, Info = Info }, Tnow + Schedule.Start )
|
||||
|
||||
self:T(string.format("Starting scheduledispatcher Call ID=%s ==> Schedule ID=%s", tostring(CallID), tostring(Schedule.ScheduleID)))
|
||||
self:T( string.format( "Starting SCHEDULEDISPATCHER Call ID=%s ==> Schedule ID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
||||
end
|
||||
|
||||
else
|
||||
@@ -323,20 +320,20 @@ function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
||||
|
||||
if CallID then
|
||||
|
||||
local Schedule = self.Schedule[Scheduler][CallID] --#SCHEDULEDISPATCHER.ScheduleData
|
||||
local Schedule = self.Schedule[Scheduler][CallID] -- #SCHEDULEDISPATCHER.ScheduleData
|
||||
|
||||
-- Only stop when there is a ScheduleID defined for the CallID. So, when the scheduler was stopped before, do nothing.
|
||||
if Schedule.ScheduleID then
|
||||
|
||||
self:T(string.format("scheduledispatcher stopping scheduler CallID=%s, ScheduleID=%s", tostring(CallID), tostring(Schedule.ScheduleID)))
|
||||
self:T( string.format( "SCHEDULEDISPATCHER stopping scheduler CallID=%s, ScheduleID=%s", tostring( CallID ), tostring( Schedule.ScheduleID ) ) )
|
||||
|
||||
-- Remove schedule function https://wiki.hoggitworld.com/view/DCS_func_removeFunction
|
||||
timer.removeFunction(Schedule.ScheduleID)
|
||||
timer.removeFunction( Schedule.ScheduleID )
|
||||
|
||||
Schedule.ScheduleID = nil
|
||||
|
||||
else
|
||||
self:T(string.format("Error no ScheduleID for CallID=%s", tostring(CallID)))
|
||||
self:T( string.format( "Error no ScheduleID for CallID=%s", tostring( CallID ) ) )
|
||||
end
|
||||
|
||||
else
|
||||
@@ -359,7 +356,7 @@ function SCHEDULEDISPATCHER:Clear( Scheduler )
|
||||
end
|
||||
end
|
||||
|
||||
--- Shopw tracing info.
|
||||
--- Show tracing info.
|
||||
-- @param #SCHEDULEDISPATCHER self
|
||||
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
|
||||
function SCHEDULEDISPATCHER:ShowTrace( Scheduler )
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
-- @field #boolean ShowTrace Trace info if true.
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
--- Creates and handles schedules over time, which allow to execute code at specific time intervals with randomization.
|
||||
--
|
||||
-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**.
|
||||
@@ -79,7 +78,7 @@
|
||||
--
|
||||
-- ### Construct a SCHEDULER object without a volatile schedule, but volatile to the Object existence...
|
||||
--
|
||||
-- * @{#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection.
|
||||
-- * @{#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is set to nil or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection.
|
||||
--
|
||||
-- ZoneObject = ZONE:New( "ZoneName" )
|
||||
-- MasterObject = SCHEDULER:New( ZoneObject )
|
||||
@@ -149,13 +148,13 @@
|
||||
-- ZoneObject = ZONE:New( "ZoneName" )
|
||||
-- MasterObject = SCHEDULER:New( ZoneObject )
|
||||
--
|
||||
-- Several parameters can be specified that influence the behaviour of a Schedule.
|
||||
-- Several parameters can be specified that influence the behavior of a Schedule.
|
||||
--
|
||||
-- ### A single schedule, immediately executed
|
||||
--
|
||||
-- SchedulerID = MasterObject:Schedule( ZoneObject, ScheduleFunction, {} )
|
||||
--
|
||||
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within milleseconds ...
|
||||
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within milliseconds ...
|
||||
--
|
||||
-- ### A single schedule, planned over time
|
||||
--
|
||||
@@ -193,10 +192,10 @@
|
||||
--
|
||||
-- @field #SCHEDULER
|
||||
SCHEDULER = {
|
||||
ClassName = "SCHEDULER",
|
||||
Schedules = {},
|
||||
MasterObject = nil,
|
||||
ShowTrace = nil,
|
||||
ClassName = "SCHEDULER",
|
||||
Schedules = {},
|
||||
MasterObject = nil,
|
||||
ShowTrace = nil,
|
||||
}
|
||||
|
||||
--- SCHEDULER constructor.
|
||||
@@ -235,7 +234,7 @@ end
|
||||
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
||||
-- @param #number Repeat Specifies the time interval in seconds when the scheduler will call the event function.
|
||||
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
|
||||
-- @param #number Stop Time interval in seconds after which the scheduler will be stoppe.
|
||||
-- @param #number Stop Time interval in seconds after which the scheduler will be stopped.
|
||||
-- @param #number TraceLevel Trace level [0,3]. Default 3.
|
||||
-- @param Core.Fsm#FSM Fsm Finite state model.
|
||||
-- @return #table The ScheduleID of the planned schedule.
|
||||
@@ -248,25 +247,24 @@ function SCHEDULER:Schedule( MasterObject, SchedulerFunction, SchedulerArguments
|
||||
if MasterObject and MasterObject.ClassName and MasterObject.ClassID then
|
||||
ObjectName = MasterObject.ClassName .. MasterObject.ClassID
|
||||
end
|
||||
self:F3( { "Schedule :", ObjectName, tostring( MasterObject ), Start, Repeat, RandomizeFactor, Stop } )
|
||||
self:F3( { "Schedule :", ObjectName, tostring( MasterObject ), Start, Repeat, RandomizeFactor, Stop } )
|
||||
|
||||
-- Set master object.
|
||||
self.MasterObject = MasterObject
|
||||
|
||||
-- Add schedule.
|
||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||
self,
|
||||
SchedulerFunction,
|
||||
SchedulerArguments,
|
||||
Start,
|
||||
Repeat,
|
||||
RandomizeFactor,
|
||||
Stop,
|
||||
TraceLevel or 3,
|
||||
Fsm
|
||||
)
|
||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( self,
|
||||
SchedulerFunction,
|
||||
SchedulerArguments,
|
||||
Start,
|
||||
Repeat,
|
||||
RandomizeFactor,
|
||||
Stop,
|
||||
TraceLevel or 3,
|
||||
Fsm
|
||||
)
|
||||
|
||||
self.Schedules[#self.Schedules+1] = ScheduleID
|
||||
self.Schedules[#self.Schedules + 1] = ScheduleID
|
||||
|
||||
return ScheduleID
|
||||
end
|
||||
@@ -276,7 +274,7 @@ end
|
||||
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
|
||||
function SCHEDULER:Start( ScheduleID )
|
||||
self:F3( { ScheduleID } )
|
||||
self:T(string.format("Starting scheduler ID=%s", tostring(ScheduleID)))
|
||||
self:T( string.format( "Starting scheduler ID=%s", tostring( ScheduleID ) ) )
|
||||
_SCHEDULEDISPATCHER:Start( self, ScheduleID )
|
||||
end
|
||||
|
||||
@@ -285,7 +283,7 @@ end
|
||||
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
|
||||
function SCHEDULER:Stop( ScheduleID )
|
||||
self:F3( { ScheduleID } )
|
||||
self:T(string.format("Stopping scheduler ID=%s", tostring(ScheduleID)))
|
||||
self:T( string.format( "Stopping scheduler ID=%s", tostring( ScheduleID ) ) )
|
||||
_SCHEDULEDISPATCHER:Stop( self, ScheduleID )
|
||||
end
|
||||
|
||||
@@ -294,15 +292,15 @@ end
|
||||
-- @param #string ScheduleID (optional) The ScheduleID of the planned (repeating) schedule.
|
||||
function SCHEDULER:Remove( ScheduleID )
|
||||
self:F3( { ScheduleID } )
|
||||
self:T(string.format("Removing scheduler ID=%s", tostring(ScheduleID)))
|
||||
self:T( string.format( "Removing scheduler ID=%s", tostring( ScheduleID ) ) )
|
||||
_SCHEDULEDISPATCHER:RemoveSchedule( self, ScheduleID )
|
||||
end
|
||||
|
||||
--- Clears all pending schedules.
|
||||
-- @param #SCHEDULER self
|
||||
function SCHEDULER:Clear()
|
||||
self:F3( )
|
||||
self:T(string.format("Clearing scheduler"))
|
||||
self:F3()
|
||||
self:T( string.format( "Clearing scheduler" ) )
|
||||
_SCHEDULEDISPATCHER:Clear( self )
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,15 +29,14 @@
|
||||
-- @module Core.Settings
|
||||
-- @image Core_Settings.JPG
|
||||
|
||||
|
||||
--- @type SETTINGS
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
|
||||
--- Takes care of various settings that influence the behavior of certain functionalities and classes within the MOOSE framework.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
|
||||
-- The SETTINGS class takes care of various settings that influence the behavior of certain functionalities and classes within the MOOSE framework.
|
||||
-- SETTINGS can work on 2 levels:
|
||||
--
|
||||
-- - **Default settings**: A running mission has **Default settings**.
|
||||
@@ -59,7 +58,7 @@
|
||||
--
|
||||
-- A menu is created automatically per Command Center that allows to modify the **Default** settings.
|
||||
-- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**!
|
||||
-- Note that the **Default settings** will only be used when a player has not choosen its own settings.
|
||||
-- Note that the **Default settings** will only be used when a player has not chosen its own settings.
|
||||
--
|
||||
-- ## 2.2) Player settings menu
|
||||
--
|
||||
@@ -69,7 +68,7 @@
|
||||
--
|
||||
-- ## 2.3) Show or Hide the Player Setting menus
|
||||
--
|
||||
-- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**.
|
||||
-- Of course, it may be required not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**.
|
||||
-- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus.
|
||||
-- Note that when this method is used, any player already in a slot will not have its menus visibility changed.
|
||||
-- The option will only have effect when a player enters a new slot or changes a slot.
|
||||
@@ -94,8 +93,8 @@
|
||||
--
|
||||
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)).
|
||||
-- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
|
||||
-- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||
-- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||
-- - A2G LL DMS: Latitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
|
||||
-- - A2G LL DDM: Latitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
|
||||
--
|
||||
-- ### 3.1.2) A2G coordinates setting **menu**
|
||||
--
|
||||
@@ -183,7 +182,7 @@
|
||||
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
|
||||
--
|
||||
-- Each Message Type has specific timings that will be applied when the message is displayed.
|
||||
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be choosen.
|
||||
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be chosen.
|
||||
-- So the player can choose its own amount of seconds how long a message should be displayed of a certain type.
|
||||
-- Note that **Update** messages can be chosen not to be displayed at all!
|
||||
--
|
||||
@@ -196,7 +195,7 @@
|
||||
--
|
||||
-- ## 3.5) **Era** of the battle
|
||||
--
|
||||
-- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greather threat in WWII than on modern warfare.
|
||||
-- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greater threat in WWII than on modern warfare.
|
||||
-- Therefore, there are 4 era that are defined within the settings:
|
||||
--
|
||||
-- - **WWII** era: Use for warfare with equipment during the world war II time.
|
||||
@@ -213,8 +212,8 @@
|
||||
SETTINGS = {
|
||||
ClassName = "SETTINGS",
|
||||
ShowPlayerMenu = true,
|
||||
MenuShort = false,
|
||||
MenuStatic = false,
|
||||
MenuShort = false,
|
||||
MenuStatic = false,
|
||||
}
|
||||
|
||||
SETTINGS.__Enum = {}
|
||||
@@ -231,7 +230,6 @@ SETTINGS.__Enum.Era = {
|
||||
Modern = 4,
|
||||
}
|
||||
|
||||
|
||||
do -- SETTINGS
|
||||
|
||||
--- SETTINGS constructor.
|
||||
@@ -268,14 +266,14 @@ do -- SETTINGS
|
||||
-- Short text are better suited for, e.g., VR.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #boolean onoff If *true* use short menu texts. If *false* long ones (default).
|
||||
function SETTINGS:SetMenutextShort(onoff)
|
||||
function SETTINGS:SetMenutextShort( onoff )
|
||||
_SETTINGS.MenuShort = onoff
|
||||
end
|
||||
|
||||
--- Set menu to be static.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #boolean onoff If *true* menu is static. If *false* menu will be updated after changes (default).
|
||||
function SETTINGS:SetMenuStatic(onoff)
|
||||
function SETTINGS:SetMenuStatic( onoff )
|
||||
_SETTINGS.MenuStatic = onoff
|
||||
end
|
||||
|
||||
@@ -289,7 +287,7 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if metric.
|
||||
function SETTINGS:IsMetric()
|
||||
return ( self.Metric ~= nil and self.Metric == true ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
|
||||
return (self.Metric ~= nil and self.Metric == true) or (self.Metric == nil and _SETTINGS:IsMetric())
|
||||
end
|
||||
|
||||
--- Sets the SETTINGS imperial.
|
||||
@@ -302,7 +300,7 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if imperial.
|
||||
function SETTINGS:IsImperial()
|
||||
return ( self.Metric ~= nil and self.Metric == false ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
|
||||
return (self.Metric ~= nil and self.Metric == false) or (self.Metric == nil and _SETTINGS:IsMetric())
|
||||
end
|
||||
|
||||
--- Sets the SETTINGS LL accuracy.
|
||||
@@ -344,13 +342,12 @@ do -- SETTINGS
|
||||
self.MessageTypeTimings[MessageType] = MessageTime
|
||||
end
|
||||
|
||||
|
||||
--- Gets the SETTINGS Message Display Timing of a MessageType
|
||||
-- @param #SETTINGS self
|
||||
-- @param Core.Message#MESSAGE MessageType The type of the message.
|
||||
-- @return #number
|
||||
function SETTINGS:GetMessageTime( MessageType )
|
||||
return ( self.MessageTypeTimings and self.MessageTypeTimings[MessageType] ) or _SETTINGS:GetMessageTime( MessageType )
|
||||
return (self.MessageTypeTimings and self.MessageTypeTimings[MessageType]) or _SETTINGS:GetMessageTime( MessageType )
|
||||
end
|
||||
|
||||
--- Sets A2G LL DMS
|
||||
@@ -371,14 +368,14 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL DMS
|
||||
function SETTINGS:IsA2G_LL_DMS()
|
||||
return ( self.A2GSystem and self.A2GSystem == "LL DMS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS() )
|
||||
return (self.A2GSystem and self.A2GSystem == "LL DMS") or (not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS())
|
||||
end
|
||||
|
||||
--- Is LL DDM
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL DDM
|
||||
function SETTINGS:IsA2G_LL_DDM()
|
||||
return ( self.A2GSystem and self.A2GSystem == "LL DDM" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM() )
|
||||
return (self.A2GSystem and self.A2GSystem == "LL DDM") or (not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM())
|
||||
end
|
||||
|
||||
--- Sets A2G MGRS
|
||||
@@ -392,7 +389,7 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if MGRS
|
||||
function SETTINGS:IsA2G_MGRS()
|
||||
return ( self.A2GSystem and self.A2GSystem == "MGRS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_MGRS() )
|
||||
return (self.A2GSystem and self.A2GSystem == "MGRS") or (not self.A2GSystem and _SETTINGS:IsA2G_MGRS())
|
||||
end
|
||||
|
||||
--- Sets A2G BRA
|
||||
@@ -406,7 +403,7 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if BRA
|
||||
function SETTINGS:IsA2G_BR()
|
||||
return ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() )
|
||||
return (self.A2GSystem and self.A2GSystem == "BR") or (not self.A2GSystem and _SETTINGS:IsA2G_BR())
|
||||
end
|
||||
|
||||
--- Sets A2A BRA
|
||||
@@ -420,7 +417,7 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if BRA
|
||||
function SETTINGS:IsA2A_BRAA()
|
||||
return ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() )
|
||||
return (self.A2ASystem and self.A2ASystem == "BRAA") or (not self.A2ASystem and _SETTINGS:IsA2A_BRAA())
|
||||
end
|
||||
|
||||
--- Sets A2A BULLS
|
||||
@@ -434,7 +431,7 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if BULLS
|
||||
function SETTINGS:IsA2A_BULLS()
|
||||
return ( self.A2ASystem and self.A2ASystem == "BULLS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BULLS() )
|
||||
return (self.A2ASystem and self.A2ASystem == "BULLS") or (not self.A2ASystem and _SETTINGS:IsA2A_BULLS())
|
||||
end
|
||||
|
||||
--- Sets A2A LL DMS
|
||||
@@ -455,14 +452,14 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL DMS
|
||||
function SETTINGS:IsA2A_LL_DMS()
|
||||
return ( self.A2ASystem and self.A2ASystem == "LL DMS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS() )
|
||||
return (self.A2ASystem and self.A2ASystem == "LL DMS") or (not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS())
|
||||
end
|
||||
|
||||
--- Is LL DDM
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL DDM
|
||||
function SETTINGS:IsA2A_LL_DDM()
|
||||
return ( self.A2ASystem and self.A2ASystem == "LL DDM" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM() )
|
||||
return (self.A2ASystem and self.A2ASystem == "LL DDM") or (not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM())
|
||||
end
|
||||
|
||||
--- Sets A2A MGRS
|
||||
@@ -476,7 +473,7 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if MGRS
|
||||
function SETTINGS:IsA2A_MGRS()
|
||||
return ( self.A2ASystem and self.A2ASystem == "MGRS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_MGRS() )
|
||||
return (self.A2ASystem and self.A2ASystem == "MGRS") or (not self.A2ASystem and _SETTINGS:IsA2A_MGRS())
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
@@ -495,37 +492,37 @@ do -- SETTINGS
|
||||
-- A2G Coordinate System
|
||||
-------
|
||||
|
||||
local text="A2G Coordinate System"
|
||||
local text = "A2G Coordinate System"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2G Coordinates"
|
||||
text = "A2G Coordinates"
|
||||
end
|
||||
local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
-- Set LL DMS
|
||||
if not self:IsA2G_LL_DMS() then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
local text = "Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DMS"
|
||||
text = "LL DMS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
-- Set LL DDM
|
||||
if not self:IsA2G_LL_DDM() then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
local text = "Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DDM"
|
||||
text = "LL DDM"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
-- Set LL DMS accuracy.
|
||||
if self:IsA2G_LL_DDM() then
|
||||
local text1="LL DDM Accuracy 1"
|
||||
local text2="LL DDM Accuracy 2"
|
||||
local text3="LL DDM Accuracy 3"
|
||||
local text1 = "LL DDM Accuracy 1"
|
||||
local text2 = "LL DDM Accuracy 2"
|
||||
local text3 = "LL DDM Accuracy 3"
|
||||
if _SETTINGS.MenuShort then
|
||||
text1="LL DDM"
|
||||
text1 = "LL DDM"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
|
||||
@@ -534,18 +531,18 @@ do -- SETTINGS
|
||||
|
||||
-- Set BR.
|
||||
if not self:IsA2G_BR() then
|
||||
local text="Bearing, Range (BR)"
|
||||
local text = "Bearing, Range (BR)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="BR"
|
||||
text = "BR"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text , A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
-- Set MGRS.
|
||||
if not self:IsA2G_MGRS() then
|
||||
local text="Military Grid (MGRS)"
|
||||
local text = "Military Grid (MGRS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="MGRS"
|
||||
text = "MGRS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
|
||||
end
|
||||
@@ -563,24 +560,24 @@ do -- SETTINGS
|
||||
-- A2A Coordinate System
|
||||
-------
|
||||
|
||||
local text="A2A Coordinate System"
|
||||
local text = "A2A Coordinate System"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2A Coordinates"
|
||||
text = "A2A Coordinates"
|
||||
end
|
||||
local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
if not self:IsA2A_LL_DMS() then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
local text = "Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DMS"
|
||||
text = "LL DMS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if not self:IsA2A_LL_DDM() then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
local text = "Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="LL DDM"
|
||||
text = "LL DDM"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
|
||||
end
|
||||
@@ -593,25 +590,25 @@ do -- SETTINGS
|
||||
end
|
||||
|
||||
if not self:IsA2A_BULLS() then
|
||||
local text="Bullseye (BULLS)"
|
||||
local text = "Bullseye (BULLS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Bulls"
|
||||
text = "Bulls"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if not self:IsA2A_BRAA() then
|
||||
local text="Bearing Range Altitude Aspect (BRAA)"
|
||||
local text = "Bearing Range Altitude Aspect (BRAA)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="BRAA"
|
||||
text = "BRAA"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if not self:IsA2A_MGRS() then
|
||||
local text="Military Grid (MGRS)"
|
||||
local text = "Military Grid (MGRS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="MGRS"
|
||||
text = "MGRS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
|
||||
end
|
||||
@@ -624,31 +621,31 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
local text="Measures and Weights System"
|
||||
local text = "Measures and Weights System"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Unit System"
|
||||
text = "Unit System"
|
||||
end
|
||||
local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
if self:IsMetric() then
|
||||
local text="Imperial (Miles,Feet)"
|
||||
local text = "Imperial (Miles,Feet)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Imperial"
|
||||
text = "Imperial"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if self:IsImperial() then
|
||||
local text="Metric (Kilometers,Meters)"
|
||||
local text = "Metric (Kilometers,Meters)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Metric"
|
||||
text = "Metric"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
local text="Messages and Reports"
|
||||
local text = "Messages and Reports"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Messages & Reports"
|
||||
text = "Messages & Reports"
|
||||
end
|
||||
local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
@@ -689,7 +686,6 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 120 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime )
|
||||
|
||||
|
||||
SettingsMenu:Remove( MenuTime )
|
||||
|
||||
return self
|
||||
@@ -733,11 +729,11 @@ do -- SETTINGS
|
||||
|
||||
self.PlayerMenu = PlayerMenu
|
||||
|
||||
self:I(string.format("Setting menu for player %s", tostring(PlayerName)))
|
||||
self:I( string.format( "Setting menu for player %s", tostring( PlayerName ) ) )
|
||||
|
||||
local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 0 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 1 Decimal", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 1 Decimal", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 2 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 3 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL 4 Decimals", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
||||
@@ -754,40 +750,40 @@ do -- SETTINGS
|
||||
-- A2G Coordinate System
|
||||
------
|
||||
|
||||
local text="A2G Coordinate System"
|
||||
local text = "A2G Coordinate System"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2G Coordinates"
|
||||
text = "A2G Coordinates"
|
||||
end
|
||||
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
|
||||
|
||||
if not self:IsA2G_LL_DMS() or _SETTINGS.MenuStatic then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
local text = "Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2G LL DMS"
|
||||
text = "A2G LL DMS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||
end
|
||||
|
||||
if not self:IsA2G_LL_DDM() or _SETTINGS.MenuStatic then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
local text = "Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2G LL DDM"
|
||||
text = "A2G LL DDM"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
||||
end
|
||||
|
||||
if not self:IsA2G_BR() or _SETTINGS.MenuStatic then
|
||||
local text="Bearing, Range (BR)"
|
||||
local text = "Bearing, Range (BR)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2G BR"
|
||||
text = "A2G BR"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
|
||||
end
|
||||
|
||||
if not self:IsA2G_MGRS() or _SETTINGS.MenuStatic then
|
||||
local text="Military Grid (MGRS)"
|
||||
local text = "Military Grid (MGRS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2G MGRS"
|
||||
text = "A2G MGRS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||
end
|
||||
@@ -796,49 +792,48 @@ do -- SETTINGS
|
||||
-- A2A Coordinates Menu
|
||||
------
|
||||
|
||||
local text="A2A Coordinate System"
|
||||
local text = "A2A Coordinate System"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2A Coordinates"
|
||||
text = "A2A Coordinates"
|
||||
end
|
||||
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
|
||||
|
||||
|
||||
if not self:IsA2A_LL_DMS() or _SETTINGS.MenuStatic then
|
||||
local text="Lat/Lon Degree Min Sec (LL DMS)"
|
||||
local text = "Lat/Lon Degree Min Sec (LL DMS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2A LL DMS"
|
||||
text = "A2A LL DMS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||
end
|
||||
|
||||
if not self:IsA2A_LL_DDM() or _SETTINGS.MenuStatic then
|
||||
local text="Lat/Lon Degree Dec Min (LL DDM)"
|
||||
local text = "Lat/Lon Degree Dec Min (LL DDM)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2A LL DDM"
|
||||
text = "A2A LL DDM"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
||||
end
|
||||
|
||||
if not self:IsA2A_BULLS() or _SETTINGS.MenuStatic then
|
||||
local text="Bullseye (BULLS)"
|
||||
local text = "Bullseye (BULLS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2A BULLS"
|
||||
text = "A2A BULLS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
|
||||
end
|
||||
|
||||
if not self:IsA2A_BRAA() or _SETTINGS.MenuStatic then
|
||||
local text="Bearing Range Altitude Aspect (BRAA)"
|
||||
local text = "Bearing Range Altitude Aspect (BRAA)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2A BRAA"
|
||||
text = "A2A BRAA"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
|
||||
end
|
||||
|
||||
if not self:IsA2A_MGRS() or _SETTINGS.MenuStatic then
|
||||
local text="Military Grid (MGRS)"
|
||||
local text = "Military Grid (MGRS)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="A2A MGRS"
|
||||
text = "A2A MGRS"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||
end
|
||||
@@ -847,24 +842,24 @@ do -- SETTINGS
|
||||
-- Unit system
|
||||
---
|
||||
|
||||
local text="Measures and Weights System"
|
||||
local text = "Measures and Weights System"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Unit System"
|
||||
text = "Unit System"
|
||||
end
|
||||
local MetricsMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
|
||||
|
||||
if self:IsMetric() or _SETTINGS.MenuStatic then
|
||||
local text="Imperial (Miles,Feet)"
|
||||
local text = "Imperial (Miles,Feet)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Imperial"
|
||||
text = "Imperial"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
|
||||
end
|
||||
|
||||
if self:IsImperial() or _SETTINGS.MenuStatic then
|
||||
local text="Metric (Kilometers,Meters)"
|
||||
local text = "Metric (Kilometers,Meters)"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Metric"
|
||||
text = "Metric"
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
|
||||
end
|
||||
@@ -873,9 +868,9 @@ do -- SETTINGS
|
||||
-- Messages and Reports
|
||||
---
|
||||
|
||||
local text="Messages and Reports"
|
||||
local text = "Messages and Reports"
|
||||
if _SETTINGS.MenuShort then
|
||||
text="Messages & Reports"
|
||||
text = "Messages & Reports"
|
||||
end
|
||||
local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
|
||||
|
||||
@@ -935,39 +930,38 @@ do -- SETTINGS
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
|
||||
self.A2GSystem = A2GSystem
|
||||
MESSAGE:New( string.format("Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
|
||||
MESSAGE:New( string.format( "Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
|
||||
self.A2ASystem = A2ASystem
|
||||
MESSAGE:New( string.format("Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
|
||||
MESSAGE:New( string.format( "Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
|
||||
self.LL_Accuracy = LL_Accuracy
|
||||
MESSAGE:New( string.format("Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
|
||||
MESSAGE:New( string.format( "Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy )
|
||||
self.MGRS_Accuracy = MGRS_Accuracy
|
||||
MESSAGE:New( string.format("Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
|
||||
MESSAGE:New( string.format( "Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW )
|
||||
self.Metric = MW
|
||||
MESSAGE:New( string.format("Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
|
||||
MESSAGE:New( string.format( "Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
@@ -980,12 +974,12 @@ do -- SETTINGS
|
||||
do
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
|
||||
BASE:E( {self, PlayerUnit:GetName(), A2GSystem} )
|
||||
BASE:E( { self, PlayerUnit:GetName(), A2GSystem } )
|
||||
self.A2GSystem = A2GSystem
|
||||
MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
if _SETTINGS.MenuStatic == false then
|
||||
self:RemovePlayerMenu( PlayerUnit )
|
||||
self:SetPlayerMenu( PlayerUnit )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -993,9 +987,9 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
|
||||
self.A2ASystem = A2ASystem
|
||||
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
if _SETTINGS.MenuStatic == false then
|
||||
self:RemovePlayerMenu( PlayerUnit )
|
||||
self:SetPlayerMenu( PlayerUnit )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1003,9 +997,9 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
|
||||
self.LL_Accuracy = LL_Accuracy
|
||||
MESSAGE:New( string.format( "Settings: LL format accuracy set to %d decimal places for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
if _SETTINGS.MenuStatic == false then
|
||||
self:RemovePlayerMenu( PlayerUnit )
|
||||
self:SetPlayerMenu( PlayerUnit )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1013,9 +1007,9 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
|
||||
self.MGRS_Accuracy = MGRS_Accuracy
|
||||
MESSAGE:New( string.format( "Settings: MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
if _SETTINGS.MenuStatic == false then
|
||||
self:RemovePlayerMenu( PlayerUnit )
|
||||
self:SetPlayerMenu( PlayerUnit )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1023,9 +1017,9 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
|
||||
self.Metric = MW
|
||||
MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
if _SETTINGS.MenuStatic==false then
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
if _SETTINGS.MenuStatic == false then
|
||||
self:RemovePlayerMenu( PlayerUnit )
|
||||
self:SetPlayerMenu( PlayerUnit )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1055,7 +1049,6 @@ do -- SETTINGS
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Configures the era of the mission to be Cold war.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS self
|
||||
@@ -1065,7 +1058,6 @@ do -- SETTINGS
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Configures the era of the mission to be Modern war.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS self
|
||||
@@ -1075,7 +1067,4 @@ do -- SETTINGS
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,6 @@
|
||||
-- @module Functional.FOX
|
||||
-- @image Functional_FOX.png
|
||||
|
||||
|
||||
--- FOX class.
|
||||
-- @type FOX
|
||||
-- @field #string ClassName Name of the class.
|
||||
@@ -48,7 +47,6 @@
|
||||
-- @field #number dt05 Time step [sec] for missile position updates if distance to target > 5 km and < 10 km. Default 0.5 sec.
|
||||
-- @field #number dt01 Time step [sec] for missile position updates if distance to target > 1 km and < 5 km. Default 0.1 sec.
|
||||
-- @field #number dt00 Time step [sec] for missile position updates if distance to target < 1 km. Default 0.01 sec.
|
||||
-- @field #boolean
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- Fox 3!
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
--
|
||||
-- @module Functional.Mantis
|
||||
-- @image Functional.Mantis.jpg
|
||||
|
||||
-- Date: July 2021
|
||||
--
|
||||
-- Date: Nov 2021
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
--- **MANTIS** class, extends Core.Base#BASE
|
||||
@@ -101,23 +101,23 @@
|
||||
--
|
||||
-- # 2. Start up your MANTIS with a basic setting
|
||||
--
|
||||
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)`
|
||||
-- `myredmantis:Start()`
|
||||
-- myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)
|
||||
-- myredmantis:Start()
|
||||
--
|
||||
-- [optional] Use
|
||||
--
|
||||
-- * `MANTIS:SetEWRGrouping(radius)`
|
||||
-- * `MANTIS:SetEWRRange(radius)`
|
||||
-- * `MANTIS:SetSAMRadius(radius)`
|
||||
-- * `MANTIS:SetDetectInterval(interval)`
|
||||
-- * `MANTIS:SetAutoRelocate(hq, ewr)`
|
||||
-- * MANTIS:SetEWRGrouping(radius)
|
||||
-- * MANTIS:SetEWRRange(radius)
|
||||
-- * MANTIS:SetSAMRadius(radius)
|
||||
-- * MANTIS:SetDetectInterval(interval)
|
||||
-- * MANTIS:SetAutoRelocate(hq, ewr)
|
||||
--
|
||||
-- before starting #MANTIS to fine-tune your setup.
|
||||
--
|
||||
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
|
||||
--
|
||||
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
|
||||
-- `mybluemantis:Start()`
|
||||
-- mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||
-- mybluemantis:Start()
|
||||
--
|
||||
-- # 3. Default settings
|
||||
--
|
||||
@@ -138,7 +138,7 @@
|
||||
--
|
||||
-- Advanced mode will *decrease* reactivity of MANTIS, if HQ and/or EWR network dies. Awacs is counted as one EWR unit. It will set SAMs to RED state if both are dead. Requires usage of an **HQ** object and the **dynamic** option.
|
||||
--
|
||||
-- E.g. `mymantis:SetAdvancedMode( true, 90 )`
|
||||
-- E.g. mymantis:SetAdvancedMode( true, 90 )
|
||||
--
|
||||
-- Use this option if you want to make use of or allow advanced SEAD tactics.
|
||||
--
|
||||
@@ -147,16 +147,39 @@
|
||||
-- You can also choose to integrate Mantis with @{Functional.Shorad#SHORAD} for protection against HARMs and AGMs. When SHORAD detects a missile fired at one of MANTIS' SAM sites, it will activate SHORAD systems in
|
||||
-- the given defense checkradius around that SAM site. Create a SHORAD object first, then integrate with MANTIS like so:
|
||||
--
|
||||
-- `local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()`
|
||||
-- `myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")`
|
||||
-- `-- now set up MANTIS`
|
||||
-- `mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
|
||||
-- `mymantis:AddShorad(myshorad,720)`
|
||||
-- `mymantis:Start()`
|
||||
-- local SamSet = SET_GROUP:New():FilterPrefixes("Blue SAM"):FilterCoalitions("blue"):FilterStart()
|
||||
-- myshorad = SHORAD:New("BlueShorad", "Blue SHORAD", SamSet, 22000, 600, "blue")
|
||||
-- -- now set up MANTIS
|
||||
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||
-- mymantis:AddShorad(myshorad,720)
|
||||
-- mymantis:Start()
|
||||
--
|
||||
-- and (optionally) remove the link later on with
|
||||
--
|
||||
-- `mymantis:RemoveShorad()`
|
||||
-- mymantis:RemoveShorad()
|
||||
--
|
||||
-- # 6. Integrated SEAD
|
||||
--
|
||||
-- MANTIS is using @{Functional.Sead#SEAD} internally to both detect and evade HARM attacks. No extra efforts needed to set this up!
|
||||
-- Once a HARM attack is detected, MANTIS (via SEAD) will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
||||
-- vehicles around (*if they are __drivable__*, that is). There's a component of randomness in detection and evasion, which is based on the
|
||||
-- skill set of the SAM set (the higher the skill, the more likely). When a missile is fired from far away, the SAM will stay active for a
|
||||
-- period of time to stay defensive, before it takes evasive actions.
|
||||
--
|
||||
-- You can link into the SEAD driven events of MANTIS like so:
|
||||
--
|
||||
-- function mymantis:OnAfterSeadSuppressionPlanned(From, Event, To, Group, Name, SuppressionStartTime, SuppressionEndTime)
|
||||
-- -- your code here - SAM site shutdown and evasion planned, but not yet executed
|
||||
-- -- Time entries relate to timer.getTime() - see https://wiki.hoggitworld.com/view/DCS_func_getTime
|
||||
-- end
|
||||
--
|
||||
-- function mymantis:OnAfterSeadSuppressionStart(From, Event, To, Group, Name)
|
||||
-- -- your code here - SAM site is emissions off and possibly moving
|
||||
-- end
|
||||
--
|
||||
-- function mymantis:OnAfterSeadSuppressionEnd(From, Event, To, Group, Name)
|
||||
-- -- your code here - SAM site is back online
|
||||
-- end
|
||||
--
|
||||
-- @field #MANTIS
|
||||
MANTIS = {
|
||||
@@ -198,6 +221,7 @@ MANTIS = {
|
||||
DLink = false,
|
||||
DLTimeStamp = 0,
|
||||
Padding = 10,
|
||||
SuppressedGroups = {},
|
||||
}
|
||||
|
||||
--- Advanced state enumerator
|
||||
@@ -227,23 +251,23 @@ do
|
||||
--@return #MANTIS self
|
||||
--@usage Start up your MANTIS with a basic setting
|
||||
--
|
||||
-- `myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)`
|
||||
-- `myredmantis:Start()`
|
||||
-- myredmantis = MANTIS:New("myredmantis","Red SAM","Red EWR",nil,"red",false)
|
||||
-- myredmantis:Start()
|
||||
--
|
||||
-- [optional] Use
|
||||
--
|
||||
-- * `MANTIS:SetEWRGrouping(radius)`
|
||||
-- * `MANTIS:SetEWRRange(radius)`
|
||||
-- * `MANTIS:SetSAMRadius(radius)`
|
||||
-- * `MANTIS:SetDetectInterval(interval)`
|
||||
-- * `MANTIS:SetAutoRelocate(hq, ewr)`
|
||||
-- * MANTIS:SetEWRGrouping(radius)
|
||||
-- * MANTIS:SetEWRRange(radius)
|
||||
-- * MANTIS:SetSAMRadius(radius)
|
||||
-- * MANTIS:SetDetectInterval(interval)
|
||||
-- * MANTIS:SetAutoRelocate(hq, ewr)
|
||||
--
|
||||
-- before starting #MANTIS to fine-tune your setup.
|
||||
--
|
||||
-- If you want to use a separate AWACS unit (default detection range: 250km) to support your EWR system, use e.g. the following setup:
|
||||
--
|
||||
-- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")`
|
||||
-- `mybluemantis:Start()`
|
||||
-- mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||
-- mybluemantis:Start()
|
||||
--
|
||||
function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, EmOnOff, Padding)
|
||||
|
||||
@@ -284,6 +308,7 @@ do
|
||||
self.SamStateTracker = {} -- table to hold alert states, so we don't trigger state changes twice in adv mode
|
||||
self.DLink = false
|
||||
self.Padding = Padding or 10
|
||||
self.SuppressedGroups = {}
|
||||
|
||||
if EmOnOff then
|
||||
if EmOnOff == false then
|
||||
@@ -331,7 +356,7 @@ do
|
||||
end
|
||||
|
||||
-- @field #string version
|
||||
self.version="0.6.2"
|
||||
self.version="0.7.1"
|
||||
self:I(string.format("***** Starting MANTIS Version %s *****", self.version))
|
||||
|
||||
--- FSM Functions ---
|
||||
@@ -340,15 +365,18 @@ do
|
||||
self:SetStartState("Stopped")
|
||||
|
||||
-- Add FSM transitions.
|
||||
-- From State --> Event --> To State
|
||||
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
|
||||
self:AddTransition("*", "Status", "*") -- MANTIS status update.
|
||||
self:AddTransition("*", "Relocating", "*") -- MANTIS HQ and EWR are relocating.
|
||||
self:AddTransition("*", "GreenState", "*") -- MANTIS A SAM switching to GREEN state.
|
||||
self:AddTransition("*", "RedState", "*") -- MANTIS A SAM switching to RED state.
|
||||
self:AddTransition("*", "AdvStateChange", "*") -- MANTIS advanced mode state change.
|
||||
self:AddTransition("*", "ShoradActivated", "*") -- MANTIS woke up a connected SHORAD.
|
||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||
-- From State --> Event --> To State
|
||||
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
|
||||
self:AddTransition("*", "Status", "*") -- MANTIS status update.
|
||||
self:AddTransition("*", "Relocating", "*") -- MANTIS HQ and EWR are relocating.
|
||||
self:AddTransition("*", "GreenState", "*") -- MANTIS A SAM switching to GREEN state.
|
||||
self:AddTransition("*", "RedState", "*") -- MANTIS A SAM switching to RED state.
|
||||
self:AddTransition("*", "AdvStateChange", "*") -- MANTIS advanced mode state change.
|
||||
self:AddTransition("*", "ShoradActivated", "*") -- MANTIS woke up a connected SHORAD.
|
||||
self:AddTransition("*", "SeadSuppressionStart", "*") -- SEAD has switched off one group.
|
||||
self:AddTransition("*", "SeadSuppressionEnd", "*") -- SEAD has switched on one group.
|
||||
self:AddTransition("*", "SeadSuppressionPlanned", "*") -- SEAD has planned a suppression.
|
||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
@@ -427,6 +455,35 @@ do
|
||||
-- @param #number Radius Radius around the named group to find SHORAD groups
|
||||
-- @param #number Ontime Seconds the SHORAD will stay active
|
||||
|
||||
--- On After "SeadSuppressionPlanned" event. Mantis has planned to switch off a site to defend SEAD attack.
|
||||
-- @function [parent=#MANTIS] OnAfterSeadSuppressionPlanned
|
||||
-- @param #MANTIS self
|
||||
-- @param #string From The From State
|
||||
-- @param #string Event The Event
|
||||
-- @param #string To The To State
|
||||
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
|
||||
-- @param #string Name Name of the suppressed group
|
||||
-- @param #number SuppressionStartTime Model start time of the suppression from `timer.getTime()`
|
||||
-- @param #number SuppressionEndTime Model end time of the suppression from `timer.getTime()`
|
||||
|
||||
--- On After "SeadSuppressionStart" event. Mantis has switched off a site to defend a SEAD attack.
|
||||
-- @function [parent=#MANTIS] OnAfterSeadSuppressionStart
|
||||
-- @param #MANTIS self
|
||||
-- @param #string From The From State
|
||||
-- @param #string Event The Event
|
||||
-- @param #string To The To State
|
||||
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
|
||||
-- @param #string Name Name of the suppressed groupe
|
||||
|
||||
--- On After "SeadSuppressionEnd" event. Mantis has switched on a site after a SEAD attack.
|
||||
-- @function [parent=#MANTIS] OnAfterSeadSuppressionEnd
|
||||
-- @param #MANTIS self
|
||||
-- @param #string From The From State
|
||||
-- @param #string Event The Event
|
||||
-- @param #string To The To State
|
||||
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
|
||||
-- @param #string Name Name of the suppressed group
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -625,7 +682,7 @@ do
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set using an #INTEL_DLINK object instead of #DETECTION. Requires Develop branch of Moose.lua.
|
||||
--- Set using an #INTEL_DLINK object instead of #DETECTION
|
||||
-- @param #MANTIS self
|
||||
-- @param Ops.Intelligence#INTEL_DLINK DLink The data link object to be used.
|
||||
function MANTIS:SetUsingDLink(DLink)
|
||||
@@ -891,6 +948,7 @@ do
|
||||
local group = _group -- Wrapper.Group#GROUP
|
||||
-- TODO: add emissions on/off
|
||||
if self.UseEmOnOff then
|
||||
group:OptionAlarmStateRed()
|
||||
group:EnableEmission(false)
|
||||
--group:SetAIOff()
|
||||
else
|
||||
@@ -909,6 +967,10 @@ do
|
||||
-- make SAMs evasive
|
||||
local mysead = SEAD:New( SEAD_Grps, self.Padding ) -- Functional.Sead#SEAD
|
||||
mysead:SetEngagementRange(engagerange)
|
||||
mysead:AddCallBack(self)
|
||||
if self.UseEmOnOff then
|
||||
mysead:SwitchEmissions(true)
|
||||
end
|
||||
self.mysead = mysead
|
||||
return self
|
||||
end
|
||||
@@ -995,22 +1057,24 @@ do
|
||||
local name = _data[1]
|
||||
local samgroup = GROUP:FindByName(name)
|
||||
local IsInZone, Distance = self:CheckObjectInZone(detset, samcoordinate)
|
||||
if IsInZone then --check any target in zone
|
||||
local suppressed = self.SuppressedGroups[name] or false
|
||||
if IsInZone then --check any target in zone and not curr managed by SEAD
|
||||
if samgroup:IsAlive() then
|
||||
-- switch on SAM
|
||||
if self.UseEmOnOff then
|
||||
-- TODO: add emissions on/off
|
||||
if self.UseEmOnOff and not suppressed then
|
||||
-- DONE: add emissions on/off
|
||||
--samgroup:SetAIOn()
|
||||
samgroup:EnableEmission(true)
|
||||
elseif not self.UseEmOnOff and not suppressed then
|
||||
samgroup:OptionAlarmStateRed()
|
||||
end
|
||||
samgroup:OptionAlarmStateRed()
|
||||
if self.SamStateTracker[name] ~= "RED" then
|
||||
if self.SamStateTracker[name] ~= "RED" and not suppressed then
|
||||
self:__RedState(1,samgroup)
|
||||
self.SamStateTracker[name] = "RED"
|
||||
end
|
||||
-- link in to SHORAD if available
|
||||
-- DONE: Test integration fully
|
||||
if self.ShoradLink and Distance < self.ShoradActDistance then -- don't give SHORAD position away too early
|
||||
if self.ShoradLink and (Distance < self.ShoradActDistance or suppressed) then -- don't give SHORAD position away too early
|
||||
local Shorad = self.Shorad
|
||||
local radius = self.checkradius
|
||||
local ontime = self.ShoradTime
|
||||
@@ -1018,7 +1082,7 @@ do
|
||||
self:__ShoradActivated(1,name, radius, ontime)
|
||||
end
|
||||
-- debug output
|
||||
if self.debug or self.verbose then
|
||||
if self.debug or self.verbose and not suppressed then
|
||||
local text = string.format("SAM %s switched to alarm state RED!", name)
|
||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||
if self.verbose then self:I(self.lid..text) end
|
||||
@@ -1027,15 +1091,16 @@ do
|
||||
else
|
||||
if samgroup:IsAlive() then
|
||||
-- switch off SAM
|
||||
if self.UseEmOnOff then
|
||||
if self.UseEmOnOff and not suppressed then
|
||||
samgroup:EnableEmission(false)
|
||||
end
|
||||
elseif not self.UseEmOnOff and not suppressed then
|
||||
samgroup:OptionAlarmStateGreen()
|
||||
if self.SamStateTracker[name] ~= "GREEN" then
|
||||
self:__GreenState(1,samgroup)
|
||||
self.SamStateTracker[name] = "GREEN"
|
||||
end
|
||||
if self.debug or self.verbose then
|
||||
end
|
||||
if self.SamStateTracker[name] ~= "GREEN" and not suppressed then
|
||||
self:__GreenState(1,samgroup)
|
||||
self.SamStateTracker[name] = "GREEN"
|
||||
end
|
||||
if self.debug or self.verbose and not suppressed then
|
||||
local text = string.format("SAM %s switched to alarm state GREEN!", name)
|
||||
local m=MESSAGE:New(text,10,"MANTIS"):ToAllIf(self.debug)
|
||||
if self.verbose then self:I(self.lid..text) end
|
||||
@@ -1264,6 +1329,47 @@ do
|
||||
self:T({From, Event, To, Name, Radius, Ontime})
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Internal] Function triggered by Event SeadSuppressionStart
|
||||
-- @param #MANTIS self
|
||||
-- @param #string From The From State
|
||||
-- @param #string Event The Event
|
||||
-- @param #string To The To State
|
||||
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
|
||||
-- @param #string Name Name of the suppressed group
|
||||
function MANTIS:onafterSeadSuppressionStart(From, Event, To, Group, Name)
|
||||
self:T({From, Event, To, Name})
|
||||
self.SuppressedGroups[Name] = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Internal] Function triggered by Event SeadSuppressionEnd
|
||||
-- @param #MANTIS self
|
||||
-- @param #string From The From State
|
||||
-- @param #string Event The Event
|
||||
-- @param #string To The To State
|
||||
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
|
||||
-- @param #string Name Name of the suppressed group
|
||||
function MANTIS:onafterSeadSuppressionEnd(From, Event, To, Group, Name)
|
||||
self:T({From, Event, To, Name})
|
||||
self.SuppressedGroups[Name] = false
|
||||
return self
|
||||
end
|
||||
|
||||
--- [Internal] Function triggered by Event SeadSuppressionPlanned
|
||||
-- @param #MANTIS self
|
||||
-- @param #string From The From State
|
||||
-- @param #string Event The Event
|
||||
-- @param #string To The To State
|
||||
-- @param Wrapper.Group#GROUP Group The suppressed GROUP object
|
||||
-- @param #string Name Name of the suppressed group
|
||||
-- @param #number SuppressionStartTime Model start time of the suppression from `timer.getTime()`
|
||||
-- @param #number SuppressionEndTime Model end time of the suppression from `timer.getTime()`
|
||||
function MANTIS:onafterSeadSuppressionPlanned(From, Event, To, Group, Name, SuppressionStartTime, SuppressionEndTime)
|
||||
self:T({From, Event, To, Name})
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
-----------------------------------------------------------------------
|
||||
-- MANTIS end
|
||||
|
||||
@@ -742,7 +742,7 @@ function PSEUDOATC:ReportWeather(GID, UID, position, location)
|
||||
local T=position:GetTemperature()
|
||||
|
||||
-- Correct unit system.
|
||||
local _T=string.format('%d°F', UTILS.CelciusToFarenheit(T))
|
||||
local _T=string.format('%d°F', UTILS.CelsiusToFahrenheit(T))
|
||||
if settings:IsMetric() then
|
||||
_T=string.format('%d°C', T)
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,8 @@
|
||||
--
|
||||
-- * When SAM sites are being fired upon, the SAMs will take evasive action will reposition themselves when possible.
|
||||
-- * When SAM sites are being fired upon, the SAMs will take defensive action by shutting down their radars.
|
||||
-- * SEAD calculates the time it takes for a HARM to reach the target - and will attempt to minimize the shut-down time.
|
||||
-- * Detection and evasion of shots has a random component based on the skill level of the SAM groups.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -17,7 +19,7 @@
|
||||
--
|
||||
-- ### Authors: **FlightControl**, **applevangelist**
|
||||
--
|
||||
-- Last Update: Aug 2021
|
||||
-- Last Update: Nov 2021
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@@ -31,6 +33,10 @@
|
||||
--- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
||||
--
|
||||
-- This class is very easy to use. Just setup a SEAD object by using @{#SEAD.New}() and SAMs will evade and take defensive action when being fired upon.
|
||||
-- Once a HARM attack is detected, SEAD will shut down the radars of the attacked SAM site and take evasive action by moving the SAM
|
||||
-- vehicles around (*if* they are drivable, that is). There's a component of randomness in detection and evasion, which is based on the
|
||||
-- skill set of the SAM set (the higher the skill, the more likely). When a missile is fired from far away, the SAM will stay active for a
|
||||
-- period of time to stay defensive, before it takes evasive actions.
|
||||
--
|
||||
-- # Constructor:
|
||||
--
|
||||
@@ -51,6 +57,8 @@ SEAD = {
|
||||
SuppressedGroups = {},
|
||||
EngagementRange = 75, -- default 75% engagement range Feature Request #1355
|
||||
Padding = 10,
|
||||
CallBack = nil,
|
||||
UseCallBack = false,
|
||||
}
|
||||
|
||||
--- Missile enumerators
|
||||
@@ -93,7 +101,7 @@ SEAD = {
|
||||
-- @param #SEAD self
|
||||
-- @param #table SEADGroupPrefixes Table of #string entries or single #string, which is a table of Prefixes of the SA Groups in the DCS mission editor on which evasive actions need to be taken.
|
||||
-- @param #number Padding (Optional) Extra number of seconds to add to radar switch-back-on time
|
||||
-- @return SEAD
|
||||
-- @return #SEAD self
|
||||
-- @usage
|
||||
-- -- CCCP SEAD Defenses
|
||||
-- -- Defends the Russian SA installations from SEAD attacks.
|
||||
@@ -114,14 +122,18 @@ function SEAD:New( SEADGroupPrefixes, Padding )
|
||||
local padding = Padding or 10
|
||||
if padding < 10 then padding = 10 end
|
||||
self.Padding = padding
|
||||
self.UseEmissionsOnOff = false
|
||||
|
||||
self.CallBack = nil
|
||||
self.UseCallBack = false
|
||||
|
||||
self:HandleEvent( EVENTS.Shot, self.HandleEventShot )
|
||||
|
||||
self:I("*** SEAD - Started Version 0.3.1")
|
||||
self:I("*** SEAD - Started Version 0.3.3")
|
||||
return self
|
||||
end
|
||||
|
||||
--- Update the active SEAD Set
|
||||
--- Update the active SEAD Set (while running)
|
||||
-- @param #SEAD self
|
||||
-- @param #table SEADGroupPrefixes The prefixes to add, note: can also be a single #string
|
||||
-- @return #SEAD self
|
||||
@@ -142,8 +154,8 @@ end
|
||||
|
||||
--- Sets the engagement range of the SAMs. Defaults to 75% to make it more deadly. Feature Request #1355
|
||||
-- @param #SEAD self
|
||||
-- @param #number range Set the engagement range in percent, e.g. 50
|
||||
-- @return self
|
||||
-- @param #number range Set the engagement range in percent, e.g. 55 (default 75)
|
||||
-- @return #SEAD self
|
||||
function SEAD:SetEngagementRange(range)
|
||||
self:T( { range } )
|
||||
range = range or 75
|
||||
@@ -157,7 +169,8 @@ end
|
||||
|
||||
--- Set the padding in seconds, which extends the radar off time calculated by SEAD
|
||||
-- @param #SEAD self
|
||||
-- @param #number Padding Extra number of seconds to add for the switch-on
|
||||
-- @param #number Padding Extra number of seconds to add for the switch-on (default 10 seconds)
|
||||
-- @return #SEAD self
|
||||
function SEAD:SetPadding(Padding)
|
||||
self:T( { Padding } )
|
||||
local padding = Padding or 10
|
||||
@@ -166,56 +179,80 @@ function SEAD:SetPadding(Padding)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Check if a known HARM was fired
|
||||
-- @param #SEAD self
|
||||
-- @param #string WeaponName
|
||||
-- @return #boolean Returns true for a match
|
||||
-- @return #string name Name of hit in table
|
||||
function SEAD:_CheckHarms(WeaponName)
|
||||
self:T( { WeaponName } )
|
||||
local hit = false
|
||||
local name = ""
|
||||
for _,_name in pairs (SEAD.Harms) do
|
||||
if string.find(WeaponName,_name,1) then
|
||||
hit = true
|
||||
name = _name
|
||||
break
|
||||
end
|
||||
end
|
||||
return hit, name
|
||||
end
|
||||
--- Set SEAD to use emissions on/off in addition to alarm state.
|
||||
-- @param #SEAD self
|
||||
-- @param #boolean Switch True for on, false for off.
|
||||
-- @return #SEAD self
|
||||
function SEAD:SwitchEmissions(Switch)
|
||||
self:T({Switch})
|
||||
self.UseEmissionsOnOff = Switch
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal) Return distance in meters between two coordinates or -1 on error.
|
||||
-- @param #SEAD self
|
||||
-- @param Core.Point#COORDINATE _point1 Coordinate one
|
||||
-- @param Core.Point#COORDINATE _point2 Coordinate two
|
||||
-- @return #number Distance in meters
|
||||
function SEAD:_GetDistance(_point1, _point2)
|
||||
self:T("_GetDistance")
|
||||
if _point1 and _point2 then
|
||||
local distance1 = _point1:Get2DDistance(_point2)
|
||||
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
||||
--self:T({dist1=distance1, dist2=distance2})
|
||||
if distance1 and type(distance1) == "number" then
|
||||
return distance1
|
||||
elseif distance2 and type(distance2) == "number" then
|
||||
return distance2
|
||||
else
|
||||
self:E("*****Cannot calculate distance!")
|
||||
self:E({_point1,_point2})
|
||||
return -1
|
||||
--- Add an object to call back when going evasive.
|
||||
-- @param #SEAD self
|
||||
-- @param #table Object The object to call. Needs to have object functions as follows:
|
||||
-- `:SeadSuppressionPlanned(Group, Name, SuppressionStartTime, SuppressionEndTime)`
|
||||
-- `:SeadSuppressionStart(Group, Name)`,
|
||||
-- `:SeadSuppressionEnd(Group, Name)`,
|
||||
-- @return #SEAD self
|
||||
function SEAD:AddCallBack(Object)
|
||||
self:T({Class=Object.ClassName})
|
||||
self.CallBack = Object
|
||||
self.UseCallBack = true
|
||||
return self
|
||||
end
|
||||
|
||||
--- (Internal) Check if a known HARM was fired
|
||||
-- @param #SEAD self
|
||||
-- @param #string WeaponName
|
||||
-- @return #boolean Returns true for a match
|
||||
-- @return #string name Name of hit in table
|
||||
function SEAD:_CheckHarms(WeaponName)
|
||||
self:T( { WeaponName } )
|
||||
local hit = false
|
||||
local name = ""
|
||||
for _,_name in pairs (SEAD.Harms) do
|
||||
if string.find(WeaponName,_name,1) then
|
||||
hit = true
|
||||
name = _name
|
||||
break
|
||||
end
|
||||
end
|
||||
return hit, name
|
||||
end
|
||||
|
||||
--- (Internal) Return distance in meters between two coordinates or -1 on error.
|
||||
-- @param #SEAD self
|
||||
-- @param Core.Point#COORDINATE _point1 Coordinate one
|
||||
-- @param Core.Point#COORDINATE _point2 Coordinate two
|
||||
-- @return #number Distance in meters
|
||||
function SEAD:_GetDistance(_point1, _point2)
|
||||
self:T("_GetDistance")
|
||||
if _point1 and _point2 then
|
||||
local distance1 = _point1:Get2DDistance(_point2)
|
||||
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
||||
--self:T({dist1=distance1, dist2=distance2})
|
||||
if distance1 and type(distance1) == "number" then
|
||||
return distance1
|
||||
elseif distance2 and type(distance2) == "number" then
|
||||
return distance2
|
||||
else
|
||||
self:E("******Cannot calculate distance!")
|
||||
self:E("*****Cannot calculate distance!")
|
||||
self:E({_point1,_point2})
|
||||
return -1
|
||||
end
|
||||
else
|
||||
self:E("******Cannot calculate distance!")
|
||||
self:E({_point1,_point2})
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
--- Detects if an SAM 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
|
||||
-- @param #SEAD
|
||||
--- (Internal) Detects if an SAM site was shot with an anti radiation missile. In this case, take evasive actions based on the skill level set within the ME.
|
||||
-- @param #SEAD self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
-- @return #SEAD self
|
||||
function SEAD:HandleEventShot( EventData )
|
||||
self:T( { EventData.id } )
|
||||
local SEADPlane = EventData.IniUnit -- Wrapper.Unit#UNIT
|
||||
@@ -245,7 +282,7 @@ function SEAD:HandleEventShot( EventData )
|
||||
-- see if we are shot at
|
||||
local SEADGroupFound = false
|
||||
for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do
|
||||
self:T( SEADGroupPrefix )
|
||||
self:T( _targetgroupname, SEADGroupPrefix )
|
||||
if string.find( _targetgroupname, SEADGroupPrefix, 1, true ) then
|
||||
SEADGroupFound = true
|
||||
self:T( '*** SEAD - Group Match Found' )
|
||||
@@ -291,16 +328,32 @@ function SEAD:HandleEventShot( EventData )
|
||||
local function SuppressionStart(args)
|
||||
self:T(string.format("*** SEAD - %s Radar Off & Relocating",args[2]))
|
||||
local grp = args[1] -- Wrapper.Group#GROUP
|
||||
grp:OptionAlarmStateGreen()
|
||||
local name = args[2] -- #string Group Name
|
||||
if self.UseEmissionsOnOff then
|
||||
grp:EnableEmission(false)
|
||||
end
|
||||
grp:OptionAlarmStateGreen() -- needed else we cannot move around
|
||||
grp:RelocateGroundRandomInRadius(20,300,false,false,"Diamond")
|
||||
if self.UseCallBack then
|
||||
local object = self.CallBack
|
||||
object:SeadSuppressionStart(grp,name)
|
||||
end
|
||||
end
|
||||
|
||||
local function SuppressionStop(args)
|
||||
self:T(string.format("*** SEAD - %s Radar On",args[2]))
|
||||
local grp = args[1] -- Wrapper.Group#GROUP
|
||||
grp:OptionAlarmStateRed()
|
||||
local name = args[2] -- #string Group Nam
|
||||
if self.UseEmissionsOnOff then
|
||||
grp:EnableEmission(true)
|
||||
end
|
||||
grp:OptionAlarmStateAuto()
|
||||
grp:OptionEngageRange(self.EngagementRange)
|
||||
self.SuppressedGroups[args[2]] = false
|
||||
self.SuppressedGroups[name] = false
|
||||
if self.UseCallBack then
|
||||
local object = self.CallBack
|
||||
object:SeadSuppressionEnd(grp,name)
|
||||
end
|
||||
end
|
||||
|
||||
-- randomize switch-on time
|
||||
@@ -316,6 +369,10 @@ function SEAD:HandleEventShot( EventData )
|
||||
timer.scheduleFunction(SuppressionStart,{_targetgroup,_targetgroupname},SuppressionStartTime)
|
||||
timer.scheduleFunction(SuppressionStop,{_targetgroup,_targetgroupname},SuppressionEndTime)
|
||||
self.SuppressedGroups[_targetgroupname] = true
|
||||
if self.UseCallBack then
|
||||
local object = self.CallBack
|
||||
object:SeadSuppressionPlanned(_targetgroup,_targetgroupname,SuppressionStartTime,SuppressionEndTime)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -323,4 +380,5 @@ function SEAD:HandleEventShot( EventData )
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1601,7 +1601,7 @@ WAREHOUSE = {
|
||||
-- @field #number range Range of the unit in meters.
|
||||
-- @field #number speedmax Maximum speed in km/h the group can do.
|
||||
-- @field #number size Maximum size in length and with of the asset in meters.
|
||||
-- @field #number weight The weight of the whole asset group in kilo gramms.
|
||||
-- @field #number weight The weight of the whole asset group in kilograms.
|
||||
-- @field DCS#Object.Desc DCSdesc All DCS descriptors.
|
||||
-- @field #WAREHOUSE.Attribute attribute Generalized attribute of the group.
|
||||
-- @field #table cargobay Array of cargo bays of all units in an asset group.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -802,7 +802,7 @@ function RESCUEHELO:_OnEventCrashOrEject(EventData)
|
||||
-- Debug.
|
||||
local text=string.format("Unit %s crashed or ejected.", unitname)
|
||||
MESSAGE:New(text, 10, "DEBUG"):ToAllIf(self.Debug)
|
||||
self:I(self.lid..text)
|
||||
self:T(self.lid..text)
|
||||
|
||||
-- Get coordinate of unit.
|
||||
local coord=unit:GetCoordinate()
|
||||
|
||||
@@ -88,10 +88,19 @@
|
||||
--
|
||||
-- Use a specific "culture" with the @{#MSRS.SetCulture} function, e.g. `:SetCulture("en-US")` or `:SetCulture("de-DE")`.
|
||||
--
|
||||
-- ## Set Google
|
||||
--
|
||||
-- Use Google's text-to-speech engine with the @{#MSRS.SetGoogle} function, e.g. ':SetGoogle()'.
|
||||
-- By enabling this it also allows you to utilize SSML in your text for added flexibilty.
|
||||
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
|
||||
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
|
||||
--
|
||||
-- ## Set Voice
|
||||
--
|
||||
-- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
|
||||
-- Note that this must be installed on your windows system.
|
||||
-- If enabling SetGoogle(), you can use voices provided by Google
|
||||
-- Google's supported voices: https://cloud.google.com/text-to-speech/docs/voices
|
||||
--
|
||||
-- ## Set Coordinate
|
||||
--
|
||||
@@ -678,7 +687,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
||||
|
||||
-- Set google.
|
||||
if self.google then
|
||||
command=command..string.format(' -G "%s"', self.google)
|
||||
command=command..string.format(' --ssml -G "%s"', self.google)
|
||||
end
|
||||
|
||||
-- Debug output.
|
||||
|
||||
@@ -38,7 +38,7 @@ do -- TASK_A2A
|
||||
--
|
||||
-- @field #TASK_A2A
|
||||
TASK_A2A = {
|
||||
ClassName = "TASK_A2A",
|
||||
ClassName = "TASK_A2A"
|
||||
}
|
||||
|
||||
--- Instantiates a new TASK_A2A.
|
||||
@@ -60,29 +60,27 @@ do -- TASK_A2A
|
||||
|
||||
local Fsm = self:GetUnitProcess()
|
||||
|
||||
|
||||
Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" )
|
||||
Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } )
|
||||
Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } )
|
||||
Fsm:AddProcess( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } )
|
||||
Fsm:AddProcess( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } )
|
||||
|
||||
Fsm:AddTransition( { "Arrived", "RoutingToRendezVous" }, "ArriveAtRendezVous", "ArrivedAtRendezVous" )
|
||||
|
||||
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" )
|
||||
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" )
|
||||
|
||||
Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} )
|
||||
Fsm:AddProcess( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} )
|
||||
Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" )
|
||||
Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} )
|
||||
Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} )
|
||||
Fsm:AddTransition( "Engaging", "RouteToTargets", "Engaging" )
|
||||
|
||||
-- Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" )
|
||||
-- Fsm:AddTransition( "Accounted", "Success", "Success" )
|
||||
-- Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" )
|
||||
-- Fsm:AddTransition( "Accounted", "Success", "Success" )
|
||||
Fsm:AddTransition( "Rejected", "Reject", "Aborted" )
|
||||
Fsm:AddTransition( "Failed", "Fail", "Failed" )
|
||||
|
||||
|
||||
---- @param #FSM_PROCESS self
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param #TASK_CARGO Task
|
||||
function Fsm:OnLeaveAssigned( TaskUnit, Task )
|
||||
@@ -128,7 +126,7 @@ do -- TASK_A2A
|
||||
function Fsm:onafterEngage( TaskUnit, Task )
|
||||
self:F( { self } )
|
||||
self:__Account( 0.1 )
|
||||
self:__RouteToTarget(0.1 )
|
||||
self:__RouteToTarget( 0.1 )
|
||||
self:__RouteToTargets( -10 )
|
||||
end
|
||||
|
||||
@@ -177,8 +175,6 @@ do -- TASK_A2A
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #TASK_A2A self
|
||||
function TASK_A2A:GetPlannedMenuText()
|
||||
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
|
||||
@@ -188,7 +184,7 @@ do -- TASK_A2A
|
||||
-- @param Core.Point#COORDINATE RendezVousCoordinate The Coordinate object referencing to the 2D point where the RendezVous point is located on the map.
|
||||
-- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point.
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
function TASK_A2A:SetRendezVousCoordinate( RendezVousCoordinate, RendezVousRange, TaskUnit )
|
||||
function TASK_A2A:SetRendezVousCoordinate( RendezVousCoordinate, RendezVousRange, TaskUnit )
|
||||
|
||||
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
||||
|
||||
@@ -209,8 +205,6 @@ do -- TASK_A2A
|
||||
return ActRouteRendezVous:GetCoordinate(), ActRouteRendezVous:GetRange()
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #TASK_A2A self
|
||||
-- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map.
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
@@ -244,7 +238,6 @@ do -- TASK_A2A
|
||||
ActRouteTarget:SetCoordinate( TargetCoordinate )
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2A self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @return Core.Point#COORDINATE The Coordinate object where the Target is located on the map.
|
||||
@@ -256,7 +249,6 @@ do -- TASK_A2A
|
||||
return ActRouteTarget:GetCoordinate()
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2A self
|
||||
-- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map.
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
@@ -268,7 +260,6 @@ do -- TASK_A2A
|
||||
ActRouteTarget:SetZone( TargetZone, Altitude, Heading )
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2A self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
|
||||
@@ -293,7 +284,7 @@ do -- TASK_A2A
|
||||
--- Return the relative distance to the target vicinity from the player, in order to sort the targets in the reports per distance from the threats.
|
||||
-- @param #TASK_A2A self
|
||||
function TASK_A2A:ReportOrder( ReportGroup )
|
||||
self:UpdateTaskInfo( self.DetectedItem )
|
||||
self:UpdateTaskInfo( self.DetectedItem )
|
||||
|
||||
local Coordinate = self.TaskInfo:GetData( "Coordinate" )
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
@@ -301,7 +292,6 @@ do -- TASK_A2A
|
||||
return Distance
|
||||
end
|
||||
|
||||
|
||||
--- This method checks every 10 seconds if the goal has been reached of the task.
|
||||
-- @param #TASK_A2A self
|
||||
function TASK_A2A:onafterGoal( TaskUnit, From, Event, To )
|
||||
@@ -314,7 +304,6 @@ do -- TASK_A2A
|
||||
self:__Goal( -10 )
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2A self
|
||||
function TASK_A2A:UpdateTaskInfo( DetectedItem )
|
||||
|
||||
@@ -360,7 +349,7 @@ do -- TASK_A2A
|
||||
-- @param Wrapper.Group#GROUP TaskGroup The player group.
|
||||
function TASK_A2A:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup )
|
||||
|
||||
if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then
|
||||
if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then
|
||||
return math.random( 1, 9 )
|
||||
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then
|
||||
local Coordinate = self.TaskInfo:GetData( "Coordinate" )
|
||||
@@ -375,7 +364,6 @@ do -- TASK_A2A
|
||||
|
||||
end
|
||||
|
||||
|
||||
do -- TASK_A2A_INTERCEPT
|
||||
|
||||
--- The TASK_A2A_INTERCEPT class
|
||||
@@ -384,7 +372,7 @@ do -- TASK_A2A_INTERCEPT
|
||||
-- @extends Tasking.Task#TASK
|
||||
|
||||
--- Defines an intercept task for a human player to be executed.
|
||||
-- When enemy planes need to be intercepted by human players, use this task type to urgen the players to get out there!
|
||||
-- When enemy planes need to be intercepted by human players, use this task type to urge the players to get out there!
|
||||
--
|
||||
-- The TASK_A2A_INTERCEPT is used by the @{Tasking.Task_A2A_Dispatcher#TASK_A2A_DISPATCHER} to automatically create intercept tasks
|
||||
-- based on detected airborne enemy targets intruding friendly airspace.
|
||||
@@ -394,11 +382,9 @@ do -- TASK_A2A_INTERCEPT
|
||||
--
|
||||
-- @field #TASK_A2A_INTERCEPT
|
||||
TASK_A2A_INTERCEPT = {
|
||||
ClassName = "TASK_A2A_INTERCEPT",
|
||||
ClassName = "TASK_A2A_INTERCEPT"
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Instantiates a new TASK_A2A_INTERCEPT.
|
||||
-- @param #TASK_A2A_INTERCEPT self
|
||||
-- @param Tasking.Mission#MISSION Mission
|
||||
@@ -413,15 +399,12 @@ do -- TASK_A2A_INTERCEPT
|
||||
|
||||
Mission:AddTask( self )
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Intercept incoming intruders.\n"
|
||||
)
|
||||
self:SetBriefing( TaskBriefing or "Intercept incoming intruders.\n" )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a score when a target in scope of the A2A attack, has been destroyed .
|
||||
--- Set a score when a target in scope of the A2A attack, has been destroyed.
|
||||
-- @param #TASK_A2A_INTERCEPT self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Score The score in points to be granted when task process has been achieved.
|
||||
@@ -469,10 +452,8 @@ do -- TASK_A2A_INTERCEPT
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
do -- TASK_A2A_SWEEP
|
||||
|
||||
--- The TASK_A2A_SWEEP class
|
||||
@@ -493,11 +474,9 @@ do -- TASK_A2A_SWEEP
|
||||
--
|
||||
-- @field #TASK_A2A_SWEEP
|
||||
TASK_A2A_SWEEP = {
|
||||
ClassName = "TASK_A2A_SWEEP",
|
||||
ClassName = "TASK_A2A_SWEEP"
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Instantiates a new TASK_A2A_SWEEP.
|
||||
-- @param #TASK_A2A_SWEEP self
|
||||
-- @param Tasking.Mission#MISSION Mission
|
||||
@@ -512,10 +491,7 @@ do -- TASK_A2A_SWEEP
|
||||
|
||||
Mission:AddTask( self )
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Perform a fighter sweep. Incoming intruders were detected and could be hiding at the location.\n"
|
||||
)
|
||||
self:SetBriefing( TaskBriefing or "Perform a fighter sweep. Incoming intruders were detected and could be hiding at the location.\n" )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -531,7 +507,7 @@ do -- TASK_A2A_SWEEP
|
||||
self:__Goal( -10 )
|
||||
end
|
||||
|
||||
--- Set a score when a target in scope of the A2A attack, has been destroyed .
|
||||
--- Set a score when a target in scope of the A2A attack, has been destroyed.
|
||||
-- @param #TASK_A2A_SWEEP self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Score The score in points to be granted when task process has been achieved.
|
||||
@@ -581,7 +557,6 @@ do -- TASK_A2A_SWEEP
|
||||
|
||||
end
|
||||
|
||||
|
||||
do -- TASK_A2A_ENGAGE
|
||||
|
||||
--- The TASK_A2A_ENGAGE class
|
||||
@@ -600,11 +575,9 @@ do -- TASK_A2A_ENGAGE
|
||||
--
|
||||
-- @field #TASK_A2A_ENGAGE
|
||||
TASK_A2A_ENGAGE = {
|
||||
ClassName = "TASK_A2A_ENGAGE",
|
||||
ClassName = "TASK_A2A_ENGAGE"
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- Instantiates a new TASK_A2A_ENGAGE.
|
||||
-- @param #TASK_A2A_ENGAGE self
|
||||
-- @param Tasking.Mission#MISSION Mission
|
||||
@@ -619,10 +592,7 @@ do -- TASK_A2A_ENGAGE
|
||||
|
||||
Mission:AddTask( self )
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Bogeys are nearby! Players close by are ordered to ENGAGE the intruders!\n"
|
||||
)
|
||||
self:SetBriefing( TaskBriefing or "Bogeys are nearby! Players close by are ordered to ENGAGE the intruders!\n" )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -108,7 +108,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
-- The above example creates a SET_GROUP instance, and stores this in the variable (object) **EWRSet**.
|
||||
-- **EWRSet** is then being configured to filter all active groups with a group name starting with **EWR** to be included in the Set.
|
||||
-- **EWRSet** is then being ordered to start the dynamic filtering. Note that any destroy or new spawn of a group with the above names will be removed or added to the Set.
|
||||
-- Then a new **EWRDetection** object is created from the class DETECTION_AREAS. A grouping radius of 6000 is choosen, which is 6km.
|
||||
-- Then a new **EWRDetection** object is created from the class DETECTION_AREAS. A grouping radius of 6000 is chosen, which is 6 km.
|
||||
-- The **EWRDetection** object is then passed to the @{#TASK_A2A_DISPATCHER.New}() method to indicate the EWR network configuration and setup the A2A tasking and detection mechanism.
|
||||
--
|
||||
-- ### 2. Define the detected **target grouping radius**:
|
||||
@@ -185,7 +185,6 @@ do -- TASK_A2A_DISPATCHER
|
||||
SweepZones = {},
|
||||
}
|
||||
|
||||
|
||||
--- TASK_A2A_DISPATCHER constructor.
|
||||
-- @param #TASK_A2A_DISPATCHER self
|
||||
-- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done.
|
||||
@@ -208,7 +207,6 @@ do -- TASK_A2A_DISPATCHER
|
||||
|
||||
self:AddTransition( "Started", "Assign", "Started" )
|
||||
|
||||
|
||||
--- OnAfter Transition Handler for Event Assign.
|
||||
-- @function [parent=#TASK_A2A_DISPATCHER] OnAfterAssign
|
||||
-- @param #TASK_A2A_DISPATCHER self
|
||||
@@ -224,7 +222,6 @@ do -- TASK_A2A_DISPATCHER
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Define the radius to when an ENGAGE task will be generated for any nearby by airborne friendlies, which are executing cap or returning from an intercept mission.
|
||||
-- So, if there is a target area detected and reported,
|
||||
-- then any friendlies that are airborne near this target area,
|
||||
@@ -257,7 +254,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
-- @param #TASK_A2A_DISPATCHER self
|
||||
-- @param #boolean onoff Set messages on (true) or off (false)
|
||||
function TASK_A2A_DISPATCHER:SetSendMessages( onoff )
|
||||
self.FlashNewTask = onoff
|
||||
self.FlashNewTask = onoff
|
||||
end
|
||||
|
||||
--- Creates an INTERCEPT task when there are targets for it.
|
||||
@@ -286,7 +283,6 @@ do -- TASK_A2A_DISPATCHER
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Creates an SWEEP task when there are targets for it.
|
||||
-- @param #TASK_A2A_DISPATCHER self
|
||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||
@@ -296,8 +292,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
self:F( { DetectedItem.ItemID } )
|
||||
|
||||
local DetectedSet = DetectedItem.Set
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
|
||||
local DetectedZone = DetectedItem.Zone -- TODO: This seems unused, remove?
|
||||
|
||||
if DetectedItem.IsDetected == false then
|
||||
|
||||
@@ -312,7 +307,6 @@ do -- TASK_A2A_DISPATCHER
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Creates an ENGAGE task when there are human friendlies airborne near the targets.
|
||||
-- @param #TASK_A2A_DISPATCHER self
|
||||
-- @param Functional.Detection#DETECTION_BASE.DetectedItem DetectedItem
|
||||
@@ -322,11 +316,10 @@ do -- TASK_A2A_DISPATCHER
|
||||
self:F( { DetectedItem.ItemID } )
|
||||
|
||||
local DetectedSet = DetectedItem.Set
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
local DetectedZone = DetectedItem.Zone -- TODO: This seems unused, remove?
|
||||
|
||||
local PlayersCount, PlayersReport = self:GetPlayerFriendliesNearBy( DetectedItem )
|
||||
|
||||
|
||||
-- Only allow ENGAGE when there are Players near the zone, and when the Area has detected items since the last run in a 60 seconds time zone.
|
||||
if PlayersCount > 0 and DetectedItem.IsDetected == true then
|
||||
|
||||
@@ -341,9 +334,6 @@ do -- TASK_A2A_DISPATCHER
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Evaluates the removal of the Task from the Mission.
|
||||
-- Can only occur when the DetectedItem is Changed AND the state of the Task is "Planned".
|
||||
-- @param #TASK_A2A_DISPATCHER self
|
||||
@@ -388,8 +378,8 @@ do -- TASK_A2A_DISPATCHER
|
||||
end
|
||||
|
||||
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
|
||||
--DetectedSet:Flush( self )
|
||||
--self:F( { DetectedSetCount = DetectedSet:Count() } )
|
||||
-- DetectedSet:Flush( self )
|
||||
-- self:F( { DetectedSetCount = DetectedSet:Count() } )
|
||||
if DetectedSet:Count() == 0 then
|
||||
Remove = true
|
||||
end
|
||||
@@ -423,7 +413,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
local FriendlyUnitThreatLevel = FriendlyUnit:GetThreatLevel()
|
||||
FriendliesCount = FriendliesCount + 1
|
||||
local FriendlyType = FriendlyUnit:GetTypeName()
|
||||
FriendlyTypes[FriendlyType] = FriendlyTypes[FriendlyType] and ( FriendlyTypes[FriendlyType] + 1 ) or 1
|
||||
FriendlyTypes[FriendlyType] = FriendlyTypes[FriendlyType] and (FriendlyTypes[FriendlyType] + 1) or 1
|
||||
if DetectedTreatLevel < FriendlyUnitThreatLevel + 2 then
|
||||
end
|
||||
end
|
||||
@@ -431,19 +421,18 @@ do -- TASK_A2A_DISPATCHER
|
||||
|
||||
end
|
||||
|
||||
--self:F( { FriendliesCount = FriendliesCount } )
|
||||
-- self:F( { FriendliesCount = FriendliesCount } )
|
||||
|
||||
local FriendlyTypesReport = REPORT:New()
|
||||
|
||||
if FriendliesCount > 0 then
|
||||
for FriendlyType, FriendlyTypeCount in pairs( FriendlyTypes ) do
|
||||
FriendlyTypesReport:Add( string.format("%d of %s", FriendlyTypeCount, FriendlyType ) )
|
||||
FriendlyTypesReport:Add( string.format( "%d of %s", FriendlyTypeCount, FriendlyType ) )
|
||||
end
|
||||
else
|
||||
FriendlyTypesReport:Add( "-" )
|
||||
end
|
||||
|
||||
|
||||
return FriendliesCount, FriendlyTypesReport
|
||||
end
|
||||
|
||||
@@ -464,7 +453,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
for PlayerUnitName, PlayerUnitData in pairs( PlayersNearBy ) do
|
||||
local PlayerUnit = PlayerUnitData -- Wrapper.Unit#UNIT
|
||||
local PlayerName = PlayerUnit:GetPlayerName()
|
||||
--self:F( { PlayerName = PlayerName, PlayerUnit = PlayerUnit } )
|
||||
-- self:F( { PlayerName = PlayerName, PlayerUnit = PlayerUnit } )
|
||||
if PlayerUnit:IsAirPlane() and PlayerName ~= nil then
|
||||
local FriendlyUnitThreatLevel = PlayerUnit:GetThreatLevel()
|
||||
PlayersCount = PlayersCount + 1
|
||||
@@ -481,13 +470,12 @@ do -- TASK_A2A_DISPATCHER
|
||||
|
||||
if PlayersCount > 0 then
|
||||
for PlayerName, PlayerType in pairs( PlayerTypes ) do
|
||||
PlayerTypesReport:Add( string.format('"%s" in %s', PlayerName, PlayerType ) )
|
||||
PlayerTypesReport:Add( string.format( '"%s" in %s', PlayerName, PlayerType ) )
|
||||
end
|
||||
else
|
||||
PlayerTypesReport:Add( "-" )
|
||||
end
|
||||
|
||||
|
||||
return PlayersCount, PlayerTypesReport
|
||||
end
|
||||
|
||||
@@ -496,7 +484,6 @@ do -- TASK_A2A_DISPATCHER
|
||||
self.Tasks[TaskIndex] = nil
|
||||
end
|
||||
|
||||
|
||||
--- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}.
|
||||
-- @param #TASK_A2A_DISPATCHER self
|
||||
-- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object.
|
||||
@@ -536,8 +523,8 @@ do -- TASK_A2A_DISPATCHER
|
||||
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
|
||||
local DetectedCount = DetectedSet:Count()
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
--self:F( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } )
|
||||
--DetectedSet:Flush( self )
|
||||
-- self:F( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } )
|
||||
-- DetectedSet:Flush( self )
|
||||
|
||||
local DetectedID = DetectedItem.ID
|
||||
local TaskIndex = DetectedItem.Index
|
||||
@@ -593,7 +580,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
|
||||
TaskReport:Add( Task:GetName() )
|
||||
else
|
||||
self:F("This should not happen")
|
||||
self:F( "This should not happen" )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -612,10 +599,10 @@ do -- TASK_A2A_DISPATCHER
|
||||
-- TODO set menus using the HQ coordinator
|
||||
Mission:GetCommandCenter():SetMenu()
|
||||
|
||||
local TaskText = TaskReport:Text(", ")
|
||||
local TaskText = TaskReport:Text( ", " )
|
||||
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and (self.FlashNewTask) then
|
||||
if (not Mission:IsGroupAssigned( TaskGroup )) and TaskText ~= "" and (self.FlashNewTask) then
|
||||
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -38,7 +38,7 @@ do -- TASK_A2G
|
||||
--
|
||||
-- @field #TASK_A2G
|
||||
TASK_A2G = {
|
||||
ClassName = "TASK_A2G",
|
||||
ClassName = "TASK_A2G"
|
||||
}
|
||||
|
||||
--- Instantiates a new TASK_A2G.
|
||||
@@ -61,27 +61,25 @@ do -- TASK_A2G
|
||||
local Fsm = self:GetUnitProcess()
|
||||
|
||||
Fsm:AddTransition( "Assigned", "RouteToRendezVous", "RoutingToRendezVous" )
|
||||
Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } )
|
||||
Fsm:AddProcess ( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } )
|
||||
Fsm:AddProcess( "RoutingToRendezVous", "RouteToRendezVousPoint", ACT_ROUTE_POINT:New(), { Arrived = "ArriveAtRendezVous" } )
|
||||
Fsm:AddProcess( "RoutingToRendezVous", "RouteToRendezVousZone", ACT_ROUTE_ZONE:New(), { Arrived = "ArriveAtRendezVous" } )
|
||||
|
||||
Fsm:AddTransition( { "Arrived", "RoutingToRendezVous" }, "ArriveAtRendezVous", "ArrivedAtRendezVous" )
|
||||
|
||||
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" )
|
||||
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" )
|
||||
|
||||
Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} )
|
||||
Fsm:AddProcess( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} )
|
||||
Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" )
|
||||
Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} )
|
||||
Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} )
|
||||
Fsm:AddTransition( "Engaging", "RouteToTargets", "Engaging" )
|
||||
|
||||
--Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" )
|
||||
--Fsm:AddTransition( "Accounted", "Success", "Success" )
|
||||
-- Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" )
|
||||
-- Fsm:AddTransition( "Accounted", "Success", "Success" )
|
||||
Fsm:AddTransition( "Rejected", "Reject", "Aborted" )
|
||||
Fsm:AddTransition( "Failed", "Fail", "Failed" )
|
||||
|
||||
|
||||
|
||||
--- Test
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
@@ -130,7 +128,7 @@ do -- TASK_A2G
|
||||
function Fsm:onafterEngage( TaskUnit, Task )
|
||||
self:F( { self } )
|
||||
self:__Account( 0.1 )
|
||||
self:__RouteToTarget(0.1 )
|
||||
self:__RouteToTarget( 0.1 )
|
||||
self:__RouteToTargets( -10 )
|
||||
end
|
||||
|
||||
@@ -179,8 +177,6 @@ do -- TASK_A2G
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #TASK_A2G self
|
||||
function TASK_A2G:GetPlannedMenuText()
|
||||
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.TargetSetUnit:GetUnitTypesText() .. " )"
|
||||
@@ -190,7 +186,7 @@ do -- TASK_A2G
|
||||
-- @param Core.Point#COORDINATE RendezVousCoordinate The Coordinate object referencing to the 2D point where the RendezVous point is located on the map.
|
||||
-- @param #number RendezVousRange The RendezVousRange that defines when the player is considered to have arrived at the RendezVous point.
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
function TASK_A2G:SetRendezVousCoordinate( RendezVousCoordinate, RendezVousRange, TaskUnit )
|
||||
function TASK_A2G:SetRendezVousCoordinate( RendezVousCoordinate, RendezVousRange, TaskUnit )
|
||||
|
||||
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
||||
|
||||
@@ -211,8 +207,6 @@ do -- TASK_A2G
|
||||
return ActRouteRendezVous:GetCoordinate(), ActRouteRendezVous:GetRange()
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #TASK_A2G self
|
||||
-- @param Core.Zone#ZONE_BASE RendezVousZone The Zone object where the RendezVous is located on the map.
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
@@ -246,7 +240,6 @@ do -- TASK_A2G
|
||||
ActRouteTarget:SetCoordinate( TargetCoordinate )
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2G self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @return Core.Point#COORDINATE The Coordinate object where the Target is located on the map.
|
||||
@@ -258,7 +251,6 @@ do -- TASK_A2G
|
||||
return ActRouteTarget:GetCoordinate()
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2G self
|
||||
-- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map.
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
@@ -270,7 +262,6 @@ do -- TASK_A2G
|
||||
ActRouteTarget:SetZone( TargetZone )
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2G self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
|
||||
@@ -295,7 +286,7 @@ do -- TASK_A2G
|
||||
--- Return the relative distance to the target vicinity from the player, in order to sort the targets in the reports per distance from the threats.
|
||||
-- @param #TASK_A2G self
|
||||
function TASK_A2G:ReportOrder( ReportGroup )
|
||||
self:UpdateTaskInfo( self.DetectedItem )
|
||||
self:UpdateTaskInfo( self.DetectedItem )
|
||||
|
||||
local Coordinate = self.TaskInfo:GetData( "Coordinate" )
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
@@ -303,7 +294,6 @@ do -- TASK_A2G
|
||||
return Distance
|
||||
end
|
||||
|
||||
|
||||
--- This method checks every 10 seconds if the goal has been reached of the task.
|
||||
-- @param #TASK_A2G self
|
||||
function TASK_A2G:onafterGoal( TaskUnit, From, Event, To )
|
||||
@@ -365,12 +355,12 @@ do -- TASK_A2G
|
||||
-- @param Wrapper.Group#GROUP TaskGroup The player group.
|
||||
function TASK_A2G:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup )
|
||||
|
||||
if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then
|
||||
if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then
|
||||
return math.random( 1, 9 )
|
||||
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Distance then
|
||||
local Coordinate = self.TaskInfo:GetData( "Coordinate" )
|
||||
local Distance = Coordinate:Get2DDistance( CommandCenter:GetPositionable():GetCoordinate() )
|
||||
self:F({Distance=Distance})
|
||||
self:F( { Distance = Distance } )
|
||||
return math.floor( Distance )
|
||||
elseif AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Priority then
|
||||
return 1
|
||||
@@ -381,7 +371,6 @@ do -- TASK_A2G
|
||||
|
||||
end
|
||||
|
||||
|
||||
do -- TASK_A2G_SEAD
|
||||
|
||||
--- The TASK_A2G_SEAD class
|
||||
@@ -397,7 +386,7 @@ do -- TASK_A2G_SEAD
|
||||
--
|
||||
-- @field #TASK_A2G_SEAD
|
||||
TASK_A2G_SEAD = {
|
||||
ClassName = "TASK_A2G_SEAD",
|
||||
ClassName = "TASK_A2G_SEAD"
|
||||
}
|
||||
|
||||
--- Instantiates a new TASK_A2G_SEAD.
|
||||
@@ -408,16 +397,13 @@ do -- TASK_A2G_SEAD
|
||||
-- @param Core.Set#SET_UNIT TargetSetUnit
|
||||
-- @param #string TaskBriefing The briefing of the task.
|
||||
-- @return #TASK_A2G_SEAD self
|
||||
function TASK_A2G_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing)
|
||||
function TASK_A2G_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing )
|
||||
local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "SEAD", TaskBriefing ) ) -- #TASK_A2G_SEAD
|
||||
self:F()
|
||||
|
||||
Mission:AddTask( self )
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Execute a Suppression of Enemy Air Defenses."
|
||||
)
|
||||
self:SetBriefing( TaskBriefing or "Execute a Suppression of Enemy Air Defenses." )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -470,7 +456,6 @@ do -- TASK_A2G_SEAD
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
do -- TASK_A2G_BAI
|
||||
@@ -488,9 +473,7 @@ do -- TASK_A2G_BAI
|
||||
-- based on detected enemy ground targets.
|
||||
--
|
||||
-- @field #TASK_A2G_BAI
|
||||
TASK_A2G_BAI = {
|
||||
ClassName = "TASK_A2G_BAI",
|
||||
}
|
||||
TASK_A2G_BAI = { ClassName = "TASK_A2G_BAI" }
|
||||
|
||||
--- Instantiates a new TASK_A2G_BAI.
|
||||
-- @param #TASK_A2G_BAI self
|
||||
@@ -506,10 +489,7 @@ do -- TASK_A2G_BAI
|
||||
|
||||
Mission:AddTask( self )
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Execute a Battlefield Air Interdiction of a group of enemy targets."
|
||||
)
|
||||
self:SetBriefing( TaskBriefing or "Execute a Battlefield Air Interdiction of a group of enemy targets." )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -564,9 +544,6 @@ do -- TASK_A2G_BAI
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
do -- TASK_A2G_CAS
|
||||
|
||||
--- The TASK_A2G_CAS class
|
||||
@@ -581,9 +558,7 @@ do -- TASK_A2G_CAS
|
||||
-- based on detected enemy ground targets.
|
||||
--
|
||||
-- @field #TASK_A2G_CAS
|
||||
TASK_A2G_CAS = {
|
||||
ClassName = "TASK_A2G_CAS",
|
||||
}
|
||||
TASK_A2G_CAS = { ClassName = "TASK_A2G_CAS" }
|
||||
|
||||
--- Instantiates a new TASK_A2G_CAS.
|
||||
-- @param #TASK_A2G_CAS self
|
||||
@@ -599,17 +574,11 @@ do -- TASK_A2G_CAS
|
||||
|
||||
Mission:AddTask( self )
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Execute a Close Air Support for a group of enemy targets. " ..
|
||||
"Beware of friendlies at the vicinity! "
|
||||
)
|
||||
|
||||
self:SetBriefing( TaskBriefing or ( "Execute a Close Air Support for a group of enemy targets. " .. "Beware of friendlies at the vicinity! " ) )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set a score when a target in scope of the A2G attack, has been destroyed .
|
||||
-- @param #TASK_A2G_CAS self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
@@ -658,5 +627,4 @@ do -- TASK_A2G_CAS
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
-- * Dynamically change the tasks as the tactical situation evolves during the mission.
|
||||
-- * Dynamically assign (CAS) Close Air Support tasks for human players.
|
||||
-- * Dynamically assign (BAI) Battlefield Air Interdiction tasks for human players.
|
||||
-- * Dynamically assign (SEAD) Supression of Enemy Air Defense tasks for human players to eliminate G2A missile threats.
|
||||
-- * Dynamically assign (SEAD) Suppression of Enemy Air Defense tasks for human players to eliminate G2A missile threats.
|
||||
-- * Define and use an EWR (Early Warning Radar) network.
|
||||
-- * Define different ranges to engage upon intruders.
|
||||
-- * Keep task achievements.
|
||||
-- * Score task achievements.--
|
||||
-- * Score task achievements.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
@@ -122,7 +123,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
-- F1. Command Center [Lima]
|
||||
-- F1. Mission "Overlord (High)"
|
||||
--
|
||||
-- Command Center [Gori] is controlling Mission "Alpha", "Beta", "Gamma". Alpha is the Primary mission, Beta the Secondary and there is a Tacical mission Gamma.
|
||||
-- Command Center [Gori] is controlling Mission "Alpha", "Beta", "Gamma". Alpha is the Primary mission, Beta the Secondary and there is a Tactical mission Gamma.
|
||||
-- Command Center [Lima] is controlling Missions "Overlord", which needs to be executed with High priority.
|
||||
--
|
||||
-- ## 1.1. Mission Menu (Under the Command Center Menu)
|
||||
@@ -196,7 +197,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
--
|
||||
-- The Mission Reports Menu is a sub menu, that provides options to retrieve further information on the current Mission:
|
||||
--
|
||||
-- - **Report Mission Progress**: Shows the progress of the current Mission. Each Task has a %-tage of completion.
|
||||
-- - **Report Mission Progress**: Shows the progress of the current Mission. Each Task has a % of completion.
|
||||
-- - **Report Players per Task**: Show which players are engaged on which Task within the Mission.
|
||||
--
|
||||
-- For CC |Gori|, Mission "Alpha", the Mission Reports menu structure could look like this:
|
||||
@@ -264,7 +265,6 @@ do -- TASK_A2G_DISPATCHER
|
||||
--
|
||||
-- **The F5. Assigned Task __TaskName__ allows the player to control the current Assigned Task and take further actions.**
|
||||
--
|
||||
--
|
||||
-- ## 1.3. Join Planned Task Menu
|
||||
--
|
||||
-- The Join Planned Task Menu contains the different Planned A2G Tasks **in a structured Menu Hierarchy**.
|
||||
@@ -388,7 +388,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
-- - A @{Mission} object. Each task belongs to a Mission.
|
||||
-- - A @{Detection} object. There are several detection grouping methods to choose from.
|
||||
-- - A @{Task_A2G_Dispatcher} object. The master A2G task dispatcher.
|
||||
-- - A @{Set} of @{Wrapper.Group} objects that will detect the emeny, the RecceSet. This is attached to the @{Detection} object.
|
||||
-- - A @{Set} of @{Wrapper.Group} objects that will detect the enemy, the RecceSet. This is attached to the @{Detection} object.
|
||||
-- - A @{Set} ob @{Wrapper.Group} objects that will attack the enemy, the AttackSet. This is attached to the @{Task_A2G_Dispatcher} object.
|
||||
--
|
||||
-- Below an example mission declaration that is defines a Task A2G Dispatcher object.
|
||||
@@ -425,7 +425,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
--
|
||||
-- -- Now we have everything to setup the main A2G TaskDispatcher.
|
||||
-- TaskDispatcher = TASK_A2G_DISPATCHER
|
||||
-- :New( Mission, AttackSet, DetectionAreas ) -- We assign the TaskDispatcher under Mission. The AttackSet will engage the enemy and will recieve the dispatched Tasks. The DetectionAreas will report any detected enemies to the TaskDispatcher.
|
||||
-- :New( Mission, AttackSet, DetectionAreas ) -- We assign the TaskDispatcher under Mission. The AttackSet will engage the enemy and will receive the dispatched Tasks. The DetectionAreas will report any detected enemies to the TaskDispatcher.
|
||||
--
|
||||
--
|
||||
--
|
||||
@@ -434,10 +434,9 @@ do -- TASK_A2G_DISPATCHER
|
||||
ClassName = "TASK_A2G_DISPATCHER",
|
||||
Mission = nil,
|
||||
Detection = nil,
|
||||
Tasks = {},
|
||||
Tasks = {}
|
||||
}
|
||||
|
||||
|
||||
--- TASK_A2G_DISPATCHER constructor.
|
||||
-- @param #TASK_A2G_DISPATCHER self
|
||||
-- @param Tasking.Mission#MISSION Mission The mission for which the task dispatching is done.
|
||||
@@ -451,7 +450,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
|
||||
self.Detection = Detection
|
||||
self.Mission = Mission
|
||||
self.FlashNewTask = true --set to false to suppress flash messages
|
||||
self.FlashNewTask = true -- set to false to suppress flash messages
|
||||
|
||||
self.Detection:FilterCategories( { Unit.Category.GROUND_UNIT } )
|
||||
|
||||
@@ -472,11 +471,11 @@ do -- TASK_A2G_DISPATCHER
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set flashing player messages on or off
|
||||
--- Set flashing player messages on or off
|
||||
-- @param #TASK_A2G_DISPATCHER self
|
||||
-- @param #boolean onoff Set messages on (true) or off (false)
|
||||
function TASK_A2G_DISPATCHER:SetSendMessages( onoff )
|
||||
self.FlashNewTask = onoff
|
||||
self.FlashNewTask = onoff
|
||||
end
|
||||
|
||||
--- Creates a SEAD task when there are targets for it.
|
||||
@@ -518,7 +517,6 @@ do -- TASK_A2G_DISPATCHER
|
||||
local DetectedSet = DetectedItem.Set
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
|
||||
|
||||
-- Determine if the set has ground units.
|
||||
-- There should be ground unit friendlies nearby. Airborne units are valid friendlies types.
|
||||
-- And there shouldn't be any radar.
|
||||
@@ -550,7 +548,6 @@ do -- TASK_A2G_DISPATCHER
|
||||
local DetectedSet = DetectedItem.Set
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
|
||||
|
||||
-- Determine if the set has ground units.
|
||||
-- There shouldn't be any ground unit friendlies nearby.
|
||||
-- And there shouldn't be any radar.
|
||||
@@ -571,7 +568,6 @@ do -- TASK_A2G_DISPATCHER
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
function TASK_A2G_DISPATCHER:RemoveTask( TaskIndex )
|
||||
self.Mission:RemoveTask( self.Tasks[TaskIndex] )
|
||||
self.Tasks[TaskIndex] = nil
|
||||
@@ -588,8 +584,8 @@ do -- TASK_A2G_DISPATCHER
|
||||
function TASK_A2G_DISPATCHER:EvaluateRemoveTask( Mission, Task, TaskIndex, DetectedItemChanged )
|
||||
|
||||
if Task then
|
||||
if ( Task:IsStatePlanned() and DetectedItemChanged == true ) or Task:IsStateCancelled() then
|
||||
--self:F( "Removing Tasking: " .. Task:GetTaskName() )
|
||||
if (Task:IsStatePlanned() and DetectedItemChanged == true) or Task:IsStateCancelled() then
|
||||
-- self:F( "Removing Tasking: " .. Task:GetTaskName() )
|
||||
self:RemoveTask( TaskIndex )
|
||||
end
|
||||
end
|
||||
@@ -597,7 +593,6 @@ do -- TASK_A2G_DISPATCHER
|
||||
return Task
|
||||
end
|
||||
|
||||
|
||||
--- Assigns tasks in relation to the detected items to the @{Core.Set#SET_GROUP}.
|
||||
-- @param #TASK_A2G_DISPATCHER self
|
||||
-- @param Functional.Detection#DETECTION_BASE Detection The detection created by the @{Functional.Detection#DETECTION_BASE} derived object.
|
||||
@@ -638,8 +633,8 @@ do -- TASK_A2G_DISPATCHER
|
||||
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
|
||||
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
--self:F( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } )
|
||||
--DetectedSet:Flush( self )
|
||||
-- self:F( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } )
|
||||
-- DetectedSet:Flush( self )
|
||||
|
||||
local DetectedItemID = DetectedItem.ID
|
||||
local TaskIndex = DetectedItem.Index
|
||||
@@ -660,7 +655,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
Task:SetTargetSetUnit( TargetSetUnit )
|
||||
Task:SetDetection( Detection, DetectedItem )
|
||||
Task:UpdateTaskInfo( DetectedItem )
|
||||
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
|
||||
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
|
||||
else
|
||||
Task:Cancel()
|
||||
end
|
||||
@@ -694,8 +689,8 @@ do -- TASK_A2G_DISPATCHER
|
||||
|
||||
-- Now we send to each group the changes, if any.
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
local TargetsText = TargetsReport:Text(", ")
|
||||
if ( Mission:IsGroupAssigned(TaskGroup) ) and TargetsText ~= "" and self.FlashNewTask then
|
||||
local TargetsText = TargetsReport:Text( ", " )
|
||||
if (Mission:IsGroupAssigned( TaskGroup )) and TargetsText ~= "" and self.FlashNewTask then
|
||||
Mission:GetCommandCenter():MessageToGroup( string.format( "Task %s has change of targets:\n %s", Task:GetName(), TargetsText ), TaskGroup )
|
||||
end
|
||||
end
|
||||
@@ -753,7 +748,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2G_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", DetectedItemID ), TargetSetUnit )
|
||||
DetectedItem.DesignateMenuName = string.format( "SEAD.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||
DetectedItem.DesignateMenuName = string.format( "SEAD.%03d", DetectedItemID ) -- inject a name for DESIGNATE, if using same DETECTION object
|
||||
Task:SetDetection( Detection, DetectedItem )
|
||||
end
|
||||
|
||||
@@ -762,7 +757,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2G_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", DetectedItemID ), TargetSetUnit )
|
||||
DetectedItem.DesignateMenuName = string.format( "CAS.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||
DetectedItem.DesignateMenuName = string.format( "CAS.%03d", DetectedItemID ) -- inject a name for DESIGNATE, if using same DETECTION object
|
||||
Task:SetDetection( Detection, DetectedItem )
|
||||
end
|
||||
|
||||
@@ -771,7 +766,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be BAIed...
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2G_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", DetectedItemID ), TargetSetUnit )
|
||||
DetectedItem.DesignateMenuName = string.format( "BAI.%03d", DetectedItemID ) --inject a name for DESIGNATE, if using same DETECTION object
|
||||
DetectedItem.DesignateMenuName = string.format( "BAI.%03d", DetectedItemID ) -- inject a name for DESIGNATE, if using same DETECTION object
|
||||
Task:SetDetection( Detection, DetectedItem )
|
||||
end
|
||||
end
|
||||
@@ -800,14 +795,12 @@ do -- TASK_A2G_DISPATCHER
|
||||
self:Aborted( Task )
|
||||
end
|
||||
|
||||
|
||||
TaskReport:Add( Task:GetName() )
|
||||
else
|
||||
self:F("This should not happen")
|
||||
self:F( "This should not happen" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- OK, so the tasking has been done, now delete the changes reported for the area.
|
||||
Detection:AcceptChanges( DetectedItem )
|
||||
end
|
||||
@@ -815,9 +808,9 @@ do -- TASK_A2G_DISPATCHER
|
||||
-- TODO set menus using the HQ coordinator
|
||||
Mission:GetCommandCenter():SetMenu()
|
||||
|
||||
local TaskText = TaskReport:Text(", ")
|
||||
local TaskText = TaskReport:Text( ", " )
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and self.FlashNewTask then
|
||||
if (not Mission:IsGroupAssigned( TaskGroup )) and TaskText ~= "" and self.FlashNewTask then
|
||||
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
--
|
||||
-- DCS itself provides a lot of enumerators for various things. See [Enumerators](https://wiki.hoggitworld.com/view/Category:Enumerators) on Hoggit.
|
||||
--
|
||||
-- Other Moose classe also have enumerators. For example, the AIRBASE class has enumerators for airbase names.
|
||||
-- Other Moose classes also have enumerators. For example, the AIRBASE class has enumerators for airbase names.
|
||||
--
|
||||
-- @module ENUMS
|
||||
-- @image MOOSE.JPG
|
||||
@@ -30,16 +30,16 @@ ENUMS = {}
|
||||
-- @type ENUMS.ROE
|
||||
-- @field #number WeaponFree AI will engage any enemy group it detects. Target prioritization is based based on the threat of the target.
|
||||
-- @field #number OpenFireWeaponFree AI will engage any enemy group it detects, but will prioritize targets specified in the groups tasking.
|
||||
-- @field #number OpenFire AI will engage only targets specified in its taskings.
|
||||
-- @field #number OpenFire AI will engage only targets specified in its tasking.
|
||||
-- @field #number ReturnFire AI will only engage threats that shoot first.
|
||||
-- @field #number WeaponHold AI will hold fire under all circumstances.
|
||||
ENUMS.ROE = {
|
||||
WeaponFree=0,
|
||||
OpenFireWeaponFree=1,
|
||||
OpenFire=2,
|
||||
ReturnFire=3,
|
||||
WeaponHold=4,
|
||||
}
|
||||
WeaponFree = 0,
|
||||
OpenFireWeaponFree = 1,
|
||||
OpenFire = 2,
|
||||
ReturnFire = 3,
|
||||
WeaponHold = 4,
|
||||
}
|
||||
|
||||
--- Reaction On Threat.
|
||||
-- @type ENUMS.ROT
|
||||
@@ -49,11 +49,11 @@ ENUMS.ROE = {
|
||||
-- @field #number BypassAndEscape AI will attempt to avoid enemy threat zones all together. This includes attempting to fly above or around threats.
|
||||
-- @field #number AllowAbortMission If a threat is deemed severe enough the AI will abort its mission and return to base.
|
||||
ENUMS.ROT = {
|
||||
NoReaction=0,
|
||||
PassiveDefense=1,
|
||||
EvadeFire=2,
|
||||
BypassAndEscape=3,
|
||||
AllowAbortMission=4,
|
||||
NoReaction = 0,
|
||||
PassiveDefense = 1,
|
||||
EvadeFire = 2,
|
||||
BypassAndEscape = 3,
|
||||
AllowAbortMission = 4,
|
||||
}
|
||||
|
||||
--- Alarm state.
|
||||
@@ -62,12 +62,12 @@ ENUMS.ROT = {
|
||||
-- @field #number Green Group is not combat ready. Sensors are stowed if possible.
|
||||
-- @field #number Red Group is combat ready and actively searching for targets. Some groups like infantry will not move in this state.
|
||||
ENUMS.AlarmState = {
|
||||
Auto=0,
|
||||
Green=1,
|
||||
Red=2,
|
||||
Auto = 0,
|
||||
Green = 1,
|
||||
Red = 2,
|
||||
}
|
||||
|
||||
--- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerotor on hoggit wiki.
|
||||
--- Weapon types. See the [Weapon Flag](https://wiki.hoggitworld.com/view/DCS_enum_weapon_flag) enumerator on Hoggit wiki.
|
||||
-- @type ENUMS.WeaponFlag
|
||||
ENUMS.WeaponFlag={
|
||||
-- Bombs
|
||||
@@ -111,7 +111,7 @@ ENUMS.WeaponFlag={
|
||||
--
|
||||
-- Bombs
|
||||
GuidedBomb = 14, -- (LGB + TvGB + SNSGB)
|
||||
AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispencer + CandleBomb + ParachuteBomb)
|
||||
AnyUnguidedBomb = 2147485680, -- (HeBomb + Penetrator + NapalmBomb + FAEBomb + ClusterBomb + Dispenser + CandleBomb + ParachuteBomb)
|
||||
AnyBomb = 2147485694, -- (GuidedBomb + AnyUnguidedBomb)
|
||||
--- Rockets
|
||||
AnyRocket = 30720, -- LightRocket + MarkerRocket + CandleRocket + HeavyRocket
|
||||
@@ -173,7 +173,7 @@ ENUMS.MissionTask={
|
||||
TRANSPORT="Transport",
|
||||
}
|
||||
|
||||
--- Formations (new). See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki.
|
||||
--- Formations (new). See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on Hoggit wiki.
|
||||
-- @type ENUMS.Formation
|
||||
ENUMS.Formation={}
|
||||
ENUMS.Formation.FixedWing={}
|
||||
@@ -216,23 +216,23 @@ ENUMS.Formation.FixedWing.FighterVic.Close = 917505
|
||||
ENUMS.Formation.FixedWing.FighterVic.Open = 917506
|
||||
ENUMS.Formation.RotaryWing={}
|
||||
ENUMS.Formation.RotaryWing.Column={}
|
||||
ENUMS.Formation.RotaryWing.Column.D70=720896
|
||||
ENUMS.Formation.RotaryWing.Column.D70 = 720896
|
||||
ENUMS.Formation.RotaryWing.Wedge={}
|
||||
ENUMS.Formation.RotaryWing.Wedge.D70=8
|
||||
ENUMS.Formation.RotaryWing.Wedge.D70 = 8
|
||||
ENUMS.Formation.RotaryWing.FrontRight={}
|
||||
ENUMS.Formation.RotaryWing.FrontRight.D300=655361
|
||||
ENUMS.Formation.RotaryWing.FrontRight.D600=655362
|
||||
ENUMS.Formation.RotaryWing.FrontRight.D300 = 655361
|
||||
ENUMS.Formation.RotaryWing.FrontRight.D600 = 655362
|
||||
ENUMS.Formation.RotaryWing.FrontLeft={}
|
||||
ENUMS.Formation.RotaryWing.FrontLeft.D300=655617
|
||||
ENUMS.Formation.RotaryWing.FrontLeft.D600=655618
|
||||
ENUMS.Formation.RotaryWing.FrontLeft.D300 = 655617
|
||||
ENUMS.Formation.RotaryWing.FrontLeft.D600 = 655618
|
||||
ENUMS.Formation.RotaryWing.EchelonRight={}
|
||||
ENUMS.Formation.RotaryWing.EchelonRight.D70 =589825
|
||||
ENUMS.Formation.RotaryWing.EchelonRight.D300=589826
|
||||
ENUMS.Formation.RotaryWing.EchelonRight.D600=589827
|
||||
ENUMS.Formation.RotaryWing.EchelonRight.D70 = 589825
|
||||
ENUMS.Formation.RotaryWing.EchelonRight.D300 = 589826
|
||||
ENUMS.Formation.RotaryWing.EchelonRight.D600 = 589827
|
||||
ENUMS.Formation.RotaryWing.EchelonLeft={}
|
||||
ENUMS.Formation.RotaryWing.EchelonLeft.D70 =590081
|
||||
ENUMS.Formation.RotaryWing.EchelonLeft.D300=590082
|
||||
ENUMS.Formation.RotaryWing.EchelonLeft.D600=590083
|
||||
ENUMS.Formation.RotaryWing.EchelonLeft.D70 = 590081
|
||||
ENUMS.Formation.RotaryWing.EchelonLeft.D300 = 590082
|
||||
ENUMS.Formation.RotaryWing.EchelonLeft.D600 = 590083
|
||||
ENUMS.Formation.Vehicle={}
|
||||
ENUMS.Formation.Vehicle.Vee="Vee"
|
||||
ENUMS.Formation.Vehicle.EchelonRight="EchelonR"
|
||||
@@ -244,25 +244,25 @@ ENUMS.Formation.Vehicle.Cone="Cone"
|
||||
ENUMS.Formation.Vehicle.Diamond="Diamond"
|
||||
|
||||
--- Formations (old). The old format is a simplified version of the new formation enums, which allow more sophisticated settings.
|
||||
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on hoggit wiki.
|
||||
-- See the [Formations](https://wiki.hoggitworld.com/view/DCS_enum_formation) on Hoggit wiki.
|
||||
-- @type ENUMS.FormationOld
|
||||
ENUMS.FormationOld={}
|
||||
ENUMS.FormationOld.FixedWing={}
|
||||
ENUMS.FormationOld.FixedWing.LineAbreast=1
|
||||
ENUMS.FormationOld.FixedWing.Trail=2
|
||||
ENUMS.FormationOld.FixedWing.Wedge=3
|
||||
ENUMS.FormationOld.FixedWing.EchelonRight=4
|
||||
ENUMS.FormationOld.FixedWing.EchelonLeft=5
|
||||
ENUMS.FormationOld.FixedWing.FingerFour=6
|
||||
ENUMS.FormationOld.FixedWing.SpreadFour=7
|
||||
ENUMS.FormationOld.FixedWing.BomberElement=12
|
||||
ENUMS.FormationOld.FixedWing.BomberElementHeight=13
|
||||
ENUMS.FormationOld.FixedWing.FighterVic=14
|
||||
ENUMS.FormationOld.FixedWing.LineAbreast = 1
|
||||
ENUMS.FormationOld.FixedWing.Trail = 2
|
||||
ENUMS.FormationOld.FixedWing.Wedge = 3
|
||||
ENUMS.FormationOld.FixedWing.EchelonRight = 4
|
||||
ENUMS.FormationOld.FixedWing.EchelonLeft = 5
|
||||
ENUMS.FormationOld.FixedWing.FingerFour = 6
|
||||
ENUMS.FormationOld.FixedWing.SpreadFour = 7
|
||||
ENUMS.FormationOld.FixedWing.BomberElement = 12
|
||||
ENUMS.FormationOld.FixedWing.BomberElementHeight = 13
|
||||
ENUMS.FormationOld.FixedWing.FighterVic = 14
|
||||
ENUMS.FormationOld.RotaryWing={}
|
||||
ENUMS.FormationOld.RotaryWing.Wedge=8
|
||||
ENUMS.FormationOld.RotaryWing.Echelon=9
|
||||
ENUMS.FormationOld.RotaryWing.Front=10
|
||||
ENUMS.FormationOld.RotaryWing.Column=11
|
||||
ENUMS.FormationOld.RotaryWing.Wedge = 8
|
||||
ENUMS.FormationOld.RotaryWing.Echelon = 9
|
||||
ENUMS.FormationOld.RotaryWing.Front = 10
|
||||
ENUMS.FormationOld.RotaryWing.Column = 11
|
||||
|
||||
|
||||
--- Morse Code. See the [Wikipedia](https://en.wikipedia.org/wiki/Morse_code).
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
-- @module Utilities.PROFILER
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
|
||||
--- PROFILER class.
|
||||
-- @type PROFILER
|
||||
-- @field #string ClassName Name of the class.
|
||||
@@ -25,7 +24,6 @@
|
||||
-- @field #number ThreshTtot Total time threshold. Only write output if total function CPU time is more than this value.
|
||||
-- @field #string fileNamePrefix Output file name prefix, e.g. "MooseProfiler".
|
||||
-- @field #string fileNameSuffix Output file name prefix, e.g. "txt"
|
||||
|
||||
--- *The emperor counsels simplicity. First principles. Of each particular thing, ask: What is it in itself, in its own constitution? What is its causal nature? *
|
||||
--
|
||||
-- ===
|
||||
@@ -35,12 +33,11 @@
|
||||
-- # The PROFILER Concept
|
||||
--
|
||||
-- Profile your lua code. This tells you, which functions are called very often and which consume most real time.
|
||||
-- With this information you can optimize the perfomance of your code.
|
||||
-- With this information you can optimize the performance of your code.
|
||||
--
|
||||
-- # Prerequisites
|
||||
--
|
||||
-- The modules **os** and **lfs** need to be desanizied.
|
||||
--
|
||||
-- The modules **os** and **lfs** need to be de-sanitized.
|
||||
--
|
||||
-- # Start
|
||||
--
|
||||
@@ -117,61 +114,60 @@ PROFILER = {
|
||||
--- Start profiler.
|
||||
-- @param #number Delay Delay in seconds before profiler is stated. Default is immediately.
|
||||
-- @param #number Duration Duration in (game) seconds before the profiler is stopped. Default is when mission ends.
|
||||
function PROFILER.Start(Delay, Duration)
|
||||
function PROFILER.Start( Delay, Duration )
|
||||
|
||||
-- Check if os, io and lfs are available.
|
||||
local go=true
|
||||
local go = true
|
||||
if not os then
|
||||
env.error("ERROR: Profiler needs os to be desanitized!")
|
||||
go=false
|
||||
env.error( "ERROR: Profiler needs os to be de-sanitized!" )
|
||||
go = false
|
||||
end
|
||||
if not io then
|
||||
env.error("ERROR: Profiler needs io to be desanitized!")
|
||||
go=false
|
||||
env.error( "ERROR: Profiler needs io to be de-sanitized!" )
|
||||
go = false
|
||||
end
|
||||
if not lfs then
|
||||
env.error("ERROR: Profiler needs lfs to be desanitized!")
|
||||
go=false
|
||||
env.error( "ERROR: Profiler needs lfs to be de-sanitized!" )
|
||||
go = false
|
||||
end
|
||||
if not go then
|
||||
return
|
||||
end
|
||||
|
||||
if Delay and Delay>0 then
|
||||
BASE:ScheduleOnce(Delay, PROFILER.Start, 0, Duration)
|
||||
if Delay and Delay > 0 then
|
||||
BASE:ScheduleOnce( Delay, PROFILER.Start, 0, Duration )
|
||||
else
|
||||
|
||||
-- Set start time.
|
||||
PROFILER.TstartGame=timer.getTime()
|
||||
PROFILER.TstartOS=os.clock()
|
||||
PROFILER.TstartGame = timer.getTime()
|
||||
PROFILER.TstartOS = os.clock()
|
||||
|
||||
-- Add event handler.
|
||||
world.addEventHandler(PROFILER.eventHandler)
|
||||
world.addEventHandler( PROFILER.eventHandler )
|
||||
|
||||
-- Info in log.
|
||||
env.info('############################ Profiler Started ############################')
|
||||
env.info( '############################ Profiler Started ############################' )
|
||||
if Duration then
|
||||
env.info(string.format("- Will be running for %d seconds", Duration))
|
||||
env.info( string.format( "- Will be running for %d seconds", Duration ) )
|
||||
else
|
||||
env.info(string.format("- Will be stopped when mission ends"))
|
||||
env.info( string.format( "- Will be stopped when mission ends" ) )
|
||||
end
|
||||
env.info(string.format("- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS))
|
||||
env.info(string.format("- Total function time threshold %.3f sec", PROFILER.ThreshTtot))
|
||||
env.info(string.format("- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename(PROFILER.fileNameSuffix)))
|
||||
env.info(string.format("- Output file \"%s\" in CSV format", PROFILER.getfilename("csv")))
|
||||
env.info('###############################################################################')
|
||||
|
||||
env.info( string.format( "- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS ) )
|
||||
env.info( string.format( "- Total function time threshold %.3f sec", PROFILER.ThreshTtot ) )
|
||||
env.info( string.format( "- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename( PROFILER.fileNameSuffix ) ) )
|
||||
env.info( string.format( "- Output file \"%s\" in CSV format", PROFILER.getfilename( "csv" ) ) )
|
||||
env.info( '###############################################################################' )
|
||||
|
||||
-- Message on screen
|
||||
local duration=Duration or 600
|
||||
trigger.action.outText("### Profiler running ###", duration)
|
||||
local duration = Duration or 600
|
||||
trigger.action.outText( "### Profiler running ###", duration )
|
||||
|
||||
-- Set hook.
|
||||
debug.sethook(PROFILER.hook, "cr")
|
||||
debug.sethook( PROFILER.hook, "cr" )
|
||||
|
||||
-- Auto stop profiler.
|
||||
if Duration then
|
||||
PROFILER.Stop(Duration)
|
||||
PROFILER.Stop( Duration )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -180,34 +176,33 @@ end
|
||||
|
||||
--- Stop profiler.
|
||||
-- @param #number Delay Delay before stop in seconds.
|
||||
function PROFILER.Stop(Delay)
|
||||
function PROFILER.Stop( Delay )
|
||||
|
||||
if Delay and Delay>0 then
|
||||
if Delay and Delay > 0 then
|
||||
|
||||
BASE:ScheduleOnce(Delay, PROFILER.Stop)
|
||||
BASE:ScheduleOnce( Delay, PROFILER.Stop )
|
||||
|
||||
else
|
||||
|
||||
-- Remove hook.
|
||||
debug.sethook()
|
||||
|
||||
|
||||
-- Run time game.
|
||||
local runTimeGame=timer.getTime()-PROFILER.TstartGame
|
||||
local runTimeGame = timer.getTime() - PROFILER.TstartGame
|
||||
|
||||
-- Run time real OS.
|
||||
local runTimeOS=os.clock()-PROFILER.TstartOS
|
||||
local runTimeOS = os.clock() - PROFILER.TstartOS
|
||||
|
||||
-- Show info.
|
||||
PROFILER.showInfo(runTimeGame, runTimeOS)
|
||||
PROFILER.showInfo( runTimeGame, runTimeOS )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Event handler.
|
||||
function PROFILER.eventHandler:onEvent(event)
|
||||
if event.id==world.event.S_EVENT_MISSION_END then
|
||||
function PROFILER.eventHandler:onEvent( event )
|
||||
if event.id == world.event.S_EVENT_MISSION_END then
|
||||
PROFILER.Stop()
|
||||
end
|
||||
end
|
||||
@@ -218,34 +213,34 @@ end
|
||||
|
||||
--- Debug hook.
|
||||
-- @param #table event Event.
|
||||
function PROFILER.hook(event)
|
||||
function PROFILER.hook( event )
|
||||
|
||||
local f=debug.getinfo(2, "f").func
|
||||
local f = debug.getinfo( 2, "f" ).func
|
||||
|
||||
if event=='call' then
|
||||
if event == 'call' then
|
||||
|
||||
if PROFILER.Counters[f]==nil then
|
||||
if PROFILER.Counters[f] == nil then
|
||||
|
||||
PROFILER.Counters[f]=1
|
||||
PROFILER.dInfo[f]=debug.getinfo(2,"Sn")
|
||||
PROFILER.Counters[f] = 1
|
||||
PROFILER.dInfo[f] = debug.getinfo( 2, "Sn" )
|
||||
|
||||
if PROFILER.fTimeTotal[f]==nil then
|
||||
PROFILER.fTimeTotal[f]=0
|
||||
if PROFILER.fTimeTotal[f] == nil then
|
||||
PROFILER.fTimeTotal[f] = 0
|
||||
end
|
||||
|
||||
else
|
||||
PROFILER.Counters[f]=PROFILER.Counters[f]+1
|
||||
PROFILER.Counters[f] = PROFILER.Counters[f] + 1
|
||||
end
|
||||
|
||||
if PROFILER.fTime[f]==nil then
|
||||
PROFILER.fTime[f]=os.clock()
|
||||
if PROFILER.fTime[f] == nil then
|
||||
PROFILER.fTime[f] = os.clock()
|
||||
end
|
||||
|
||||
elseif (event=='return') then
|
||||
elseif (event == 'return') then
|
||||
|
||||
if PROFILER.fTime[f]~=nil then
|
||||
PROFILER.fTimeTotal[f]=PROFILER.fTimeTotal[f]+(os.clock()-PROFILER.fTime[f])
|
||||
PROFILER.fTime[f]=nil
|
||||
if PROFILER.fTime[f] ~= nil then
|
||||
PROFILER.fTimeTotal[f] = PROFILER.fTimeTotal[f] + (os.clock() - PROFILER.fTime[f])
|
||||
PROFILER.fTime[f] = nil
|
||||
end
|
||||
|
||||
end
|
||||
@@ -262,11 +257,11 @@ end
|
||||
-- @return #string Source file name.
|
||||
-- @return #string Line number.
|
||||
-- @return #number Function time in seconds.
|
||||
function PROFILER.getData(func)
|
||||
function PROFILER.getData( func )
|
||||
|
||||
local n=PROFILER.dInfo[func]
|
||||
local n = PROFILER.dInfo[func]
|
||||
|
||||
if n.what=="C" then
|
||||
if n.what == "C" then
|
||||
return n.name, "?", "?", PROFILER.fTimeTotal[func]
|
||||
end
|
||||
|
||||
@@ -276,31 +271,31 @@ end
|
||||
--- Write text to log file.
|
||||
-- @param #function f The file.
|
||||
-- @param #string txt The text.
|
||||
function PROFILER._flog(f, txt)
|
||||
f:write(txt.."\r\n")
|
||||
function PROFILER._flog( f, txt )
|
||||
f:write( txt .. "\r\n" )
|
||||
end
|
||||
|
||||
--- Show table.
|
||||
-- @param #table data Data table.
|
||||
-- @param #function f The file.
|
||||
-- @param #number runTimeGame Game run time in seconds.
|
||||
function PROFILER.showTable(data, f, runTimeGame)
|
||||
function PROFILER.showTable( data, f, runTimeGame )
|
||||
|
||||
-- Loop over data.
|
||||
for i=1, #data do
|
||||
local t=data[i] --#PROFILER.Data
|
||||
for i = 1, #data do
|
||||
local t = data[i] -- #PROFILER.Data
|
||||
|
||||
-- Calls per second.
|
||||
local cps=t.count/runTimeGame
|
||||
local cps = t.count / runTimeGame
|
||||
|
||||
local threshCPS=cps>=PROFILER.ThreshCPS
|
||||
local threshTot=t.tm>=PROFILER.ThreshTtot
|
||||
local threshCPS = cps >= PROFILER.ThreshCPS
|
||||
local threshTot = t.tm >= PROFILER.ThreshTtot
|
||||
|
||||
if threshCPS and threshTot then
|
||||
|
||||
-- Output
|
||||
local text=string.format("%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line))
|
||||
PROFILER._flog(f, text)
|
||||
local text = string.format( "%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm / runTimeGame * 100, t.tm / t.count, tostring( t.src ), tostring( t.line ) )
|
||||
PROFILER._flog( f, text )
|
||||
|
||||
end
|
||||
end
|
||||
@@ -310,26 +305,26 @@ end
|
||||
--- Print csv file.
|
||||
-- @param #table data Data table.
|
||||
-- @param #number runTimeGame Game run time in seconds.
|
||||
function PROFILER.printCSV(data, runTimeGame)
|
||||
function PROFILER.printCSV( data, runTimeGame )
|
||||
|
||||
-- Output file.
|
||||
local file=PROFILER.getfilename("csv")
|
||||
local g=io.open(file, 'w')
|
||||
local file = PROFILER.getfilename( "csv" )
|
||||
local g = io.open( file, 'w' )
|
||||
|
||||
-- Header.
|
||||
local text="Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number,"
|
||||
g:write(text.."\r\n")
|
||||
local text = "Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number,"
|
||||
g:write( text .. "\r\n" )
|
||||
|
||||
-- Loop over data.
|
||||
for i=1, #data do
|
||||
local t=data[i] --#PROFILER.Data
|
||||
for i = 1, #data do
|
||||
local t = data[i] -- #PROFILER.Data
|
||||
|
||||
-- Calls per second.
|
||||
local cps=t.count/runTimeGame
|
||||
local cps = t.count / runTimeGame
|
||||
|
||||
-- Output
|
||||
local txt=string.format("%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line))
|
||||
g:write(txt.."\r\n")
|
||||
local txt = string.format( "%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm / runTimeGame * 100, t.tm / t.count, tostring( t.src ), tostring( t.line ) )
|
||||
g:write( txt .. "\r\n" )
|
||||
|
||||
end
|
||||
|
||||
@@ -337,27 +332,26 @@ function PROFILER.printCSV(data, runTimeGame)
|
||||
g:close()
|
||||
end
|
||||
|
||||
|
||||
--- Write info to output file.
|
||||
-- @param #string ext Extension.
|
||||
-- @return #string File name.
|
||||
function PROFILER.getfilename(ext)
|
||||
function PROFILER.getfilename( ext )
|
||||
|
||||
local dir=lfs.writedir()..[[Logs\]]
|
||||
local dir = lfs.writedir() .. [[Logs\]]
|
||||
|
||||
ext=ext or PROFILER.fileNameSuffix
|
||||
ext = ext or PROFILER.fileNameSuffix
|
||||
|
||||
local file=dir..PROFILER.fileNamePrefix.."."..ext
|
||||
local file = dir .. PROFILER.fileNamePrefix .. "." .. ext
|
||||
|
||||
if not UTILS.FileExists(file) then
|
||||
if not UTILS.FileExists( file ) then
|
||||
return file
|
||||
end
|
||||
|
||||
for i=1,999 do
|
||||
for i = 1, 999 do
|
||||
|
||||
local file=string.format("%s%s-%03d.%s", dir,PROFILER.fileNamePrefix, i, ext)
|
||||
local file = string.format( "%s%s-%03d.%s", dir, PROFILER.fileNamePrefix, i, ext )
|
||||
|
||||
if not UTILS.FileExists(file) then
|
||||
if not UTILS.FileExists( file ) then
|
||||
return file
|
||||
end
|
||||
|
||||
@@ -368,81 +362,76 @@ end
|
||||
--- Write info to output file.
|
||||
-- @param #number runTimeGame Game time in seconds.
|
||||
-- @param #number runTimeOS OS time in seconds.
|
||||
function PROFILER.showInfo(runTimeGame, runTimeOS)
|
||||
function PROFILER.showInfo( runTimeGame, runTimeOS )
|
||||
|
||||
-- Output file.
|
||||
local file=PROFILER.getfilename(PROFILER.fileNameSuffix)
|
||||
local f=io.open(file, 'w')
|
||||
local file = PROFILER.getfilename( PROFILER.fileNameSuffix )
|
||||
local f = io.open( file, 'w' )
|
||||
|
||||
-- Gather data.
|
||||
local Ttot=0
|
||||
local Calls=0
|
||||
local Ttot = 0
|
||||
local Calls = 0
|
||||
|
||||
local t={}
|
||||
local t = {}
|
||||
|
||||
local tcopy=nil --#PROFILER.Data
|
||||
local tserialize=nil --#PROFILER.Data
|
||||
local tforgen=nil --#PROFILER.Data
|
||||
local tpairs=nil --#PROFILER.Data
|
||||
local tcopy = nil -- #PROFILER.Data
|
||||
local tserialize = nil -- #PROFILER.Data
|
||||
local tforgen = nil -- #PROFILER.Data
|
||||
local tpairs = nil -- #PROFILER.Data
|
||||
|
||||
for func, count in pairs( PROFILER.Counters ) do
|
||||
|
||||
for func, count in pairs(PROFILER.Counters) do
|
||||
local s, src, line, tm = PROFILER.getData( func )
|
||||
|
||||
local s,src,line,tm=PROFILER.getData(func)
|
||||
|
||||
if PROFILER.logUnknown==true then
|
||||
if s==nil then s="<Unknown>" end
|
||||
if PROFILER.logUnknown == true then
|
||||
if s == nil then
|
||||
s = "<Unknown>"
|
||||
end
|
||||
end
|
||||
|
||||
if s~=nil then
|
||||
if s ~= nil then
|
||||
|
||||
-- Profile data.
|
||||
local T=
|
||||
{ func=s,
|
||||
src=src,
|
||||
line=line,
|
||||
count=count,
|
||||
tm=tm,
|
||||
} --#PROFILER.Data
|
||||
local T = { func = s, src = src, line = line, count = count, tm = tm } -- #PROFILER.Data
|
||||
|
||||
-- Collect special cases. Somehow, e.g. "_copy" appears multiple times so we try to gather all data.
|
||||
if s=="_copy" then
|
||||
if tcopy==nil then
|
||||
tcopy=T
|
||||
if s == "_copy" then
|
||||
if tcopy == nil then
|
||||
tcopy = T
|
||||
else
|
||||
tcopy.count=tcopy.count+T.count
|
||||
tcopy.tm=tcopy.tm+T.tm
|
||||
tcopy.count = tcopy.count + T.count
|
||||
tcopy.tm = tcopy.tm + T.tm
|
||||
end
|
||||
elseif s=="_Serialize" then
|
||||
if tserialize==nil then
|
||||
tserialize=T
|
||||
elseif s == "_Serialize" then
|
||||
if tserialize == nil then
|
||||
tserialize = T
|
||||
else
|
||||
tserialize.count=tserialize.count+T.count
|
||||
tserialize.tm=tserialize.tm+T.tm
|
||||
tserialize.count = tserialize.count + T.count
|
||||
tserialize.tm = tserialize.tm + T.tm
|
||||
end
|
||||
elseif s=="(for generator)" then
|
||||
if tforgen==nil then
|
||||
tforgen=T
|
||||
elseif s == "(for generator)" then
|
||||
if tforgen == nil then
|
||||
tforgen = T
|
||||
else
|
||||
tforgen.count=tforgen.count+T.count
|
||||
tforgen.tm=tforgen.tm+T.tm
|
||||
tforgen.count = tforgen.count + T.count
|
||||
tforgen.tm = tforgen.tm + T.tm
|
||||
end
|
||||
elseif s=="pairs" then
|
||||
if tpairs==nil then
|
||||
tpairs=T
|
||||
elseif s == "pairs" then
|
||||
if tpairs == nil then
|
||||
tpairs = T
|
||||
else
|
||||
tpairs.count=tpairs.count+T.count
|
||||
tpairs.tm=tpairs.tm+T.tm
|
||||
tpairs.count = tpairs.count + T.count
|
||||
tpairs.tm = tpairs.tm + T.tm
|
||||
end
|
||||
else
|
||||
table.insert(t, T)
|
||||
table.insert( t, T )
|
||||
end
|
||||
|
||||
-- Total function time.
|
||||
Ttot=Ttot+tm
|
||||
Ttot = Ttot + tm
|
||||
|
||||
-- Total number of calls.
|
||||
Calls=Calls+count
|
||||
Calls = Calls + count
|
||||
|
||||
end
|
||||
|
||||
@@ -450,90 +439,95 @@ function PROFILER.showInfo(runTimeGame, runTimeOS)
|
||||
|
||||
-- Add special cases.
|
||||
if tcopy then
|
||||
table.insert(t, tcopy)
|
||||
table.insert( t, tcopy )
|
||||
end
|
||||
if tserialize then
|
||||
table.insert(t, tserialize)
|
||||
table.insert( t, tserialize )
|
||||
end
|
||||
if tforgen then
|
||||
table.insert(t, tforgen)
|
||||
table.insert( t, tforgen )
|
||||
end
|
||||
if tpairs then
|
||||
table.insert(t, tpairs)
|
||||
table.insert( t, tpairs )
|
||||
end
|
||||
|
||||
env.info('############################ Profiler Stopped ############################')
|
||||
env.info(string.format("* Runtime Game : %s = %d sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame))
|
||||
env.info(string.format("* Runtime Real : %s = %d sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS))
|
||||
env.info(string.format("* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100))
|
||||
env.info(string.format("* Total functions : %d", #t))
|
||||
env.info(string.format("* Total func calls : %d", Calls))
|
||||
env.info(string.format("* Writing to file : \"%s\"", file))
|
||||
env.info(string.format("* Writing to file : \"%s\"", PROFILER.getfilename("csv")))
|
||||
env.info("##############################################################################")
|
||||
env.info( '############################ Profiler Stopped ############################' )
|
||||
env.info( string.format( "* Runtime Game : %s = %d sec", UTILS.SecondsToClock( runTimeGame, true ), runTimeGame ) )
|
||||
env.info( string.format( "* Runtime Real : %s = %d sec", UTILS.SecondsToClock( runTimeOS, true ), runTimeOS ) )
|
||||
env.info( string.format( "* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock( Ttot, true ), Ttot, Ttot / runTimeGame * 100 ) )
|
||||
env.info( string.format( "* Total functions : %d", #t ) )
|
||||
env.info( string.format( "* Total func calls : %d", Calls ) )
|
||||
env.info( string.format( "* Writing to file : \"%s\"", file ) )
|
||||
env.info( string.format( "* Writing to file : \"%s\"", PROFILER.getfilename( "csv" ) ) )
|
||||
env.info( "##############################################################################" )
|
||||
|
||||
-- Sort by total time.
|
||||
table.sort(t, function(a,b) return a.tm>b.tm end)
|
||||
table.sort( t, function( a, b )
|
||||
return a.tm > b.tm
|
||||
end )
|
||||
|
||||
-- Write data.
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"-------------------------")
|
||||
PROFILER._flog(f,"---- Profiler Report ----")
|
||||
PROFILER._flog(f,"-------------------------")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,string.format("* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame))
|
||||
PROFILER._flog(f,string.format("* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS))
|
||||
PROFILER._flog(f,string.format("* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100))
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,string.format("* Total functions = %d", #t))
|
||||
PROFILER._flog(f,string.format("* Total func calls = %d", Calls))
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,string.format("* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS))
|
||||
PROFILER._flog(f,string.format("* Total func time threshold = %.3f sec", PROFILER.ThreshTtot))
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER.showTable(t, f, runTimeGame)
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "-------------------------" )
|
||||
PROFILER._flog( f, "---- Profiler Report ----" )
|
||||
PROFILER._flog( f, "-------------------------" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, string.format( "* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock( runTimeGame, true ), runTimeGame ) )
|
||||
PROFILER._flog( f, string.format( "* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock( runTimeOS, true ), runTimeOS ) )
|
||||
PROFILER._flog( f, string.format( "* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock( Ttot, true ), Ttot, Ttot / runTimeGame * 100 ) )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, string.format( "* Total functions = %d", #t ) )
|
||||
PROFILER._flog( f, string.format( "* Total func calls = %d", Calls ) )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, string.format( "* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS ) )
|
||||
PROFILER._flog( f, string.format( "* Total func time threshold = %.3f sec", PROFILER.ThreshTtot ) )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER.showTable( t, f, runTimeGame )
|
||||
|
||||
-- Sort by number of calls.
|
||||
table.sort(t, function(a,b) return a.tm/a.count>b.tm/b.count end)
|
||||
table.sort( t, function( a, b )
|
||||
return a.tm / a.count > b.tm / b.count
|
||||
end )
|
||||
|
||||
-- Detailed data.
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"--------------------------------------")
|
||||
PROFILER._flog(f,"---- Data Sorted by Time per Call ----")
|
||||
PROFILER._flog(f,"--------------------------------------")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER.showTable(t, f, runTimeGame)
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "--------------------------------------" )
|
||||
PROFILER._flog( f, "---- Data Sorted by Time per Call ----" )
|
||||
PROFILER._flog( f, "--------------------------------------" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER.showTable( t, f, runTimeGame )
|
||||
|
||||
-- Sort by number of calls.
|
||||
table.sort(t, function(a,b) return a.count>b.count end)
|
||||
table.sort( t, function( a, b )
|
||||
return a.count > b.count
|
||||
end )
|
||||
|
||||
-- Detailed data.
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"------------------------------------")
|
||||
PROFILER._flog(f,"---- Data Sorted by Total Calls ----")
|
||||
PROFILER._flog(f,"------------------------------------")
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER.showTable(t, f, runTimeGame)
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "------------------------------------" )
|
||||
PROFILER._flog( f, "---- Data Sorted by Total Calls ----" )
|
||||
PROFILER._flog( f, "------------------------------------" )
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER.showTable( t, f, runTimeGame )
|
||||
|
||||
-- Closing.
|
||||
PROFILER._flog(f,"")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog(f,"************************************************************************************************************************")
|
||||
PROFILER._flog( f, "" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
||||
-- Close file.
|
||||
f:close()
|
||||
|
||||
-- Print csv file.
|
||||
PROFILER.printCSV(t, runTimeGame)
|
||||
PROFILER.printCSV( t, runTimeGame )
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
--- **Utilities** DCS Simple Text-To-Speech (STTS).
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @module Utils.STTS
|
||||
-- @image MOOSE.JPG
|
||||
|
||||
@@ -15,7 +14,7 @@
|
||||
--
|
||||
-- # DCS Modification Required
|
||||
--
|
||||
-- You will need to edit MissionScripting.lua in DCS World/Scripts/MissionScripting.lua and remove the sanitisation.
|
||||
-- You will need to edit MissionScripting.lua in DCS World/Scripts/MissionScripting.lua and remove the sanitization.
|
||||
-- To do this remove all the code below the comment - the line starts "local function sanitizeModule(name)"
|
||||
-- Do this without DCS running to allow mission scripts to use os functions.
|
||||
--
|
||||
@@ -23,7 +22,7 @@
|
||||
--
|
||||
-- # USAGE:
|
||||
--
|
||||
-- Add this script into the mission as a DO SCRIPT or DO SCRIPT FROM FILE to initialise it
|
||||
-- Add this script into the mission as a DO SCRIPT or DO SCRIPT FROM FILE to initialize it
|
||||
-- Make sure to edit the STTS.SRS_PORT and STTS.DIRECTORY to the correct values before adding to the mission.
|
||||
-- Then its as simple as calling the correct function in LUA as a DO SCRIPT or in your own scripts.
|
||||
--
|
||||
@@ -43,7 +42,7 @@
|
||||
-- * OPTIONAL - Speed -10 to +10
|
||||
-- * OPTIONAL - Gender male, female or neuter
|
||||
-- * OPTIONAL - Culture - en-US, en-GB etc
|
||||
-- * OPTIONAL - Voice - a specfic voice by name. Run DCS-SR-ExternalAudio.exe with --help to get the ones you can use on the command line
|
||||
-- * OPTIONAL - Voice - a specific voice by name. Run DCS-SR-ExternalAudio.exe with --help to get the ones you can use on the command line
|
||||
-- * OPTIONAL - Google TTS - Switch to Google Text To Speech - Requires STTS.GOOGLE_CREDENTIALS path and Google project setup correctly
|
||||
--
|
||||
--
|
||||
@@ -55,7 +54,7 @@
|
||||
--
|
||||
-- ## Example
|
||||
--
|
||||
--This example will say the words "Hello DCS WORLD" on 251 MHz AM at maximum volume with a client called SRS and to the Blue coalition only centered on the position of the Unit called "A UNIT"
|
||||
-- This example will say the words "Hello DCS WORLD" on 251 MHz AM at maximum volume with a client called SRS and to the Blue coalition only centered on the position of the Unit called "A UNIT"
|
||||
--
|
||||
-- STTS.TextToSpeech("Hello DCS WORLD","251","AM","1.0","SRS",2,Unit.getByName("A UNIT"):getPoint(),-5,"male","en-GB")
|
||||
--
|
||||
@@ -75,12 +74,12 @@
|
||||
-- STTS.PlayMP3("C:\\Users\\Ciaran\\Downloads\\PR-Music.mp3","255,31","AM,FM","0.5","Multiple",0)
|
||||
--
|
||||
-- @field #STTS
|
||||
STTS={
|
||||
ClassName="STTS",
|
||||
DIRECTORY="",
|
||||
SRS_PORT=5002,
|
||||
GOOGLE_CREDENTIALS="C:\\Users\\Ciaran\\Downloads\\googletts.json",
|
||||
EXECUTABLE="DCS-SR-ExternalAudio.exe",
|
||||
STTS = {
|
||||
ClassName = "STTS",
|
||||
DIRECTORY = "",
|
||||
SRS_PORT = 5002,
|
||||
GOOGLE_CREDENTIALS = "C:\\Users\\Ciaran\\Downloads\\googletts.json",
|
||||
EXECUTABLE = "DCS-SR-ExternalAudio.exe"
|
||||
}
|
||||
|
||||
--- FULL Path to the FOLDER containing DCS-SR-ExternalAudio.exe - EDIT TO CORRECT FOLDER
|
||||
@@ -92,40 +91,43 @@ STTS.SRS_PORT = 5002
|
||||
--- Google credentials file
|
||||
STTS.GOOGLE_CREDENTIALS = "C:\\Users\\Ciaran\\Downloads\\googletts.json"
|
||||
|
||||
--- DONT CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING
|
||||
--- DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING
|
||||
STTS.EXECUTABLE = "DCS-SR-ExternalAudio.exe"
|
||||
|
||||
|
||||
--- Function for UUID.
|
||||
function STTS.uuid()
|
||||
local random = math.random
|
||||
local template ='yxxx-xxxxxxxxxxxx'
|
||||
return string.gsub(template, '[xy]', function (c)
|
||||
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
|
||||
return string.format('%x', v)
|
||||
end)
|
||||
local template = 'yxxx-xxxxxxxxxxxx'
|
||||
return string.gsub( template, '[xy]', function( c )
|
||||
local v = (c == 'x') and random( 0, 0xf ) or random( 8, 0xb )
|
||||
return string.format( '%x', v )
|
||||
end )
|
||||
end
|
||||
|
||||
--- Round a number.
|
||||
-- @param #number x Number.
|
||||
-- @param #number n Precision.
|
||||
function STTS.round(x, n)
|
||||
n = math.pow(10, n or 0)
|
||||
function STTS.round( x, n )
|
||||
n = math.pow( 10, n or 0 )
|
||||
x = x * n
|
||||
if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end
|
||||
if x >= 0 then
|
||||
x = math.floor( x + 0.5 )
|
||||
else
|
||||
x = math.ceil( x - 0.5 )
|
||||
end
|
||||
return x / n
|
||||
end
|
||||
|
||||
--- Function returns estimated speech time in seconds.
|
||||
-- Assumptions for time calc: 100 Words per min, avarage of 5 letters for english word so
|
||||
-- Assumptions for time calc: 100 Words per min, average of 5 letters for english word so
|
||||
--
|
||||
-- * 5 chars * 100wpm = 500 characters per min = 8.3 chars per second
|
||||
--
|
||||
-- So lengh of msg / 8.3 = number of seconds needed to read it. rounded down to 8 chars per sec map function:
|
||||
-- So length of msg / 8.3 = number of seconds needed to read it. rounded down to 8 chars per sec map function:
|
||||
--
|
||||
-- * (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
|
||||
--
|
||||
function STTS.getSpeechTime(length,speed,isGoogle)
|
||||
function STTS.getSpeechTime( length, speed, isGoogle )
|
||||
|
||||
local maxRateRatio = 3
|
||||
|
||||
@@ -134,100 +136,99 @@ function STTS.getSpeechTime(length,speed,isGoogle)
|
||||
|
||||
local speedFactor = 1.0
|
||||
if isGoogle then
|
||||
speedFactor = speed
|
||||
speedFactor = speed
|
||||
else
|
||||
if speed ~= 0 then
|
||||
speedFactor = math.abs(speed) * (maxRateRatio - 1) / 10 + 1
|
||||
end
|
||||
if speed < 0 then
|
||||
speedFactor = 1/speedFactor
|
||||
end
|
||||
if speed ~= 0 then
|
||||
speedFactor = math.abs( speed ) * (maxRateRatio - 1) / 10 + 1
|
||||
end
|
||||
if speed < 0 then
|
||||
speedFactor = 1 / speedFactor
|
||||
end
|
||||
end
|
||||
|
||||
local wpm = math.ceil(100 * speedFactor)
|
||||
local cps = math.floor((wpm * 5)/60)
|
||||
local wpm = math.ceil( 100 * speedFactor )
|
||||
local cps = math.floor( (wpm * 5) / 60 )
|
||||
|
||||
if type(length) == "string" then
|
||||
length = string.len(length)
|
||||
if type( length ) == "string" then
|
||||
length = string.len( length )
|
||||
end
|
||||
|
||||
return math.ceil(length/cps)
|
||||
return math.ceil( length / cps )
|
||||
end
|
||||
|
||||
--- Text to speech function.
|
||||
function STTS.TextToSpeech(message, freqs, modulations, volume, name, coalition, point, speed, gender, culture, voice, googleTTS)
|
||||
if os == nil or io == nil then
|
||||
env.info("[DCS-STTS] LUA modules os or io are sanitized. skipping. ")
|
||||
return
|
||||
end
|
||||
function STTS.TextToSpeech( message, freqs, modulations, volume, name, coalition, point, speed, gender, culture, voice, googleTTS )
|
||||
if os == nil or io == nil then
|
||||
env.info( "[DCS-STTS] LUA modules os or io are sanitized. skipping. " )
|
||||
return
|
||||
end
|
||||
|
||||
speed = speed or 1
|
||||
gender = gender or "female"
|
||||
culture = culture or ""
|
||||
voice = voice or ""
|
||||
coalition=coalition or "0"
|
||||
name=name or "ROBOT"
|
||||
volume=1
|
||||
speed=1
|
||||
speed = speed or 1
|
||||
gender = gender or "female"
|
||||
culture = culture or ""
|
||||
voice = voice or ""
|
||||
coalition = coalition or "0"
|
||||
name = name or "ROBOT"
|
||||
volume = 1
|
||||
speed = 1
|
||||
|
||||
message = message:gsub( "\"", "\\\"" )
|
||||
|
||||
message = message:gsub("\"","\\\"")
|
||||
|
||||
local cmd = string.format("start /min \"\" /d \"%s\" /b \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -h", STTS.DIRECTORY, STTS.EXECUTABLE, freqs or "305", modulations or "AM", coalition, STTS.SRS_PORT, name)
|
||||
local cmd = string.format( "start /min \"\" /d \"%s\" /b \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -h", STTS.DIRECTORY, STTS.EXECUTABLE, freqs or "305", modulations or "AM", coalition, STTS.SRS_PORT, name )
|
||||
|
||||
if voice ~= "" then
|
||||
cmd = cmd .. string.format(" -V \"%s\"",voice)
|
||||
cmd = cmd .. string.format( " -V \"%s\"", voice )
|
||||
else
|
||||
|
||||
if culture ~= "" then
|
||||
cmd = cmd .. string.format(" -l %s",culture)
|
||||
end
|
||||
if culture ~= "" then
|
||||
cmd = cmd .. string.format( " -l %s", culture )
|
||||
end
|
||||
|
||||
if gender ~= "" then
|
||||
cmd = cmd .. string.format(" -g %s",gender)
|
||||
end
|
||||
if gender ~= "" then
|
||||
cmd = cmd .. string.format( " -g %s", gender )
|
||||
end
|
||||
end
|
||||
|
||||
if googleTTS == true then
|
||||
cmd = cmd .. string.format(" -G \"%s\"",STTS.GOOGLE_CREDENTIALS)
|
||||
cmd = cmd .. string.format( " -G \"%s\"", STTS.GOOGLE_CREDENTIALS )
|
||||
end
|
||||
|
||||
if speed ~= 1 then
|
||||
cmd = cmd .. string.format(" -s %s",speed)
|
||||
cmd = cmd .. string.format( " -s %s", speed )
|
||||
end
|
||||
|
||||
if volume ~= 1.0 then
|
||||
cmd = cmd .. string.format(" -v %s",volume)
|
||||
cmd = cmd .. string.format( " -v %s", volume )
|
||||
end
|
||||
|
||||
if point and type(point) == "table" and point.x then
|
||||
local lat, lon, alt = coord.LOtoLL(point)
|
||||
if point and type( point ) == "table" and point.x then
|
||||
local lat, lon, alt = coord.LOtoLL( point )
|
||||
|
||||
lat = STTS.round(lat,4)
|
||||
lon = STTS.round(lon,4)
|
||||
alt = math.floor(alt)
|
||||
lat = STTS.round( lat, 4 )
|
||||
lon = STTS.round( lon, 4 )
|
||||
alt = math.floor( alt )
|
||||
|
||||
cmd = cmd .. string.format(" -L %s -O %s -A %s",lat,lon,alt)
|
||||
cmd = cmd .. string.format( " -L %s -O %s -A %s", lat, lon, alt )
|
||||
end
|
||||
|
||||
cmd = cmd ..string.format(" -t \"%s\"",message)
|
||||
cmd = cmd .. string.format( " -t \"%s\"", message )
|
||||
|
||||
if string.len(cmd) > 255 then
|
||||
local filename = os.getenv('TMP') .. "\\DCS_STTS-" .. STTS.uuid() .. ".bat"
|
||||
local script = io.open(filename,"w+")
|
||||
script:write(cmd .. " && exit" )
|
||||
script:close()
|
||||
cmd = string.format("\"%s\"",filename)
|
||||
timer.scheduleFunction(os.remove, filename, timer.getTime() + 1)
|
||||
if string.len( cmd ) > 255 then
|
||||
local filename = os.getenv( 'TMP' ) .. "\\DCS_STTS-" .. STTS.uuid() .. ".bat"
|
||||
local script = io.open( filename, "w+" )
|
||||
script:write( cmd .. " && exit" )
|
||||
script:close()
|
||||
cmd = string.format( "\"%s\"", filename )
|
||||
timer.scheduleFunction( os.remove, filename, timer.getTime() + 1 )
|
||||
end
|
||||
|
||||
if string.len(cmd) > 255 then
|
||||
env.info("[DCS-STTS] - cmd string too long")
|
||||
env.info("[DCS-STTS] TextToSpeech Command :\n" .. cmd.."\n")
|
||||
if string.len( cmd ) > 255 then
|
||||
env.info( "[DCS-STTS] - cmd string too long" )
|
||||
env.info( "[DCS-STTS] TextToSpeech Command :\n" .. cmd .. "\n" )
|
||||
end
|
||||
os.execute(cmd)
|
||||
os.execute( cmd )
|
||||
|
||||
return STTS.getSpeechTime(message,speed,googleTTS)
|
||||
return STTS.getSpeechTime( message, speed, googleTTS )
|
||||
end
|
||||
|
||||
--- Play mp3 function.
|
||||
@@ -235,22 +236,21 @@ end
|
||||
-- @param #string freqs Frequencies, e.g. "305, 256".
|
||||
-- @param #string modulations Modulations, e.g. "AM, FM".
|
||||
-- @param #string volume Volume, e.g. "0.5".
|
||||
function STTS.PlayMP3(pathToMP3, freqs, modulations, volume, name, coalition, point)
|
||||
function STTS.PlayMP3( pathToMP3, freqs, modulations, volume, name, coalition, point )
|
||||
|
||||
local cmd = string.format("start \"\" /d \"%s\" /b /min \"%s\" -i \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -v %s -h",
|
||||
STTS.DIRECTORY, STTS.EXECUTABLE, pathToMP3, freqs or "305", modulations or "AM", coalition or "0", STTS.SRS_PORT, name or "ROBOT", volume or "1")
|
||||
local cmd = string.format( "start \"\" /d \"%s\" /b /min \"%s\" -i \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -v %s -h", STTS.DIRECTORY, STTS.EXECUTABLE, pathToMP3, freqs or "305", modulations or "AM", coalition or "0", STTS.SRS_PORT, name or "ROBOT", volume or "1" )
|
||||
|
||||
if point and type(point) == "table" and point.x then
|
||||
local lat, lon, alt = coord.LOtoLL(point)
|
||||
if point and type( point ) == "table" and point.x then
|
||||
local lat, lon, alt = coord.LOtoLL( point )
|
||||
|
||||
lat = STTS.round(lat,4)
|
||||
lon = STTS.round(lon,4)
|
||||
alt = math.floor(alt)
|
||||
lat = STTS.round( lat, 4 )
|
||||
lon = STTS.round( lon, 4 )
|
||||
alt = math.floor( alt )
|
||||
|
||||
cmd = cmd .. string.format(" -L %s -O %s -A %s",lat,lon,alt)
|
||||
end
|
||||
cmd = cmd .. string.format( " -L %s -O %s -A %s", lat, lon, alt )
|
||||
end
|
||||
|
||||
env.info("[DCS-STTS] MP3/OGG Command :\n" .. cmd.."\n")
|
||||
os.execute(cmd)
|
||||
env.info( "[DCS-STTS] MP3/OGG Command :\n" .. cmd .. "\n" )
|
||||
os.execute( cmd )
|
||||
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -310,8 +310,7 @@ end
|
||||
|
||||
--- Returns the @{DCS#Position3} position vectors indicating the point and direction vectors in 3D of the POSITIONABLE within the mission.
|
||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||
-- @return DCS#Position The 3D position vectors of the POSITIONABLE.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
-- @return DCS#Position The 3D position vectors of the POSITIONABLE or #nil if the groups not existing or alive.
|
||||
function GROUP:GetPositionVec3() -- Overridden from POSITIONABLE:GetPositionVec3()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
@@ -339,9 +338,7 @@ end
|
||||
-- If the first @{Wrapper.Unit} of the group is inactive, it will return false.
|
||||
--
|
||||
-- @param #GROUP self
|
||||
-- @return #boolean true if the group is alive and active.
|
||||
-- @return #boolean false if the group is alive but inactive.
|
||||
-- @return #nil if the group does not exist anymore.
|
||||
-- @return #boolean `true` if the group is alive *and* active, `false` if the group is alive but inactive or `#nil` if the group does not exist anymore.
|
||||
function GROUP:IsAlive()
|
||||
self:F2( self.GroupName )
|
||||
|
||||
@@ -363,8 +360,7 @@ end
|
||||
|
||||
--- Returns if the group is activated.
|
||||
-- @param #GROUP self
|
||||
-- @return #boolean true if group is activated.
|
||||
-- @return #nil The group is not existing or alive.
|
||||
-- @return #boolean `true` if group is activated or `#nil` The group is not existing or alive.
|
||||
function GROUP:IsActive()
|
||||
self:F2( self.GroupName )
|
||||
|
||||
@@ -412,7 +408,6 @@ function GROUP:Destroy( GenerateEvent, delay )
|
||||
self:F2( self.GroupName )
|
||||
|
||||
if delay and delay>0 then
|
||||
--SCHEDULER:New(nil, GROUP.Destroy, {self, GenerateEvent}, delay)
|
||||
self:ScheduleOnce(delay, GROUP.Destroy, self, GenerateEvent)
|
||||
else
|
||||
|
||||
@@ -568,12 +563,12 @@ function GROUP:GetSpeedMax()
|
||||
|
||||
local Units=self:GetUnits()
|
||||
|
||||
local speedmax=nil
|
||||
local speedmax=0
|
||||
|
||||
for _,unit in pairs(Units) do
|
||||
local unit=unit --Wrapper.Unit#UNIT
|
||||
local speed=unit:GetSpeedMax()
|
||||
if speedmax==nil then
|
||||
if speedmax==0 then
|
||||
speedmax=speed
|
||||
elseif speed<speedmax then
|
||||
speedmax=speed
|
||||
@@ -2326,41 +2321,44 @@ function GROUP:GetAttribute()
|
||||
local unarmedship=self:HasAttribute("Unarmed ships")
|
||||
|
||||
|
||||
-- Define attribute. Order is important.
|
||||
if transportplane then
|
||||
attribute=GROUP.Attribute.AIR_TRANSPORTPLANE
|
||||
elseif awacs then
|
||||
attribute=GROUP.Attribute.AIR_AWACS
|
||||
elseif fighter then
|
||||
-- Define attribute. Order of attack is important.
|
||||
if fighter then
|
||||
attribute=GROUP.Attribute.AIR_FIGHTER
|
||||
elseif bomber then
|
||||
attribute=GROUP.Attribute.AIR_BOMBER
|
||||
elseif awacs then
|
||||
attribute=GROUP.Attribute.AIR_AWACS
|
||||
elseif transportplane then
|
||||
attribute=GROUP.Attribute.AIR_TRANSPORTPLANE
|
||||
elseif tanker then
|
||||
attribute=GROUP.Attribute.AIR_TANKER
|
||||
elseif transporthelo then
|
||||
attribute=GROUP.Attribute.AIR_TRANSPORTHELO
|
||||
-- helos
|
||||
elseif attackhelicopter then
|
||||
attribute=GROUP.Attribute.AIR_ATTACKHELO
|
||||
elseif transporthelo then
|
||||
attribute=GROUP.Attribute.AIR_TRANSPORTHELO
|
||||
elseif uav then
|
||||
attribute=GROUP.Attribute.AIR_UAV
|
||||
elseif apc then
|
||||
attribute=GROUP.Attribute.GROUND_APC
|
||||
elseif infantry then
|
||||
attribute=GROUP.Attribute.GROUND_INFANTRY
|
||||
elseif artillery then
|
||||
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
||||
elseif tank then
|
||||
attribute=GROUP.Attribute.GROUND_TANK
|
||||
elseif aaa then
|
||||
attribute=GROUP.Attribute.GROUND_AAA
|
||||
-- ground - order of attack
|
||||
elseif ewr then
|
||||
attribute=GROUP.Attribute.GROUND_EWR
|
||||
elseif sam then
|
||||
attribute=GROUP.Attribute.GROUND_SAM
|
||||
elseif aaa then
|
||||
attribute=GROUP.Attribute.GROUND_AAA
|
||||
elseif artillery then
|
||||
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
||||
elseif tank then
|
||||
attribute=GROUP.Attribute.GROUND_TANK
|
||||
elseif apc then
|
||||
attribute=GROUP.Attribute.GROUND_APC
|
||||
elseif infantry then
|
||||
attribute=GROUP.Attribute.GROUND_INFANTRY
|
||||
elseif truck then
|
||||
attribute=GROUP.Attribute.GROUND_TRUCK
|
||||
elseif train then
|
||||
attribute=GROUP.Attribute.GROUND_TRAIN
|
||||
-- ships
|
||||
elseif aircraftcarrier then
|
||||
attribute=GROUP.Attribute.NAVAL_AIRCRAFTCARRIER
|
||||
elseif warship then
|
||||
@@ -2578,8 +2576,10 @@ end
|
||||
-- @return #GROUP self
|
||||
function GROUP:SetCommandInvisible(switch)
|
||||
self:F2( self.GroupName )
|
||||
local switch = switch or false
|
||||
local SetInvisible = {id = 'SetInvisible', params = {value = true}}
|
||||
if switch==nil then
|
||||
switch=false
|
||||
end
|
||||
local SetInvisible = {id = 'SetInvisible', params = {value = switch}}
|
||||
self:SetCommand(SetInvisible)
|
||||
return self
|
||||
end
|
||||
@@ -2590,9 +2590,11 @@ end
|
||||
-- @return #GROUP self
|
||||
function GROUP:SetCommandImmortal(switch)
|
||||
self:F2( self.GroupName )
|
||||
local switch = switch or false
|
||||
local SetInvisible = {id = 'SetImmortal', params = {value = true}}
|
||||
self:SetCommand(SetInvisible)
|
||||
if switch==nil then
|
||||
switch=false
|
||||
end
|
||||
local SetImmortal = {id = 'SetImmortal', params = {value = switch}}
|
||||
self:SetCommand(SetImmortal)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,11 +10,8 @@
|
||||
--
|
||||
-- @module Wrapper.Static
|
||||
-- @image Wrapper_Static.JPG
|
||||
|
||||
|
||||
--- @type STATIC
|
||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||
|
||||
--- Wrapper class to handle Static objects.
|
||||
--
|
||||
-- Note that Statics are almost the same as Units, but they don't have a controller.
|
||||
@@ -40,13 +37,10 @@
|
||||
--
|
||||
-- * @{#STATIC.FindByName}(): Find a STATIC instance from the _DATABASE object using a DCS Static name.
|
||||
--
|
||||
-- IMPORTANT: ONE SHOULD NEVER SANATIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil).
|
||||
-- IMPORTANT: ONE SHOULD NEVER SANITIZE these STATIC OBJECT REFERENCES! (make the STATIC object references nil).
|
||||
--
|
||||
-- @field #STATIC
|
||||
STATIC = {
|
||||
ClassName = "STATIC",
|
||||
}
|
||||
|
||||
STATIC = { ClassName = "STATIC" }
|
||||
|
||||
--- Register a static object.
|
||||
-- @param #STATIC self
|
||||
@@ -58,7 +52,6 @@ function STATIC:Register( StaticName )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Finds a STATIC from the _DATABASE using a DCSStatic object.
|
||||
-- @param #STATIC self
|
||||
-- @param DCS#StaticObject DCSStatic An existing DCS Static object reference.
|
||||
@@ -85,7 +78,7 @@ function STATIC:FindByName( StaticName, RaiseError )
|
||||
self.StaticName = StaticName
|
||||
|
||||
if StaticFound then
|
||||
return StaticFound
|
||||
return StaticFound
|
||||
end
|
||||
|
||||
if RaiseError == nil or RaiseError == true then
|
||||
@@ -97,8 +90,9 @@ end
|
||||
|
||||
--- Destroys the STATIC.
|
||||
-- @param #STATIC self
|
||||
-- @param #boolean GenerateEvent (Optional) true if you want to generate a crash or dead event for the static.
|
||||
-- @param #boolean GenerateEvent (Optional) true to generate a crash or dead event, false to not generate any event. `nil` (default) creates a remove event.
|
||||
-- @return #nil The DCS StaticObject is not existing or alive.
|
||||
--
|
||||
-- @usage
|
||||
-- -- Air static example: destroy the static Helicopter and generate a S_EVENT_CRASH.
|
||||
-- Helicopter = STATIC:FindByName( "Helicopter" )
|
||||
@@ -117,7 +111,7 @@ end
|
||||
-- @usage
|
||||
-- -- Destroy without event generation example.
|
||||
-- Ship = STATIC:FindByName( "Boat" )
|
||||
-- Ship:Destroy( false ) -- Don't generate an event upon destruction.
|
||||
-- Ship:Destroy( false ) -- Don't generate any event upon destruction.
|
||||
--
|
||||
function STATIC:Destroy( GenerateEvent )
|
||||
self:F2( self.ObjectName )
|
||||
@@ -148,7 +142,6 @@ function STATIC:Destroy( GenerateEvent )
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Get DCS object of static of static.
|
||||
-- @param #STATIC self
|
||||
-- @return DCS static object
|
||||
@@ -180,7 +173,6 @@ function STATIC:GetUnits()
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Get threat level of static.
|
||||
-- @param #STATIC self
|
||||
-- @return #number Threat level 1.
|
||||
@@ -194,15 +186,15 @@ end
|
||||
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
||||
-- @param #number Heading The heading of the static respawn in degrees. Default is 0 deg.
|
||||
-- @param #number Delay Delay in seconds before the static is spawned.
|
||||
function STATIC:SpawnAt(Coordinate, Heading, Delay)
|
||||
function STATIC:SpawnAt( Coordinate, Heading, Delay )
|
||||
|
||||
Heading=Heading or 0
|
||||
Heading = Heading or 0
|
||||
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil, self.SpawnAt, {self, Coordinate, Heading}, Delay)
|
||||
if Delay and Delay > 0 then
|
||||
SCHEDULER:New( nil, self.SpawnAt, { self, Coordinate, Heading }, Delay )
|
||||
else
|
||||
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName)
|
||||
local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName )
|
||||
|
||||
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
||||
|
||||
@@ -211,47 +203,43 @@ function STATIC:SpawnAt(Coordinate, Heading, Delay)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Respawn the @{Wrapper.Unit} at the same location with the same properties.
|
||||
-- This is useful to respawn a cargo after it has been destroyed.
|
||||
-- @param #STATIC self
|
||||
-- @param DCS#country.id CountryID (Optional) The country ID used for spawning the new static. Default is same as currently.
|
||||
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default now.
|
||||
function STATIC:ReSpawn(CountryID, Delay)
|
||||
function STATIC:ReSpawn( CountryID, Delay )
|
||||
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil, self.ReSpawn, {self, CountryID}, Delay)
|
||||
if Delay and Delay > 0 then
|
||||
SCHEDULER:New( nil, self.ReSpawn, { self, CountryID }, Delay )
|
||||
else
|
||||
|
||||
CountryID=CountryID or self:GetCountry()
|
||||
CountryID = CountryID or self:GetCountry()
|
||||
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, CountryID)
|
||||
local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName, CountryID )
|
||||
|
||||
SpawnStatic:Spawn(nil, self.StaticName)
|
||||
SpawnStatic:Spawn( nil, self.StaticName )
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Respawn the @{Wrapper.Unit} at a defined Coordinate with an optional heading.
|
||||
-- @param #STATIC self
|
||||
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
||||
-- @param #number Heading (Optional) The heading of the static respawn in degrees. Default the current heading.
|
||||
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default now.
|
||||
function STATIC:ReSpawnAt(Coordinate, Heading, Delay)
|
||||
-- @param #number Heading (Optional) The heading of the static respawn in degrees. Default is the current heading.
|
||||
-- @param #number Delay (Optional) Delay in seconds before static is respawned. Default is now.
|
||||
function STATIC:ReSpawnAt( Coordinate, Heading, Delay )
|
||||
|
||||
--Heading=Heading or 0
|
||||
-- Heading=Heading or 0
|
||||
|
||||
if Delay and Delay>0 then
|
||||
SCHEDULER:New(nil, self.ReSpawnAt, {self, Coordinate, Heading}, Delay)
|
||||
if Delay and Delay > 0 then
|
||||
SCHEDULER:New( nil, self.ReSpawnAt, { self, Coordinate, Heading }, Delay )
|
||||
else
|
||||
local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName, self:GetCountry() )
|
||||
|
||||
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName, self:GetCountry())
|
||||
|
||||
SpawnStatic:SpawnFromCoordinate(Coordinate, Heading, self.StaticName)
|
||||
|
||||
SpawnStatic:SpawnFromCoordinate( Coordinate, Heading, self.StaticName )
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
@@ -168,9 +168,6 @@ function UNIT:GetDCSObject()
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Respawn the @{Wrapper.Unit} using a (tweaked) template of the parent Group.
|
||||
--
|
||||
-- This function will:
|
||||
@@ -263,8 +260,6 @@ function UNIT:ReSpawnAt( Coordinate, Heading )
|
||||
_DATABASE:Spawn( SpawnGroupTemplate )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Returns if the unit is activated.
|
||||
-- @param #UNIT self
|
||||
-- @return #boolean `true` if Unit is activated. `nil` The DCS Unit is not existing or alive.
|
||||
@@ -301,8 +296,6 @@ function UNIT:IsAlive()
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Returns the Unit's callsign - the localized string.
|
||||
-- @param #UNIT self
|
||||
-- @return #string The Callsign of the Unit.
|
||||
@@ -442,7 +435,7 @@ function UNIT:GetSpeedMax()
|
||||
return SpeedMax*3.6
|
||||
end
|
||||
|
||||
return nil
|
||||
return 0
|
||||
end
|
||||
|
||||
--- Returns the unit's max range in meters derived from the DCS descriptors.
|
||||
@@ -626,8 +619,8 @@ function UNIT:GetAmmunition()
|
||||
-- Type name of current weapon.
|
||||
local Tammo=ammotable[w]["desc"]["typeName"]
|
||||
|
||||
local _weaponString = UTILS.Split(Tammo,"%.")
|
||||
local _weaponName = _weaponString[#_weaponString]
|
||||
--local _weaponString = UTILS.Split(Tammo,"%.")
|
||||
--local _weaponName = _weaponString[#_weaponString]
|
||||
|
||||
-- Get the weapon category: shell=0, missile=1, rocket=2, bomb=3
|
||||
local Category=ammotable[w].desc.category
|
||||
@@ -656,7 +649,8 @@ function UNIT:GetAmmunition()
|
||||
|
||||
elseif Category==Weapon.Category.MISSILE then
|
||||
|
||||
-- Add up all cruise missiles (category 5)
|
||||
|
||||
-- Add up all missiles (category 5)
|
||||
if MissileCategory==Weapon.MissileCategory.AAM then
|
||||
nmissiles=nmissiles+Nammo
|
||||
elseif MissileCategory==Weapon.MissileCategory.ANTI_SHIP then
|
||||
@@ -665,6 +659,10 @@ function UNIT:GetAmmunition()
|
||||
nmissiles=nmissiles+Nammo
|
||||
elseif MissileCategory==Weapon.MissileCategory.OTHER then
|
||||
nmissiles=nmissiles+Nammo
|
||||
elseif MissileCategory==Weapon.MissileCategory.SAM then
|
||||
nmissiles=nmissiles+Nammo
|
||||
elseif MissileCategory==Weapon.MissileCategory.CRUISE then
|
||||
nmissiles=nmissiles+Nammo
|
||||
end
|
||||
|
||||
end
|
||||
@@ -956,7 +954,6 @@ end
|
||||
-- @return #string Some text.
|
||||
function UNIT:GetThreatLevel()
|
||||
|
||||
|
||||
local ThreatLevel = 0
|
||||
local ThreatText = ""
|
||||
|
||||
@@ -982,7 +979,6 @@ function UNIT:GetThreatLevel()
|
||||
"LR SAMs"
|
||||
}
|
||||
|
||||
|
||||
if Attributes["LR SAM"] then ThreatLevel = 10
|
||||
elseif Attributes["MR SAM"] then ThreatLevel = 9
|
||||
elseif Attributes["SR SAM"] and
|
||||
@@ -1018,7 +1014,6 @@ function UNIT:GetThreatLevel()
|
||||
"Fighter"
|
||||
}
|
||||
|
||||
|
||||
if Attributes["Fighters"] then ThreatLevel = 10
|
||||
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
||||
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
||||
@@ -1136,12 +1131,6 @@ function UNIT:OtherUnitInRadius( AwaitUnit, Radius )
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Returns if the unit is a friendly unit.
|
||||
-- @param #UNIT self
|
||||
-- @return #boolean IsFriendly evaluation result.
|
||||
|
||||
Reference in New Issue
Block a user