Merge branch 'master' into beacons

This commit is contained in:
Grey-Echo
2017-04-19 15:33:24 +02:00
361 changed files with 26099 additions and 43083 deletions

View File

@@ -219,16 +219,17 @@ local _ClassID = 0
BASE = {
ClassName = "BASE",
ClassID = 0,
_Private = {},
Events = {},
States = {}
States = {},
_ = {},
}
--- The Formation Class
-- @type FORMATION
-- @field Cone A cone formation.
FORMATION = {
Cone = "Cone"
Cone = "Cone",
Vee = "Vee"
}
@@ -360,7 +361,7 @@ do -- Event Handling
-- @param #BASE self
-- @return #number The @{Event} processing Priority.
function BASE:GetEventPriority()
return self._Private.EventPriority or 5
return self._.EventPriority or 5
end
--- Set the Class @{Event} processing Priority.
@@ -370,7 +371,7 @@ do -- Event Handling
-- @param #number EventPriority The @{Event} processing Priority.
-- @return self
function BASE:SetEventPriority( EventPriority )
self._Private.EventPriority = EventPriority
self._.EventPriority = EventPriority
end
--- Remove all subscribed events

File diff suppressed because it is too large Load Diff

View File

@@ -6,12 +6,14 @@
-- ===================================================
-- Mission designers can use the DATABASE class to refer to:
--
-- * STATICS
-- * UNITS
-- * GROUPS
-- * CLIENTS
-- * AIRPORTS
-- * AIRBASES
-- * PLAYERSJOINED
-- * PLAYERS
-- * CARGOS
--
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
--
@@ -44,6 +46,7 @@ DATABASE = {
Templates = {
Units = {},
Groups = {},
Statics = {},
ClientsByName = {},
ClientsByID = {},
},
@@ -53,6 +56,7 @@ DATABASE = {
PLAYERS = {},
PLAYERSJOINED = {},
CLIENTS = {},
CARGOS = {},
AIRBASES = {},
COUNTRY_ID = {},
COUNTRY_NAME = {},
@@ -84,13 +88,15 @@ local _DATABASECategory =
function DATABASE:New()
-- Inherits from BASE
local self = BASE:Inherit( self, BASE:New() )
local self = BASE:Inherit( self, BASE:New() ) -- #DATABASE
self:SetEventPriority( 1 )
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.NewCargo )
self:HandleEvent( EVENTS.DeleteCargo )
-- Follow alive players and clients
self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit )
@@ -166,22 +172,24 @@ end
--- Adds a Airbase based on the Airbase Name in the DATABASE.
-- @param #DATABASE self
function DATABASE:AddAirbase( DCSAirbaseName )
-- @param #string AirbaseName The name of the airbase
function DATABASE:AddAirbase( AirbaseName )
if not self.AIRBASES[DCSAirbaseName] then
self.AIRBASES[DCSAirbaseName] = AIRBASE:Register( DCSAirbaseName )
if not self.AIRBASES[AirbaseName] then
self.AIRBASES[AirbaseName] = AIRBASE:Register( AirbaseName )
end
end
--- Deletes a Airbase from the DATABASE based on the Airbase Name.
-- @param #DATABASE self
function DATABASE:DeleteAirbase( DCSAirbaseName )
-- @param #string AirbaseName The name of the airbase
function DATABASE:DeleteAirbase( AirbaseName )
--self.AIRBASES[DCSAirbaseName] = nil
self.AIRBASES[AirbaseName] = nil
end
--- Finds a AIRBASE based on the AirbaseName.
--- Finds an AIRBASE based on the AirbaseName.
-- @param #DATABASE self
-- @param #string AirbaseName
-- @return Wrapper.Airbase#AIRBASE The found AIRBASE.
@@ -191,6 +199,35 @@ function DATABASE:FindAirbase( AirbaseName )
return AirbaseFound
end
--- Adds a Cargo based on the Cargo Name in the DATABASE.
-- @param #DATABASE self
-- @param #string CargoName The name of the airbase
function DATABASE:AddCargo( Cargo )
if not self.CARGOS[Cargo.Name] then
self.CARGOS[Cargo.Name] = Cargo
end
end
--- Deletes a Cargo from the DATABASE based on the Cargo Name.
-- @param #DATABASE self
-- @param #string CargoName The name of the airbase
function DATABASE:DeleteCargo( CargoName )
self.CARGOS[CargoName] = nil
end
--- Finds an CARGO based on the CargoName.
-- @param #DATABASE self
-- @param #string CargoName
-- @return Wrapper.Cargo#CARGO The found CARGO.
function DATABASE:FindCargo( CargoName )
local CargoFound = self.CARGOS[CargoName]
return CargoFound
end
--- Finds a CLIENT based on the ClientName.
-- @param #DATABASE self
@@ -282,7 +319,7 @@ function DATABASE:Spawn( SpawnTemplate )
SpawnTemplate.CountryID = nil
SpawnTemplate.CategoryID = nil
self:_RegisterTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID )
self:_RegisterGroupTemplate( SpawnTemplate, SpawnCoalitionID, SpawnCategoryID, SpawnCountryID )
self:T3( SpawnTemplate )
coalition.addGroup( SpawnCountryID, SpawnCategoryID, SpawnTemplate )
@@ -318,7 +355,7 @@ end
-- @param #DATABASE self
-- @param #table GroupTemplate
-- @return #DATABASE self
function DATABASE:_RegisterTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID )
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID )
local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name)
@@ -396,6 +433,54 @@ function DATABASE:GetGroupTemplate( GroupName )
return GroupTemplate
end
--- Private method that registers new Static Templates within the DATABASE Object.
-- @param #DATABASE self
-- @param #table GroupTemplate
-- @return #DATABASE self
function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, CategoryID, CountryID )
local TraceTable = {}
local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name)
self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {}
StaticTemplate.CategoryID = CategoryID
StaticTemplate.CoalitionID = CoalitionID
StaticTemplate.CountryID = CountryID
self.Templates.Statics[StaticTemplateName].StaticName = StaticTemplateName
self.Templates.Statics[StaticTemplateName].GroupTemplate = StaticTemplate
self.Templates.Statics[StaticTemplateName].UnitTemplate = StaticTemplate.units[1]
self.Templates.Statics[StaticTemplateName].CategoryID = CategoryID
self.Templates.Statics[StaticTemplateName].CoalitionID = CoalitionID
self.Templates.Statics[StaticTemplateName].CountryID = CountryID
TraceTable[#TraceTable+1] = "Static"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].GroupName
TraceTable[#TraceTable+1] = "Coalition"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CoalitionID
TraceTable[#TraceTable+1] = "Category"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CategoryID
TraceTable[#TraceTable+1] = "Country"
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CountryID
self:E( TraceTable )
end
--- @param #DATABASE self
function DATABASE:GetStaticUnitTemplate( StaticName )
local StaticTemplate = self.Templates.Statics[StaticName].UnitTemplate
StaticTemplate.SpawnCoalitionID = self.Templates.Statics[StaticName].CoalitionID
StaticTemplate.SpawnCategoryID = self.Templates.Statics[StaticName].CategoryID
StaticTemplate.SpawnCountryID = self.Templates.Statics[StaticName].CountryID
return StaticTemplate
end
function DATABASE:GetGroupNameFromUnitName( UnitName )
return self.Templates.Units[UnitName].GroupName
end
@@ -665,7 +750,7 @@ end
--- Iterate the DATABASE and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the database. The function needs to accept a UNIT parameter.
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
-- @return #DATABASE self
function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... )
self:F2( arg )
@@ -677,7 +762,7 @@ end
--- Iterate the DATABASE and call an iterator function for each **alive** GROUP, providing the GROUP and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called when there is an alive GROUP in the database. The function needs to accept a GROUP parameter.
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a GROUP parameter.
-- @return #DATABASE self
function DATABASE:ForEachGroup( IteratorFunction, ... )
self:F2( arg )
@@ -690,7 +775,7 @@ end
--- Iterate the DATABASE and call an iterator function for each **ALIVE** player, providing the player name and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called when there is an player in the database. The function needs to accept the player name.
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept the player name.
-- @return #DATABASE self
function DATABASE:ForEachPlayer( IteratorFunction, ... )
self:F2( arg )
@@ -703,7 +788,7 @@ end
--- Iterate the DATABASE and call an iterator function for each player who has joined the mission, providing the Unit of the player and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called when there is was a player in the database. The function needs to accept a UNIT parameter.
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a UNIT parameter.
-- @return #DATABASE self
function DATABASE:ForEachPlayerJoined( IteratorFunction, ... )
self:F2( arg )
@@ -715,7 +800,7 @@ end
--- Iterate the DATABASE and call an iterator function for each CLIENT, providing the CLIENT to the function and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called when there is an alive player in the database. The function needs to accept a CLIENT parameter.
-- @param #function IteratorFunction The function that will be called object in the database. The function needs to accept a CLIENT parameter.
-- @return #DATABASE self
function DATABASE:ForEachClient( IteratorFunction, ... )
self:F2( arg )
@@ -725,7 +810,44 @@ function DATABASE:ForEachClient( IteratorFunction, ... )
return self
end
--- Iterate the DATABASE and call an iterator function for each CARGO, providing the CARGO object to the function and optional parameters.
-- @param #DATABASE self
-- @param #function IteratorFunction The function that will be called for each object in the database. The function needs to accept a CLIENT parameter.
-- @return #DATABASE self
function DATABASE:ForEachCargo( IteratorFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.CARGOS )
return self
end
--- Handles the OnEventNewCargo event.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA EventData
function DATABASE:OnEventNewCargo( EventData )
self:F2( { EventData } )
if EventData.Cargo then
self:AddCargo( EventData.Cargo )
end
end
--- Handles the OnEventDeleteCargo.
-- @param #DATABASE self
-- @param Core.Event#EVENTDATA EventData
function DATABASE:OnEventDeleteCargo( EventData )
self:F2( { EventData } )
if EventData.Cargo then
self:DeleteCargo( EventData.Cargo.Name )
end
end
--- @param #DATABASE self
function DATABASE:_RegisterTemplates()
self:F2()
@@ -781,11 +903,18 @@ function DATABASE:_RegisterTemplates()
--self.Units[coa_name][countryName][category] = {}
for group_num, GroupTemplate in pairs(obj_type_data.group) do
for group_num, Template in pairs(obj_type_data.group) do
if GroupTemplate and GroupTemplate.units and type(GroupTemplate.units) == 'table' then --making sure again- this is a valid group
self:_RegisterTemplate(
GroupTemplate,
if obj_type_name ~= "static" and Template and Template.units and type(Template.units) == 'table' then --making sure again- this is a valid group
self:_RegisterGroupTemplate(
Template,
CoalitionSide,
_DATABASECategory[string.lower(CategoryName)],
CountryID
)
else
self:_RegisterStaticTemplate(
Template,
CoalitionSide,
_DATABASECategory[string.lower(CategoryName)],
CountryID

View File

@@ -197,6 +197,9 @@ EVENT = {
ClassID = 0,
}
world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001
--- The different types of events supported by MOOSE.
-- Use this structure to subscribe to events using the @{Base#BASE.HandleEvent}() method.
-- @type EVENTS
@@ -224,13 +227,15 @@ EVENTS = {
PlayerComment = world.event.S_EVENT_PLAYER_COMMENT,
ShootingStart = world.event.S_EVENT_SHOOTING_START,
ShootingEnd = world.event.S_EVENT_SHOOTING_END,
NewCargo = world.event.S_EVENT_NEW_CARGO,
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
}
--- The Event structure
-- Note that at the beginning of each field description, there is an indication which field will be populated depending on the object type involved in the Event:
--
-- * A (Object.Category.)UNIT : A UNIT object type is involved in the Event.
-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ
-- * A (Object.Category.)STATIC : A STATIC object type is involved in the Event.µ
--
-- @type EVENTDATA
-- @field #number id The identifier of the event.
@@ -271,122 +276,156 @@ EVENTS = {
-- @field WeaponTgtDCSUnit
local _EVENTMETA = {
[world.event.S_EVENT_SHOT] = {
Order = 1,
Side = "I",
Event = "OnEventShot",
Text = "S_EVENT_SHOT"
},
[world.event.S_EVENT_HIT] = {
Order = 1,
Side = "T",
Event = "OnEventHit",
Text = "S_EVENT_HIT"
},
[world.event.S_EVENT_TAKEOFF] = {
Order = 1,
Side = "I",
Event = "OnEventTakeoff",
Text = "S_EVENT_TAKEOFF"
},
[world.event.S_EVENT_LAND] = {
Order = 1,
Side = "I",
Event = "OnEventLand",
Text = "S_EVENT_LAND"
},
[world.event.S_EVENT_CRASH] = {
Order = -1,
Side = "I",
Event = "OnEventCrash",
Text = "S_EVENT_CRASH"
},
[world.event.S_EVENT_EJECTION] = {
Order = 1,
Side = "I",
Event = "OnEventEjection",
Text = "S_EVENT_EJECTION"
},
[world.event.S_EVENT_REFUELING] = {
Order = 1,
Side = "I",
Event = "OnEventRefueling",
Text = "S_EVENT_REFUELING"
},
[world.event.S_EVENT_DEAD] = {
Order = -1,
Side = "I",
Event = "OnEventDead",
Text = "S_EVENT_DEAD"
},
[world.event.S_EVENT_PILOT_DEAD] = {
Order = 1,
Side = "I",
Event = "OnEventPilotDead",
Text = "S_EVENT_PILOT_DEAD"
},
[world.event.S_EVENT_BASE_CAPTURED] = {
Order = 1,
Side = "I",
Event = "OnEventBaseCaptured",
Text = "S_EVENT_BASE_CAPTURED"
},
[world.event.S_EVENT_MISSION_START] = {
Order = 1,
Side = "N",
Event = "OnEventMissionStart",
Text = "S_EVENT_MISSION_START"
},
[world.event.S_EVENT_MISSION_END] = {
Order = 1,
Side = "N",
Event = "OnEventMissionEnd",
Text = "S_EVENT_MISSION_END"
},
[world.event.S_EVENT_TOOK_CONTROL] = {
Order = 1,
Side = "N",
Event = "OnEventTookControl",
Text = "S_EVENT_TOOK_CONTROL"
},
[world.event.S_EVENT_REFUELING_STOP] = {
Order = 1,
Side = "I",
Event = "OnEventRefuelingStop",
Text = "S_EVENT_REFUELING_STOP"
},
[world.event.S_EVENT_BIRTH] = {
Order = 1,
Side = "I",
Event = "OnEventBirth",
Text = "S_EVENT_BIRTH"
},
[world.event.S_EVENT_HUMAN_FAILURE] = {
Order = 1,
Side = "I",
Event = "OnEventHumanFailure",
Text = "S_EVENT_HUMAN_FAILURE"
},
[world.event.S_EVENT_ENGINE_STARTUP] = {
Order = 1,
Side = "I",
Event = "OnEventEngineStartup",
Text = "S_EVENT_ENGINE_STARTUP"
},
[world.event.S_EVENT_ENGINE_SHUTDOWN] = {
Order = 1,
Side = "I",
Event = "OnEventEngineShutdown",
Text = "S_EVENT_ENGINE_SHUTDOWN"
},
[world.event.S_EVENT_PLAYER_ENTER_UNIT] = {
Order = 1,
Side = "I",
Event = "OnEventPlayerEnterUnit",
Text = "S_EVENT_PLAYER_ENTER_UNIT"
},
[world.event.S_EVENT_PLAYER_LEAVE_UNIT] = {
Order = -1,
Side = "I",
Event = "OnEventPlayerLeaveUnit",
Text = "S_EVENT_PLAYER_LEAVE_UNIT"
},
[world.event.S_EVENT_PLAYER_COMMENT] = {
Order = 1,
Side = "I",
Event = "OnEventPlayerComment",
Text = "S_EVENT_PLAYER_COMMENT"
},
[world.event.S_EVENT_SHOOTING_START] = {
Order = 1,
Side = "I",
Event = "OnEventShootingStart",
Text = "S_EVENT_SHOOTING_START"
},
[world.event.S_EVENT_SHOOTING_END] = {
Order = 1,
Side = "I",
Event = "OnEventShootingEnd",
Text = "S_EVENT_SHOOTING_END"
},
[EVENTS.NewCargo] = {
Order = 1,
Event = "OnEventNewCargo",
Text = "S_EVENT_NEW_CARGO"
},
[EVENTS.DeleteCargo] = {
Order = 1,
Event = "OnEventDeleteCargo",
Text = "S_EVENT_DELETE_CARGO"
},
}
@@ -401,13 +440,6 @@ function EVENT:New()
return self
end
function EVENT:EventText( EventID )
local EventText = _EVENTMETA[EventID].Text
return EventText
end
--- Initializes the Events structure for the event
-- @param #EVENT self
@@ -419,7 +451,7 @@ function EVENT:Init( EventID, EventClass )
if not self.Events[EventID] then
-- Create a WEAK table to ensure that the garbage collector is cleaning the event links when the object usage is cleaned.
self.Events[EventID] = setmetatable( {}, { __mode = "k" } )
self.Events[EventID] = {}
end
-- Each event has a subtable of EventClasses, ordered by EventPriority.
@@ -429,53 +461,56 @@ function EVENT:Init( EventID, EventClass )
end
if not self.Events[EventID][EventPriority][EventClass] then
self.Events[EventID][EventPriority][EventClass] = setmetatable( {}, { __mode = "v" } )
self.Events[EventID][EventPriority][EventClass] = {}
end
return self.Events[EventID][EventPriority][EventClass]
end
--- Removes an Events entry
--- Removes a subscription
-- @param #EVENT self
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param Dcs.DCSWorld#world.event EventID
-- @return #EVENT.Events
function EVENT:Remove( EventClass, EventID )
self:F3( { EventClass, _EVENTMETA[EventID].Text } )
local EventClass = EventClass
self:E( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
local EventPriority = EventClass:GetEventPriority()
self.EventsDead = self.EventsDead or {}
self.EventsDead[EventID] = self.EventsDead[EventID] or {}
self.EventsDead[EventID][EventPriority] = self.EventsDead[EventID][EventPriority] or {}
self.EventsDead[EventID][EventPriority][EventClass] = self.Events[EventID][EventPriority][EventClass]
self.Events[EventID][EventPriority][EventClass] = nil
end
--- Removes an Events entry for a UNIT.
--- Resets subscriptions
-- @param #EVENT self
-- @param #string UnitName The name of the UNIT.
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param Dcs.DCSWorld#world.event EventID
-- @return #EVENT.Events
function EVENT:RemoveForUnit( UnitName, EventClass, EventID )
self:F3( { EventClass, _EVENTMETA[EventID].Text } )
function EVENT:Reset( EventObject )
local EventClass = EventClass
local EventPriority = EventClass:GetEventPriority()
local Event = self.Events[EventID][EventPriority][EventClass]
Event.EventUnit[UnitName] = nil
self:E( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
local EventPriority = EventObject:GetEventPriority()
for EventID, EventData in pairs( self.Events ) do
if self.EventsDead then
if self.EventsDead[EventID] then
if self.EventsDead[EventID][EventPriority] then
if self.EventsDead[EventID][EventPriority][EventObject] then
self.Events[EventID][EventPriority][EventObject] = self.EventsDead[EventID][EventPriority][EventObject]
end
end
end
end
end
end
--- Removes an Events entry for a GROUP.
-- @param #EVENT self
-- @param #string GroupName The name of the GROUP.
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
-- @param Dcs.DCSWorld#world.event EventID
-- @return #EVENT.Events
function EVENT:RemoveForGroup( GroupName, EventClass, EventID )
self:F3( { EventClass, _EVENTMETA[EventID].Text } )
local EventClass = EventClass
local EventPriority = EventClass:GetEventPriority()
local Event = self.Events[EventID][EventPriority][EventClass]
Event.EventGroup[GroupName] = nil
end
--- Clears all event subscriptions for a @{Base#BASE} derived object.
-- @param #EVENT self
@@ -519,7 +554,6 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
local EventData = self:Init( EventID, EventClass )
EventData.EventFunction = EventFunction
EventData.EventClass = EventClass
return self
end
@@ -536,12 +570,8 @@ function EVENT:OnEventForUnit( UnitName, EventFunction, EventClass, EventID )
self:F2( UnitName )
local EventData = self:Init( EventID, EventClass )
if not EventData.EventUnit then
EventData.EventUnit = {}
end
EventData.EventUnit[UnitName] = {}
EventData.EventUnit[UnitName].EventFunction = EventFunction
EventData.EventUnit[UnitName].EventClass = EventClass
EventData.EventUnit = true
EventData.EventFunction = EventFunction
return self
end
@@ -556,12 +586,8 @@ function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID )
self:F2( GroupName )
local Event = self:Init( EventID, EventClass )
if not Event.EventGroup then
Event.EventGroup = {}
end
Event.EventGroup[GroupName] = {}
Event.EventGroup[GroupName].EventFunction = EventFunction
Event.EventGroup[GroupName].EventClass = EventClass
Event.EventGroup = true
Event.EventFunction = EventFunction
return self
end
@@ -672,6 +698,39 @@ do -- OnEngineShutDown
end
do -- Event Creation
--- Creation of a New Cargo Event.
-- @param #EVENT self
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
function EVENT:CreateEventNewCargo( Cargo )
self:F( { Cargo } )
local Event = {
id = EVENTS.NewCargo,
time = timer.getTime(),
cargo = Cargo,
}
world.onEvent( Event )
end
--- Creation of a Cargo Deletion Event.
-- @param #EVENT self
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
function EVENT:CreateEventDeleteCargo( Cargo )
self:F( { Cargo } )
local Event = {
id = EVENTS.DeleteCargo,
time = timer.getTime(),
cargo = Cargo,
}
world.onEvent( Event )
end
end
--- @param #EVENT self
-- @param #EVENTDATA Event
@@ -687,10 +746,10 @@ function EVENT:onEvent( Event )
return errmsg
end
self:E( _EVENTMETA[Event.id].Text, Event )
local EventMeta = _EVENTMETA[Event.id]
if self and self.Events and self.Events[Event.id] then
if Event.initiator then
@@ -795,12 +854,17 @@ function EVENT:onEvent( Event )
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
end
local PriorityOrder = _EVENTMETA[Event.id].Order
if Event.cargo then
Event.Cargo = Event.cargo
Event.CargoName = Event.cargo.Name
end
local PriorityOrder = EventMeta.Order
local PriorityBegin = PriorityOrder == -1 and 5 or 1
local PriorityEnd = PriorityOrder == -1 and 1 or 5
if Event.IniObjectCategory ~= 3 then
self:E( { _EVENTMETA[Event.id].Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } )
self:E( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } )
end
for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do
@@ -810,186 +874,144 @@ 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
self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
-- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT.
if ( Event.IniDCSUnitName and EventData.EventUnit and EventData.EventUnit[Event.IniDCSUnitName] ) or
( Event.TgtDCSUnitName and EventData.EventUnit and EventData.EventUnit[Event.TgtDCSUnitName] ) then
if EventData.EventUnit then
if EventData.EventUnit[Event.IniDCSUnitName] then
-- First test if a EventFunction is Set, otherwise search for the default function
if EventData.EventUnit[Event.IniDCSUnitName].EventFunction then
-- So now the EventClass must be a UNIT class!!! We check if it is still "Alive".
if EventClass:IsAlive() or
Event.id == EVENTS.Crash or
Event.id == EVENTS.Dead then
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end
local Result, Value = xpcall(
function()
return EventData.EventUnit[Event.IniDCSUnitName].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.id].Event ]
if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function.
local UnitName = EventClass:GetName()
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
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end
local Result, Value = xpcall(
function()
return EventFunction( EventClass, Event )
return EventData.EventFunction( EventClass, Event )
end, ErrorHandler )
end
end
end
if EventData.EventUnit[Event.TgtDCSUnitName] then
-- First test if a EventFunction is Set, otherwise search for the default function
if EventData.EventUnit[Event.TgtDCSUnitName].EventFunction then
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.TgtUnitName, EventPriority } )
end
local Result, Value = xpcall(
function()
return EventData.EventUnit[Event.TgtDCSUnitName].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.id].Event ]
if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
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 ]
if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
function()
return EventFunction( EventClass, Event )
end, ErrorHandler )
end
local Result, Value = xpcall(
function()
return EventFunction( EventClass, Event )
end, ErrorHandler )
end
end
end
else
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
self:Remove( EventClass, Event.id )
end
else
-- If the EventData is for a GROUP, the call directly the EventClass EventFunction for the UNIT in that GROUP.
if ( Event.IniDCSUnitName and Event.IniDCSGroupName and Event.IniGroupName and EventData.EventGroup and EventData.EventGroup[Event.IniGroupName] ) or
( Event.TgtDCSUnitName and Event.TgtDCSGroupName and Event.TgtGroupName and EventData.EventGroup and EventData.EventGroup[Event.TgtGroupName] ) then
if EventData.EventGroup then
if EventData.EventGroup[Event.IniGroupName] then
-- First test if a EventFunction is Set, otherwise search for the default function
if EventData.EventGroup[Event.IniGroupName].EventFunction then
-- So now the EventClass must be a GROUP class!!! We check if it is still "Alive".
if EventClass:IsAlive() or
Event.id == EVENTS.Crash or
Event.id == EVENTS.Dead then
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end
local Result, Value = xpcall(
function()
return EventData.EventGroup[Event.IniGroupName].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.id].Event ]
if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
function()
return EventFunction( EventClass, Event )
end, ErrorHandler )
end
end
end
-- 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 EventData.EventGroup[Event.TgtGroupName] then
if EventData.EventGroup[Event.TgtGroupName].EventFunction then
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.TgtUnitName, EventPriority } )
end
local Result, Value = xpcall(
function()
return EventData.EventGroup[Event.TgtGroupName].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.id].Event ]
if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
function()
return EventFunction( EventClass, Event )
end, ErrorHandler )
end
end
end
else
-- If the EventData is not bound to a specific unit, then call the EventClass EventFunction.
-- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon.
if (Event.IniDCSUnit or Event.WeaponUNIT) and not EventData.EventUnit then
if EventClass == EventData.EventClass then
-- First test if a EventFunction is Set, otherwise search for the default function
if EventData.EventFunction then
-- There is an EventFunction defined, so call the EventFunction.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end
self:E( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
end
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.id].Event ]
local EventFunction = EventClass[ EventMeta.Event ]
if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling " .. _EVENTMETA[Event.id].Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
self:E( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
end
local Result, Value = xpcall(
function()
local Result, Value = EventFunction( EventClass, Event )
return Result, Value
return EventFunction( EventClass, Event )
end, ErrorHandler )
end
end
end
else
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
self:Remove( EventClass, Event.id )
end
else
-- If the EventData is not bound to a specific unit, then call the EventClass EventFunction.
-- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon.
if not EventData.EventUnit then
-- First test if a EventFunction is Set, otherwise search for the default function
if EventData.EventFunction then
-- There is an EventFunction defined, so call the EventFunction.
if Event.IniObjectCategory ~= 3 then
self:E( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } )
end
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 ]
if EventFunction and type( EventFunction ) == "function" then
-- Now call the default event function.
if Event.IniObjectCategory ~= 3 then
self:E( { "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 )
end
end
end
end
end
@@ -997,7 +1019,7 @@ function EVENT:onEvent( Event )
end
end
else
self:E( { _EVENTMETA[Event.id].Text, Event } )
self:E( { EventMeta.Text, Event } )
end
Event = nil

View File

@@ -5,6 +5,8 @@
--
-- ===
--
-- 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.
-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**.
-- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**.
@@ -90,8 +92,43 @@ do -- FSM
-- @extends Core.Base#BASE
--- # 1) FSM class, extends @{Base#BASE}
--- # FSM class, extends @{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.
-- The machine is in only one state at a time; the state it is in at any given time is called the **current state**.
-- It can change from one state to another when initiated by an **__internal__ or __external__ triggering event**, which is called a **transition**.
-- An **FSM implementation** is defined by **a list of its states**, **its initial state**, and **the triggering events** for **each possible transition**.
-- An FSM implementation is composed out of **two parts**, a set of **state transition rules**, and an implementation set of **state transition handlers**, implementing those transitions.
--
-- The FSM class supports a **hierarchical implementation of a Finite State Machine**,
-- that is, it allows to **embed existing FSM implementations in a master FSM**.
-- FSM hierarchies allow for efficient FSM re-use, **not having to re-invent the wheel every time again** when designing complex processes.
--
-- ![Workflow Example](..\Presentations\FSM\Dia2.JPG)
--
-- The above diagram shows a graphical representation of a FSM implementation for a **Task**, which guides a Human towards a Zone,
-- orders him to destroy x targets and account the results.
-- Other examples of ready made FSM could be:
--
-- * route a plane to a zone flown by a human
-- * detect targets by an AI and report to humans
-- * account for destroyed targets by human players
-- * handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle
-- * let an AI patrol a zone
--
-- The **MOOSE framework** uses extensively the FSM class and derived FSM\_ classes,
-- because **the goal of MOOSE is to simplify mission design complexity for mission building**.
-- By efficiently utilizing the FSM class and derived classes, MOOSE allows mission designers to quickly build processes.
-- **Ready made FSM-based implementations classes** exist within the MOOSE framework that **can easily be re-used,
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
-- Each of these FSM implementation classes start either with:
--
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
--
-- ![Transition Rules and Transition Handlers and Event Triggers](..\Presentations\FSM\Dia3.JPG)
--
-- The FSM class is the base class of all FSM\_ derived classes. It implements the main functionality to define and execute Finite State Machines.
@@ -114,13 +151,13 @@ do -- FSM
-- 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**.
--
-- ## 1.1) FSM Linear Transitions
-- ## 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.
-- If no valid Transition Rule can be found in the FSM, the FSM will log an error and stop.
--
-- ### 1.1.1) FSM Transition Rules
-- ### FSM Transition Rules
--
-- The FSM has transition rules that it follows and validates, as it walks the process.
-- These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event.
@@ -145,7 +182,7 @@ do -- FSM
-- * It can be switched **Off** by triggering event **SwitchOff**.
-- * Note that once the Switch is **On** or **Middle**, it can only be switched **Off**.
--
-- ### Some additional comments:
-- #### Some additional comments:
--
-- Note that Linear Transition Rules **can be declared in a few variations**:
--
@@ -156,7 +193,7 @@ do -- FSM
--
-- FsmSwitch:AddTransition( { "On", "Middle" }, "SwitchOff", "Off" )
--
-- ### 1.1.2) Transition Handling
-- ### Transition Handling
--
-- ![Transition Handlers](..\Presentations\FSM\Dia4.JPG)
--
@@ -178,7 +215,7 @@ do -- FSM
--
-- On top, each of these methods can have a variable amount of parameters passed. See the example in section [1.1.3](#1.1.3\)-event-triggers).
--
-- ### 1.1.3) Event Triggers
-- ### Event Triggers
--
-- ![Event Triggers](..\Presentations\FSM\Dia5.JPG)
--
@@ -216,7 +253,7 @@ do -- FSM
--
-- Because ... When Event was asynchronously processed after 5 seconds, Amount was set to 2. So be careful when processing and passing values and objects in asynchronous processing!
--
-- ### 1.1.4) Linear Transition Example
-- ### Linear Transition Example
--
-- This example is fully implemented in the MOOSE test mission on GITHUB: [FSM-100 - Transition Explanation](https://github.com/FlightControl-Master/MOOSE/blob/master/Moose%20Test%20Missions/FSM%20-%20Finite%20State%20Machine/FSM-100%20-%20Transition%20Explanation/FSM-100%20-%20Transition%20Explanation.lua)
--
@@ -298,7 +335,7 @@ do -- FSM
-- So... When FsmDemo:Stop() is being triggered, the state of FsmDemo will transition from Red or Green to Stopped.
-- And there is no transition handling method defined for that transition, thus, no new event is being triggered causing the FsmDemo process flow to halt.
--
-- ## 1.5) FSM Hierarchical Transitions
-- ## FSM Hierarchical Transitions
--
-- Hierarchical Transitions allow to re-use readily available and implemented FSMs.
-- This becomes in very useful for mission building, where mission designers build complex processes and workflows,

View File

@@ -27,109 +27,26 @@
--
-- ===
--
-- The above menus classes **are derived** from 2 main **abstract** classes defined within the MOOSE framework (so don't use these):
-- # **AUTHORS and CONTRIBUTIONS**
--
-- 1) MENU_ BASE abstract base classes (don't use them)
-- ====================================================
-- The underlying base menu classes are **NOT** to be used within your missions.
-- These are simply abstract base classes defining a couple of fields that are used by the
-- derived MENU_ classes to manage menus.
-- ### Contributions:
--
-- 1.1) @{#MENU_BASE} class, extends @{Base#BASE}
-- --------------------------------------------------
-- The @{#MENU_BASE} class defines the main MENU class where other MENU classes are derived from.
--
-- 1.2) @{#MENU_COMMAND_BASE} class, extends @{Base#BASE}
-- ----------------------------------------------------------
-- The @{#MENU_COMMAND_BASE} class defines the main MENU class where other MENU COMMAND_ classes are derived from, in order to set commands.
--
-- ===
--
-- **The next menus define the MENU classes that you can use within your missions.**
--
-- 2) MENU MISSION classes
-- ======================
-- The underlying classes manage the menus for a complete mission file.
--
-- 2.1) @{#MENU_MISSION} class, extends @{Menu#MENU_BASE}
-- ---------------------------------------------------------
-- The @{Menu#MENU_MISSION} class manages the main menus for a complete mission.
-- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION.Remove}.
--
-- 2.2) @{#MENU_MISSION_COMMAND} class, extends @{Menu#MENU_COMMAND_BASE}
-- -------------------------------------------------------------------------
-- The @{Menu#MENU_MISSION_COMMAND} class manages the command menus for a complete mission, which allow players to execute functions during mission execution.
-- You can add menus with the @{#MENU_MISSION_COMMAND.New} method, which constructs a MENU_MISSION_COMMAND object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION_COMMAND.Remove}.
--
-- ===
--
-- 3) MENU COALITION classes
-- =========================
-- The underlying classes manage the menus for whole coalitions.
--
-- 3.1) @{#MENU_COALITION} class, extends @{Menu#MENU_BASE}
-- ------------------------------------------------------------
-- The @{Menu#MENU_COALITION} class manages the main menus for coalitions.
-- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}.
--
-- 3.2) @{Menu#MENU_COALITION_COMMAND} class, extends @{Menu#MENU_COMMAND_BASE}
-- ----------------------------------------------------------------------------
-- The @{Menu#MENU_COALITION_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution.
-- You can add menus with the @{#MENU_COALITION_COMMAND.New} method, which constructs a MENU_COALITION_COMMAND object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION_COMMAND.Remove}.
--
-- ===
--
-- 4) MENU GROUP classes
-- =====================
-- The underlying classes manage the menus for groups. Note that groups can be inactive, alive or can be destroyed.
--
-- 4.1) @{Menu#MENU_GROUP} class, extends @{Menu#MENU_BASE}
-- --------------------------------------------------------
-- The @{Menu#MENU_GROUP} class manages the main menus for coalitions.
-- 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}.
--
-- 4.2) @{Menu#MENU_GROUP_COMMAND} class, extends @{Menu#MENU_COMMAND_BASE}
-- ------------------------------------------------------------------------
-- The @{Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution.
-- You can add menus with the @{#MENU_GROUP_COMMAND.New} method, which constructs a MENU_GROUP_COMMAND 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_COMMAND.Remove}.
--
-- ===
--
-- 5) MENU CLIENT classes
-- ======================
-- The underlying classes manage the menus for units with skill level client or player.
--
-- 5.1) @{Menu#MENU_CLIENT} class, extends @{Menu#MENU_BASE}
-- ---------------------------------------------------------
-- The @{Menu#MENU_CLIENT} class manages the main menus for coalitions.
-- You can add menus with the @{#MENU_CLIENT.New} method, which constructs a MENU_CLIENT object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT.Remove}.
--
-- 5.2) @{Menu#MENU_CLIENT_COMMAND} class, extends @{Menu#MENU_COMMAND_BASE}
-- -------------------------------------------------------------------------
-- The @{Menu#MENU_CLIENT_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution.
-- You can add menus with the @{#MENU_CLIENT_COMMAND.New} method, which constructs a MENU_CLIENT_COMMAND object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT_COMMAND.Remove}.
--
-- ===
--
-- ### Contributions: -
-- ### Authors: FlightControl : Design & Programming
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
--
-- @module Menu
do -- MENU_BASE
--- The MENU_BASE class
-- @type MENU_BASE
--- @type MENU_BASE
-- @extends Base#BASE
--- # MENU_BASE class, extends @{Base#BASE}
-- The MENU_BASE class defines the main MENU class where other MENU classes are derived from.
-- This is an abstract class, so don't use it.
-- @field #MENU_BASE
MENU_BASE = {
ClassName = "MENU_BASE",
MenuPath = nil,
@@ -193,10 +110,15 @@ end
do -- MENU_COMMAND_BASE
--- The MENU_COMMAND_BASE class
-- @type MENU_COMMAND_BASE
--- @type MENU_COMMAND_BASE
-- @field #function MenuCallHandler
-- @extends Core.Menu#MENU_BASE
--- # MENU_COMMAND_BASE class, extends @{Base#BASE}
-- ----------------------------------------------------------
-- The MENU_COMMAND_BASE class defines the main MENU class where other MENU COMMAND_
-- classes are derived from, in order to set commands.
-- @field #MENU_COMMAND_BASE
MENU_COMMAND_BASE = {
ClassName = "MENU_COMMAND_BASE",
CommandMenuFunction = nil,
@@ -224,9 +146,15 @@ end
do -- MENU_MISSION
--- The MENU_MISSION class
-- @type MENU_MISSION
--- @type MENU_MISSION
-- @extends Core.Menu#MENU_BASE
--- # MENU_MISSION class, extends @{Menu#MENU_BASE}
--
-- The MENU_MISSION class manages the main menus for a complete mission.
-- You can add menus with the @{#MENU_MISSION.New} method, which constructs a MENU_MISSION object and returns you the object reference.
-- 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"
}
@@ -291,9 +219,16 @@ end
do -- MENU_MISSION_COMMAND
--- The MENU_MISSION_COMMAND class
-- @type MENU_MISSION_COMMAND
--- @type MENU_MISSION_COMMAND
-- @extends Core.Menu#MENU_COMMAND_BASE
--- # MENU_MISSION_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
--
-- The MENU_MISSION_COMMAND class manages the command menus for a complete mission, which allow players to execute functions during mission execution.
-- You can add menus with the @{#MENU_MISSION_COMMAND.New} method, which constructs a MENU_MISSION_COMMAND object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_MISSION_COMMAND.Remove}.
--
-- @field #MENU_MISSION_COMMAND
MENU_MISSION_COMMAND = {
ClassName = "MENU_MISSION_COMMAND"
}
@@ -341,9 +276,16 @@ end
do -- MENU_COALITION
--- The MENU_COALITION class
-- @type MENU_COALITION
--- @type MENU_COALITION
-- @extends Core.Menu#MENU_BASE
--- # MENU_COALITION class, extends @{Menu#MENU_BASE}
--
-- The @{Menu#MENU_COALITION} class manages the main menus for coalitions.
-- You can add menus with the @{#MENU_COALITION.New} method, which constructs a MENU_COALITION object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION.Remove}.
--
--
-- @usage
-- -- This demo creates a menu structure for the planes within the red coalition.
-- -- To test, join the planes, then look at the other radio menus (Option F10).
@@ -380,6 +322,8 @@ do -- MENU_COALITION
--
-- local MenuAdd = MENU_COALITION_COMMAND:New( coalition.side.RED, "Add Status Menu", MenuCoalitionRed, AddStatusMenu )
-- local MenuRemove = MENU_COALITION_COMMAND:New( coalition.side.RED, "Remove Status Menu", MenuCoalitionRed, RemoveStatusMenu )
--
-- @field #MENU_COALITION
MENU_COALITION = {
ClassName = "MENU_COALITION"
}
@@ -446,9 +390,16 @@ end
do -- MENU_COALITION_COMMAND
--- The MENU_COALITION_COMMAND class
-- @type MENU_COALITION_COMMAND
--- @type MENU_COALITION_COMMAND
-- @extends Core.Menu#MENU_COMMAND_BASE
--- # MENU_COALITION_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
--
-- The MENU_COALITION_COMMAND class manages the command menus for coalitions, which allow players to execute functions during mission execution.
-- You can add menus with the @{#MENU_COALITION_COMMAND.New} method, which constructs a MENU_COALITION_COMMAND object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_COALITION_COMMAND.Remove}.
--
-- @field #MENU_COALITION_COMMAND
MENU_COALITION_COMMAND = {
ClassName = "MENU_COALITION_COMMAND"
}
@@ -506,6 +457,14 @@ do -- MENU_CLIENT
--- MENU_COALITION constructor. Creates a new radio command item for a coalition, which can invoke a function with parameters.
-- @type MENU_CLIENT
-- @extends Core.Menu#MENU_BASE
--- # MENU_CLIENT class, extends @{Menu#MENU_BASE}
--
-- The MENU_CLIENT class manages the main menus for coalitions.
-- You can add menus with the @{#MENU_CLIENT.New} method, which constructs a MENU_CLIENT object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT.Remove}.
--
-- @usage
-- -- This demo creates a menu structure for the two clients of planes.
-- -- Each client will receive a different menu structure.
@@ -555,6 +514,8 @@ do -- MENU_CLIENT
-- MENU_CLIENT_COMMAND:New( PlaneClient, "Remove Status Menu Plane 2", MenuManage, RemoveStatusMenu, PlaneClient )
-- end
-- end, {}, 10, 10 )
--
-- @field #MENU_CLIENT
MENU_CLIENT = {
ClassName = "MENU_CLIENT"
}
@@ -644,9 +605,16 @@ do -- MENU_CLIENT
end
--- The MENU_CLIENT_COMMAND class
-- @type MENU_CLIENT_COMMAND
--- @type MENU_CLIENT_COMMAND
-- @extends Core.Menu#MENU_COMMAND
--- # MENU_CLIENT_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
--
-- The MENU_CLIENT_COMMAND class manages the command menus for coalitions, which allow players to execute functions during mission execution.
-- You can add menus with the @{#MENU_CLIENT_COMMAND.New} method, which constructs a MENU_CLIENT_COMMAND object and returns you the object reference.
-- Using this object reference, you can then remove ALL the menus and submenus underlying automatically with @{#MENU_CLIENT_COMMAND.Remove}.
--
-- @field #MENU_CLIENT_COMMAND
MENU_CLIENT_COMMAND = {
ClassName = "MENU_CLIENT_COMMAND"
}
@@ -730,9 +698,16 @@ do
-- These menu classes are handling this logic with this variable.
local _MENUGROUPS = {}
--- The MENU_GROUP class
-- @type MENU_GROUP
--- @type MENU_GROUP
-- @extends Core.Menu#MENU_BASE
--- #MENU_GROUP class, extends @{Menu#MENU_BASE}
--
-- The MENU_GROUP class manages the main menus for coalitions.
-- 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}.
--
-- @usage
-- -- This demo creates a menu structure for the two groups of planes.
-- -- Each group will receive a different menu structure.
@@ -783,6 +758,7 @@ do
-- end
-- end, {}, 10, 10 )
--
-- @field #MENU_GROUP
MENU_GROUP = {
ClassName = "MENU_GROUP"
}
@@ -876,9 +852,16 @@ do
end
--- The MENU_GROUP_COMMAND class
-- @type MENU_GROUP_COMMAND
--- @type MENU_GROUP_COMMAND
-- @extends Core.Menu#MENU_BASE
--- # MENU_GROUP_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
--
-- The @{Menu#MENU_GROUP_COMMAND} class manages the command menus for coalitions, which allow players to execute functions during mission execution.
-- You can add menus with the @{#MENU_GROUP_COMMAND.New} method, which constructs a MENU_GROUP_COMMAND 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_COMMAND.Remove}.
--
-- @field #MENU_GROUP_COMMAND
MENU_GROUP_COMMAND = {
ClassName = "MENU_GROUP_COMMAND"
}

View File

@@ -4,18 +4,24 @@
--
-- ===
--
-- # 1) @{Message#MESSAGE} class, extends @{Base#BASE}
-- @module Message
--- The MESSAGE class
-- @type MESSAGE
-- @extends Core.Base#BASE
--- # MESSAGE class, extends @{Base#BASE}
--
-- Message System to display Messages to Clients, Coalitions or All.
-- Messages are shown on the display panel for an amount of seconds, and will then disappear.
-- Messages can contain a category which is indicating the category of the message.
--
-- ## 1.1) MESSAGE construction
-- ## MESSAGE construction
--
-- Messages are created with @{Message#MESSAGE.New}. Note that when the MESSAGE object is created, no message is sent yet.
-- To send messages, you need to use the To functions.
--
-- ## 1.2) Send messages to an audience
-- ## Send messages to an audience
--
-- Messages are sent:
--
@@ -26,19 +32,14 @@
-- * To the blue coalition using @{Message#MESSAGE.ToBlue}().
-- * To all Players using @{Message#MESSAGE.ToAll}().
--
-- ## 1.3) Send conditionally to an audience
-- ## Send conditionally to an audience
--
-- Messages can be sent conditionally to an audience (when a condition is true):
--
-- * To all players using @{Message#MESSAGE.ToAllIf}().
-- * To a coalition using @{Message#MESSAGE.ToCoalitionIf}().
--
--
-- @module Message
--- The MESSAGE class
-- @type MESSAGE
-- @extends Core.Base#BASE
-- @field #MESSAGE
MESSAGE = {
ClassName = "MESSAGE",
MessageCategory = 0,

View File

@@ -1,91 +1,22 @@
--- **Core** - **POINT\_VEC** classes define an **extensive API** to **manage 3D points** in the simulation space.
--
-- 1) @{Point#POINT_VEC3} class, extends @{Base#BASE}
-- ==================================================
-- The @{Point#POINT_VEC3} class defines a 3D point in the simulator.
--
-- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts.
-- In order to keep the credibility of the the author, I want to emphasize that the of the MIST framework was created by Grimes, who you can find on the Eagle Dynamics Forums.
--
-- ## 1.1) POINT_VEC3 constructor
--
-- A new POINT_VEC3 instance can be created with:
--
-- * @{Point#POINT_VEC3.New}(): a 3D point.
-- * @{Point#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{DCSTypes#Vec3}.
--
-- ## 1.2) Manupulate the X, Y, Z coordinates of the point
--
-- A POINT_VEC3 class works in 3D space. It contains internally an X, Y, Z coordinate.
-- Methods exist to manupulate these coordinates.
--
-- The current X, Y, Z axis can be retrieved with the methods @{#POINT_VEC3.GetX}(), @{#POINT_VEC3.GetY}(), @{#POINT_VEC3.GetZ}() respectively.
-- The methods @{#POINT_VEC3.SetX}(), @{#POINT_VEC3.SetY}(), @{#POINT_VEC3.SetZ}() change the respective axis with a new value.
-- The current axis values can be changed by using the methods @{#POINT_VEC3.AddX}(), @{#POINT_VEC3.AddY}(), @{#POINT_VEC3.AddZ}()
-- to add or substract a value from the current respective axis value.
-- Note that the Set and Add methods return the current POINT_VEC3 object, so these manipulation methods can be chained... For example:
--
-- local Vec3 = PointVec3:AddX( 100 ):AddZ( 150 ):GetVec3()
--
-- ## 1.3) Create waypoints for routes
--
-- A POINT_VEC3 can prepare waypoints for Ground, Air and Naval groups to be embedded into a Route.
--
--
-- ## 1.5) Smoke, flare, explode, illuminate
--
-- At the point a smoke, flare, explosion and illumination bomb can be triggered. Use the following methods:
--
-- ### 1.5.1) Smoke
--
-- * @{#POINT_VEC3.Smoke}(): To smoke the point in a certain color.
-- * @{#POINT_VEC3.SmokeBlue}(): To smoke the point in blue.
-- * @{#POINT_VEC3.SmokeRed}(): To smoke the point in red.
-- * @{#POINT_VEC3.SmokeOrange}(): To smoke the point in orange.
-- * @{#POINT_VEC3.SmokeWhite}(): To smoke the point in white.
-- * @{#POINT_VEC3.SmokeGreen}(): To smoke the point in green.
--
-- ### 1.5.2) Flare
--
-- * @{#POINT_VEC3.Flare}(): To flare the point in a certain color.
-- * @{#POINT_VEC3.FlareRed}(): To flare the point in red.
-- * @{#POINT_VEC3.FlareYellow}(): To flare the point in yellow.
-- * @{#POINT_VEC3.FlareWhite}(): To flare the point in white.
-- * @{#POINT_VEC3.FlareGreen}(): To flare the point in green.
--
-- ### 1.5.3) Explode
--
-- * @{#POINT_VEC3.Explosion}(): To explode the point with a certain intensity.
--
-- ### 1.5.4) Illuminate
--
-- * @{#POINT_VEC3.IlluminationBomb}(): To illuminate the point.
--
--
-- 2) @{Point#POINT_VEC2} class, extends @{Point#POINT_VEC3}
-- =========================================================
-- The @{Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified.
-- ![Banner Image](..\Presentations\POINT\Dia1.JPG)
--
-- ====
--
-- 2.1) POINT_VEC2 constructor
-- ---------------------------
-- A new POINT_VEC2 instance can be created with:
-- # Demo Missions
--
-- * @{Point#POINT_VEC2.New}(): a 2D point, taking an additional height parameter.
-- * @{Point#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{DCSTypes#Vec2}.
-- ### [POINT_VEC Demo Missions source code]()
--
-- ## 1.2) Manupulate the X, Altitude, Y coordinates of the 2D point
-- ### [POINT_VEC Demo Missions, only for beta testers]()
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- A POINT_VEC2 class works in 2D space, with an altitude setting. It contains internally an X, Altitude, Y coordinate.
-- Methods exist to manupulate these coordinates.
-- ====
--
-- The current X, Altitude, Y axis can be retrieved with the methods @{#POINT_VEC2.GetX}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetY}() respectively.
-- The methods @{#POINT_VEC2.SetX}(), @{#POINT_VEC2.SetAlt}(), @{#POINT_VEC2.SetY}() change the respective axis with a new value.
-- The current Lat(itude), Alt(itude), Lon(gitude) values can also be retrieved with the methods @{#POINT_VEC2.GetLat}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetLon}() respectively.
-- The current axis values can be changed by using the methods @{#POINT_VEC2.AddX}(), @{#POINT_VEC2.AddAlt}(), @{#POINT_VEC2.AddY}()
-- to add or substract a value from the current respective axis value.
-- Note that the Set and Add methods return the current POINT_VEC2 object, so these manipulation methods can be chained... For example:
-- # YouTube Channel
--
-- local Vec2 = PointVec2:AddX( 100 ):AddY( 2000 ):GetVec2()
-- ### [POINT_VEC YouTube Channel]()
--
-- ===
--
@@ -133,6 +64,126 @@
-- @field #POINT_VEC3.RoutePointType RoutePointType
-- @field #POINT_VEC3.RoutePointAction RoutePointAction
-- @extends Core.Base#BASE
--- # POINT_VEC3 class, extends @{Base#BASE}
--
-- POINT_VEC3 defines a 3D point in the simulator and with its methods, you can use or manipulate the point in 3D space.
--
-- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts.
-- In order to keep the credibility of the the author,
-- I want to emphasize that the formulas embedded in the MIST framework were created by Grimes or previous authors,
-- who you can find on the Eagle Dynamics Forums.
--
--
-- ## POINT_VEC3 constructor
--
-- A new POINT_VEC3 object can be created with:
--
-- * @{#POINT_VEC3.New}(): a 3D point.
-- * @{#POINT_VEC3.NewFromVec3}(): a 3D point created from a @{DCSTypes#Vec3}.
--
--
-- ## Manupulate the X, Y, Z coordinates of the POINT_VEC3
--
-- A POINT_VEC3 class works in 3D space. It contains internally an X, Y, Z coordinate.
-- Methods exist to manupulate these coordinates.
--
-- The current X, Y, Z axis can be retrieved with the methods @{#POINT_VEC3.GetX}(), @{#POINT_VEC3.GetY}(), @{#POINT_VEC3.GetZ}() respectively.
-- The methods @{#POINT_VEC3.SetX}(), @{#POINT_VEC3.SetY}(), @{#POINT_VEC3.SetZ}() change the respective axis with a new value.
-- The current axis values can be changed by using the methods @{#POINT_VEC3.AddX}(), @{#POINT_VEC3.AddY}(), @{#POINT_VEC3.AddZ}()
-- to add or substract a value from the current respective axis value.
-- Note that the Set and Add methods return the current POINT_VEC3 object, so these manipulation methods can be chained... For example:
--
-- local Vec3 = PointVec3:AddX( 100 ):AddZ( 150 ):GetVec3()
--
--
-- ## Create waypoints for routes
--
-- A POINT_VEC3 can prepare waypoints for Ground and Air groups to be embedded into a Route.
--
-- * @{#POINT_VEC3.RoutePointAir}(): Build an air route point.
-- * @{#POINT_VEC3.RoutePointGround}(): Build a ground route point.
--
-- Route points can be used in the Route methods of the @{Group#GROUP} class.
--
--
-- ## Smoke, flare, explode, illuminate
--
-- At the point a smoke, flare, explosion and illumination bomb can be triggered. Use the following methods:
--
-- ### Smoke
--
-- * @{#POINT_VEC3.Smoke}(): To smoke the point in a certain color.
-- * @{#POINT_VEC3.SmokeBlue}(): To smoke the point in blue.
-- * @{#POINT_VEC3.SmokeRed}(): To smoke the point in red.
-- * @{#POINT_VEC3.SmokeOrange}(): To smoke the point in orange.
-- * @{#POINT_VEC3.SmokeWhite}(): To smoke the point in white.
-- * @{#POINT_VEC3.SmokeGreen}(): To smoke the point in green.
--
-- ### Flare
--
-- * @{#POINT_VEC3.Flare}(): To flare the point in a certain color.
-- * @{#POINT_VEC3.FlareRed}(): To flare the point in red.
-- * @{#POINT_VEC3.FlareYellow}(): To flare the point in yellow.
-- * @{#POINT_VEC3.FlareWhite}(): To flare the point in white.
-- * @{#POINT_VEC3.FlareGreen}(): To flare the point in green.
--
-- ### Explode
--
-- * @{#POINT_VEC3.Explosion}(): To explode the point with a certain intensity.
--
-- ### Illuminate
--
-- * @{#POINT_VEC3.IlluminationBomb}(): To illuminate the point.
--
--
-- ## 3D calculation methods
--
-- Various calculation methods exist to use or manipulate 3D space. Find below a short description of each method:
--
-- ### Distance
--
-- * @{#POINT_VEC3.Get3DDistance}(): Obtain the distance from the current 3D point to the provided 3D point in 3D space.
-- * @{#POINT_VEC3.Get2DDistance}(): Obtain the distance from the current 3D point to the provided 3D point in 2D space.
--
-- ### Angle
--
-- * @{#POINT_VEC3.GetAngleDegrees}(): Obtain the angle in degrees from the current 3D point with the provided 3D direction vector.
-- * @{#POINT_VEC3.GetAngleRadians}(): Obtain the angle in radians from the current 3D point with the provided 3D direction vector.
-- * @{#POINT_VEC3.GetDirectionVec3}(): Obtain the 3D direction vector from the current 3D point to the provided 3D point.
--
-- ### Translation
--
-- * @{#POINT_VEC3.Translate}(): Translate the current 3D point towards an other 3D point using the given Distance and Angle.
--
-- ### Get the North correction of the current location
--
-- * @{#POINT_VEC3.GetNorthCorrection}(): Obtains the north correction at the current 3D point.
--
--
-- ## Point Randomization
--
-- Various methods exist to calculate random locations around a given 3D point.
--
-- * @{#POINT_VEC3.GetRandomPointVec2InRadius}(): Provides a random 2D point around the current 3D point, in the given inner to outer band.
-- * @{#POINT_VEC3.GetRandomPointVec3InRadius}(): Provides a random 3D point around the current 3D point, in the given inner to outer band.
-- * @{#POINT_VEC3.GetRandomVec2InRadius}(): Provides a random 2D vector around the current 3D point, in the given inner to outer band.
-- * @{#POINT_VEC3.GetRandomVec3InRadius}(): Provides a random 3D vector around the current 3D point, in the given inner to outer band.
--
--
-- ## Metric system
--
-- * @{#POINT_VEC3.IsMetric}(): Returns if the 3D point is Metric or Nautical Miles.
-- * @{#POINT_VEC3.SetMetric}(): Sets the 3D point to Metric or Nautical Miles.
--
--
-- ## Coorinate text generation
--
-- * @{#POINT_VEC3.ToStringBR}(): Generates a Bearing & Range text in the format of DDD for DI where DDD is degrees and DI is distance.
-- * @{#POINT_VEC3.ToStringLL}(): Generates a Latutude & Longutude text.
--
-- @field #POINT_VEC3 POINT_VEC3
--
POINT_VEC3 = {
ClassName = "POINT_VEC3",
Metric = true,
@@ -149,11 +200,38 @@ POINT_VEC3 = {
},
}
--- The POINT_VEC2 class
-- @type POINT_VEC2
--- @type POINT_VEC2
-- @field Dcs.DCSTypes#Distance x The x coordinate in meters.
-- @field Dcs.DCSTypes#Distance y the y coordinate in meters.
-- @extends Core.Point#POINT_VEC3
--- # POINT_VEC2 class, extends @{Point#POINT_VEC3}
--
-- The @{Point#POINT_VEC2} class defines a 2D point in the simulator. The height coordinate (if needed) will be the land height + an optional added height specified.
--
-- ## POINT_VEC2 constructor
--
-- A new POINT_VEC2 instance can be created with:
--
-- * @{Point#POINT_VEC2.New}(): a 2D point, taking an additional height parameter.
-- * @{Point#POINT_VEC2.NewFromVec2}(): a 2D point created from a @{DCSTypes#Vec2}.
--
-- ## Manupulate the X, Altitude, Y coordinates of the 2D point
--
-- A POINT_VEC2 class works in 2D space, with an altitude setting. It contains internally an X, Altitude, Y coordinate.
-- Methods exist to manupulate these coordinates.
--
-- The current X, Altitude, Y axis can be retrieved with the methods @{#POINT_VEC2.GetX}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetY}() respectively.
-- The methods @{#POINT_VEC2.SetX}(), @{#POINT_VEC2.SetAlt}(), @{#POINT_VEC2.SetY}() change the respective axis with a new value.
-- The current Lat(itude), Alt(itude), Lon(gitude) values can also be retrieved with the methods @{#POINT_VEC2.GetLat}(), @{#POINT_VEC2.GetAlt}(), @{#POINT_VEC2.GetLon}() respectively.
-- The current axis values can be changed by using the methods @{#POINT_VEC2.AddX}(), @{#POINT_VEC2.AddAlt}(), @{#POINT_VEC2.AddY}()
-- to add or substract a value from the current respective axis value.
-- Note that the Set and Add methods return the current POINT_VEC2 object, so these manipulation methods can be chained... For example:
--
-- local Vec2 = PointVec2:AddX( 100 ):AddY( 2000 ):GetVec2()
--
-- @field #POINT_VEC2 POINT_VEC2
--
POINT_VEC2 = {
ClassName = "POINT_VEC2",
}
@@ -399,11 +477,11 @@ function POINT_VEC3:GetNorthCorrectionRadians()
end
--- Return a direction in radians from the POINT_VEC3 using a direction vector in Vec3 format.
--- Return an angle in radians from the POINT_VEC3 using a direction vector in Vec3 format.
-- @param #POINT_VEC3 self
-- @param Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format.
-- @return #number DirectionRadians The direction in radians.
function POINT_VEC3:GetDirectionRadians( DirectionVec3 )
-- @return #number DirectionRadians The angle in radians.
function POINT_VEC3:GetAngleRadians( DirectionVec3 )
local DirectionRadians = math.atan2( DirectionVec3.z, DirectionVec3.x )
--DirectionRadians = DirectionRadians + self:GetNorthCorrectionRadians()
if DirectionRadians < 0 then
@@ -412,6 +490,17 @@ function POINT_VEC3:GetDirectionRadians( DirectionVec3 )
return DirectionRadians
end
--- Return an angle in degrees from the POINT_VEC3 using a direction vector in Vec3 format.
-- @param #POINT_VEC3 self
-- @param Dcs.DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format.
-- @return #number DirectionRadians The angle in degrees.
function POINT_VEC3:GetAngleDegrees( DirectionVec3 )
local AngleRadians = self:GetAngleRadians(DirectionVec3)
local Angle = UTILS.ToDegree( AngleRadians )
return Angle
end
--- Return the 2D distance in meters between the target POINT_VEC3 and the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target POINT_VEC3.
@@ -482,7 +571,7 @@ end
-- @return #string The BR text.
function POINT_VEC3:GetBRText( TargetPointVec3 )
local DirectionVec3 = self:GetDirectionVec3( TargetPointVec3 )
local AngleRadians = self:GetDirectionRadians( DirectionVec3 )
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
local Distance = self:Get2DDistance( TargetPointVec3 )
return self:ToStringBR( AngleRadians, Distance )
end

View File

@@ -1,6 +1,6 @@
--- **Core** - The RADIO class is responsible for **transmitting radio communications**.
--
-- --- bitmap
-- ![Banner Image](..\Presentations\RADIO\Dia1.JPG)
--
-- ===
--
@@ -27,19 +27,20 @@
--
-- ===
--
-- ### Authors: Hugues "Grey_Echo" Bousquet
-- ### Author: Hugues "Grey_Echo" Bousquet
--
-- @module Radio
--- # 1) RADIO class, extends @{Base#BASE}
--
-- ## 1.1) RADIO usage
--
-- There are 3 steps to a successful radio transmission.
--
-- * First, you need to **"add" a @{#RADIO} object** to your @{Positionable#POSITIONABLE}. This is done using the @{Positionable#POSITIONABLE.GetRadio}() function,
-- * First, you need to **"add a @{#RADIO} object** to your @{Positionable#POSITIONABLE}. This is done using the @{Positionable#POSITIONABLE.GetRadio}() function,
-- * Then, you will **set the relevant parameters** to the transmission (see below),
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{Positionable#POSITIONABLE.Broadcast}() function.
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function.
--
-- Methods to set relevant parameters for both a @{Unit#UNIT} or a @{Group#GROUP} or any other @{Positionable#POSITIONABLE}
--
@@ -53,7 +54,7 @@
-- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration,
-- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call
--
-- Additional Methods to set relevant parameters if the transmiter is any other @{Wrapper.Positionable#POSITIONABLE}
-- Additional Methods to set relevant parameters if the transmiter is any other @{Positionable#POSITIONABLE}
--
-- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts
-- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call
@@ -68,7 +69,7 @@
-- * Note that if the transmission has a subtitle, it will be readable, regardless of the quality of the transmission.
--
-- @type RADIO
-- @field Wrapper.Positionable#POSITIONABLE Positionable The transmiter
-- @field Positionable#POSITIONABLE Positionable The transmiter
-- @field #string FileName Name of the sound file
-- @field #number Frequency Frequency of the transmission in Hz
-- @field #number Modulation Modulation of the transmission (either radio.modulation.AM or radio.modulation.FM)

View File

@@ -4,31 +4,30 @@
--
-- ===
--
-- # 1) @{Scheduler#SCHEDULER} class, extends @{Base#BASE}
-- SCHEDULER manages the **scheduling of functions**:
--
-- The @{Scheduler#SCHEDULER} class creates schedule.
--
-- ## 1.1) SCHEDULER constructor
--
-- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters:
--
-- * @{Scheduler#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection.
-- * @{Scheduler#SCHEDULER.New}( Object ): Setup a new SCHEDULER object, which is linked to the Object. When the Object is nillified or destroyed, the SCHEDULER object will also be destroyed and stopped after garbage collection.
-- * @{Scheduler#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
-- * @{Scheduler#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
--
-- ## 1.2) SCHEDULER timer stopping and (re-)starting.
--
-- The SCHEDULER can be stopped and restarted with the following methods:
--
-- * @{Scheduler#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started.
-- * @{Scheduler#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped.
--
-- ## 1.3) Create a new schedule
--
-- With @{Scheduler#SCHEDULER.Schedule}() a new time event can be scheduled. This function is used by the :New() constructor when a new schedule is planned.
-- * optionally in an optional specified time interval,
-- * optionally **repeating** with a specified time repeat interval,
-- * optionally **randomizing** with a specified time interval randomization factor,
-- * optionally **stop** the repeating after a specified time interval.
--
-- ===
--
-- # Demo Missions
--
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SCH%20-%20Scheduler)
--
-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [SCHEDULER YouTube Channel (none)]()
--
-- ====
--
-- ### Contributions:
--
@@ -38,10 +37,6 @@
--
-- * FlightControl : Design & Programming
--
-- ### Test Missions:
--
-- * SCH - Scheduler
--
-- ===
--
-- @module Scheduler
@@ -51,6 +46,153 @@
-- @type SCHEDULER
-- @field #number ScheduleID the ID of the scheduler.
-- @extends Core.Base#BASE
--- # SCHEDULER class, extends @{Base#BASE}
--
-- The SCHEDULER class creates schedule.
--
-- A SCHEDULER can manage **multiple** (repeating) schedules. Each planned or executing schedule has a unique **ScheduleID**.
-- The ScheduleID is returned when the method @{#SCHEDULER.Schedule}() is called.
-- It is recommended to store the ScheduleID in a variable, as it is used in the methods @{SCHEDULER.Start}() and @{SCHEDULER.Stop}(),
-- which can start and stop specific repeating schedules respectively within a SCHEDULER object.
--
-- ## SCHEDULER constructor
--
-- The SCHEDULER class is quite easy to use, but note that the New constructor has variable parameters:
--
-- The @{#SCHEDULER.New}() method returns 2 variables:
--
-- 1. The SCHEDULER object reference.
-- 2. The first schedule planned in the SCHEDULER object.
--
-- To clarify the different appliances, lets have a look at the following examples:
--
-- ### Construct a SCHEDULER object without a persistent schedule.
--
-- * @{#SCHEDULER.New}( nil ): Setup a new SCHEDULER object, which is persistently executed after garbage collection.
--
-- SchedulerObject = SCHEDULER:New()
-- SchedulerID = SchedulerObject:Schedule( nil, ScheduleFunction, {} )
--
-- The above example creates a new SchedulerObject, but does not schedule anything.
-- A separate schedule is created by using the SchedulerObject using the method :Schedule..., which returns a ScheduleID
--
-- ### 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.
--
-- ZoneObject = ZONE:New( "ZoneName" )
-- SchedulerObject = SCHEDULER:New( ZoneObject )
-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {} )
-- ...
-- ZoneObject = nil
-- garbagecollect()
--
-- The above example creates a new SchedulerObject, but does not schedule anything, and is bound to the existence of ZoneObject, which is a ZONE.
-- A separate schedule is created by using the SchedulerObject using the method :Schedule()..., which returns a ScheduleID
-- Later in the logic, the ZoneObject is put to nil, and garbage is collected.
-- As a result, the ScheduleObject will cancel any planned schedule.
--
-- ### Construct a SCHEDULER object with a persistent schedule.
--
-- * @{#SCHEDULER.New}( nil, Function, FunctionArguments, Start, ... ): Setup a new persistent SCHEDULER object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
--
-- SchedulerObject, SchedulerID = SCHEDULER:New( nil, ScheduleFunction, {} )
--
-- The above example creates a new SchedulerObject, and does schedule the first schedule as part of the call.
-- Note that 2 variables are returned here: SchedulerObject, ScheduleID...
--
-- ### Construct a SCHEDULER object without a schedule, but volatile to the Object existence...
--
-- * @{#SCHEDULER.New}( Object, Function, FunctionArguments, Start, ... ): Setup a new SCHEDULER object, linked to Object, and start a new schedule for the Function with the defined FunctionArguments according the Start and sequent parameters.
--
-- ZoneObject = ZONE:New( "ZoneName" )
-- SchedulerObject, SchedulerID = SCHEDULER:New( ZoneObject, ScheduleFunction, {} )
-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {} )
-- ...
-- ZoneObject = nil
-- garbagecollect()
--
-- The above example creates a new SchedulerObject, and schedules a method call (ScheduleFunction),
-- and is bound to the existence of ZoneObject, which is a ZONE object (ZoneObject).
-- Both a ScheduleObject and a SchedulerID variable are returned.
-- Later in the logic, the ZoneObject is put to nil, and garbage is collected.
-- As a result, the ScheduleObject will cancel the planned schedule.
--
-- ## SCHEDULER timer stopping and (re-)starting.
--
-- The SCHEDULER can be stopped and restarted with the following methods:
--
-- * @{#SCHEDULER.Start}(): (Re-)Start the schedules within the SCHEDULER object. If a CallID is provided to :Start(), only the schedule referenced by CallID will be (re-)started.
-- * @{#SCHEDULER.Stop}(): Stop the schedules within the SCHEDULER object. If a CallID is provided to :Stop(), then only the schedule referenced by CallID will be stopped.
--
-- ZoneObject = ZONE:New( "ZoneName" )
-- SchedulerObject, SchedulerID = SCHEDULER:New( ZoneObject, ScheduleFunction, {} )
-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 10 )
-- ...
-- SchedulerObject:Stop( SchedulerID )
-- ...
-- SchedulerObject:Start( SchedulerID )
--
-- The above example creates a new SchedulerObject, and does schedule the first schedule as part of the call.
-- Note that 2 variables are returned here: SchedulerObject, ScheduleID...
-- Later in the logic, the repeating schedule with SchedulerID is stopped.
-- A bit later, the repeating schedule with SchedulerId is (re)-started.
--
-- ## Create a new schedule
--
-- With the method @{#SCHEDULER.Schedule}() a new time event can be scheduled.
-- This method is used by the :New() constructor when a new schedule is planned.
--
-- Consider the following code fragment of the SCHEDULER object creation.
--
-- ZoneObject = ZONE:New( "ZoneName" )
-- SchedulerObject = SCHEDULER:New( ZoneObject )
--
-- Several parameters can be specified that influence the behaviour of a Schedule.
--
-- ### A single schedule, immediately executed
--
-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {} )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within milleseconds ...
--
-- ### A single schedule, planned over time
--
-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10 )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds ...
--
-- ### A schedule with a repeating time interval, planned over time
--
-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60 )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
-- and repeating 60 every seconds ...
--
-- ### A schedule with a repeating time interval, planned over time, with time interval randomization
--
-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60, 0.5 )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
-- and repeating 60 seconds, with a 50% time interval randomization ...
-- So the repeating time interval will be randomized using the **0.5**,
-- and will calculate between **60 - ( 60 * 0.5 )** and **60 + ( 60 * 0.5 )** for each repeat,
-- which is in this example between **30** and **90** seconds.
--
-- ### A schedule with a repeating time interval, planned over time, with time interval randomization, and stop after a time interval
--
-- SchedulerID = SchedulerObject:Schedule( ZoneObject, ScheduleFunction, {}, 10, 60, 0.5, 300 )
--
-- The above example schedules a new ScheduleFunction call to be executed asynchronously, within 10 seconds,
-- The schedule will repeat every 60 seconds.
-- So the repeating time interval will be randomized using the **0.5**,
-- and will calculate between **60 - ( 60 * 0.5 )** and **60 + ( 60 * 0.5 )** for each repeat,
-- which is in this example between **30** and **90** seconds.
-- The schedule will stop after **300** seconds.
--
-- @field #SCHEDULER
SCHEDULER = {
ClassName = "SCHEDULER",
Schedules = {},

View File

@@ -124,7 +124,7 @@ end
-- @param Core.Base#BASE Object
-- @return Core.Base#BASE The added BASE Object.
function SET_BASE:Add( ObjectName, Object )
self:F2( ObjectName )
self:F( ObjectName )
local t = { _ = Object }
@@ -1374,7 +1374,7 @@ function SET_UNIT:ForEachUnitCompletelyInZone( ZoneObject, IteratorFunction, ...
--- @param Core.Zone#ZONE_BASE ZoneObject
-- @param Wrapper.Unit#UNIT UnitObject
function( ZoneObject, UnitObject )
if UnitObject:IsCompletelyInZone( ZoneObject ) then
if UnitObject:IsInZone( ZoneObject ) then
return true
else
return false
@@ -2391,3 +2391,346 @@ function SET_AIRBASE:IsIncludeObject( MAirbase )
self:T2( MAirbaseInclude )
return MAirbaseInclude
end
--- @type SET_CARGO
-- @extends Core.Set#SET_BASE
--- # SET_CARGO class, extends @{Set#SET_BASE}
--
-- Mission designers can use the @{Set#SET_CARGO} class to build sets of cargos optionally belonging to certain:
--
-- * Coalitions
-- * Types
-- * Name or Prefix
--
-- ## SET_CARGO constructor
--
-- Create a new SET_CARGO object with the @{#SET_CARGO.New} method:
--
-- * @{#SET_CARGO.New}: Creates a new SET_CARGO object.
--
-- ## Add or Remove CARGOs from SET_CARGO
--
-- CARGOs can be added and removed using the @{Set#SET_CARGO.AddCargosByName} and @{Set#SET_CARGO.RemoveCargosByName} respectively.
-- These methods take a single CARGO name or an array of CARGO names to be added or removed from SET_CARGO.
--
-- ## SET_CARGO filter criteria
--
-- You can set filter criteria to automatically maintain the SET_CARGO contents.
-- Filter criteria are defined by:
--
-- * @{#SET_CARGO.FilterCoalitions}: Builds the SET_CARGO with the cargos belonging to the coalition(s).
-- * @{#SET_CARGO.FilterPrefixes}: Builds the SET_CARGO with the cargos containing the prefix string(s).
-- * @{#SET_CARGO.FilterTypes}: Builds the SET_CARGO with the cargos belonging to the cargo type(s).
-- * @{#SET_CARGO.FilterCountries}: Builds the SET_CARGO with the cargos belonging to the country(ies).
--
-- Once the filter criteria have been set for the SET_CARGO, you can start filtering using:
--
-- * @{#SET_CARGO.FilterStart}: Starts the filtering of the cargos within the SET_CARGO.
--
-- ## SET_CARGO iterators
--
-- Once the filters have been defined and the SET_CARGO has been built, you can iterate the SET_CARGO with the available iterator methods.
-- The iterator methods will walk the SET_CARGO set, and call for each cargo within the set a function that you provide.
-- The following iterator methods are currently available within the SET_CARGO:
--
-- * @{#SET_CARGO.ForEachCargo}: Calls a function for each cargo it finds within the SET_CARGO.
--
-- @field #SET_CARGO SET_CARGO
--
SET_CARGO = {
ClassName = "SET_CARGO",
Cargos = {},
Filter = {
Coalitions = nil,
Types = nil,
Countries = nil,
ClientPrefixes = nil,
},
FilterMeta = {
Coalitions = {
red = coalition.side.RED,
blue = coalition.side.BLUE,
neutral = coalition.side.NEUTRAL,
},
},
}
--- Creates a new SET_CARGO object, building a set of cargos belonging to a coalitions and categories.
-- @param #SET_CARGO self
-- @return #SET_CARGO self
-- @usage
-- -- Define a new SET_CARGO Object. The DatabaseSet will contain a reference to all Cargos.
-- DatabaseSet = SET_CARGO:New()
function SET_CARGO:New()
-- Inherits from BASE
local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.CARGOS ) )
return self
end
--- Add CARGOs to SET_CARGO.
-- @param Core.Set#SET_CARGO self
-- @param #string AddCargoNames A single name or an array of CARGO names.
-- @return self
function SET_CARGO:AddCargosByName( AddCargoNames )
local AddCargoNamesArray = ( type( AddCargoNames ) == "table" ) and AddCargoNames or { AddCargoNames }
for AddCargoID, AddCargoName in pairs( AddCargoNamesArray ) do
self:Add( AddCargoName, CARGO:FindByName( AddCargoName ) )
end
return self
end
--- Remove CARGOs from SET_CARGO.
-- @param Core.Set#SET_CARGO self
-- @param Wrapper.Cargo#CARGO RemoveCargoNames A single name or an array of CARGO names.
-- @return self
function SET_CARGO:RemoveCargosByName( RemoveCargoNames )
local RemoveCargoNamesArray = ( type( RemoveCargoNames ) == "table" ) and RemoveCargoNames or { RemoveCargoNames }
for RemoveCargoID, RemoveCargoName in pairs( RemoveCargoNamesArray ) do
self:Remove( RemoveCargoName.CargoName )
end
return self
end
--- Finds a Cargo based on the Cargo Name.
-- @param #SET_CARGO self
-- @param #string CargoName
-- @return Wrapper.Cargo#CARGO The found Cargo.
function SET_CARGO:FindCargo( CargoName )
local CargoFound = self.Set[CargoName]
return CargoFound
end
--- Builds a set of cargos of coalitions.
-- Possible current coalitions are red, blue and neutral.
-- @param #SET_CARGO self
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral".
-- @return #SET_CARGO self
function SET_CARGO:FilterCoalitions( Coalitions )
if not self.Filter.Coalitions then
self.Filter.Coalitions = {}
end
if type( Coalitions ) ~= "table" then
Coalitions = { Coalitions }
end
for CoalitionID, Coalition in pairs( Coalitions ) do
self.Filter.Coalitions[Coalition] = Coalition
end
return self
end
--- Builds a set of cargos of defined cargo types.
-- Possible current types are those types known within DCS world.
-- @param #SET_CARGO self
-- @param #string Types Can take those type strings known within DCS world.
-- @return #SET_CARGO self
function SET_CARGO:FilterTypes( Types )
if not self.Filter.Types then
self.Filter.Types = {}
end
if type( Types ) ~= "table" then
Types = { Types }
end
for TypeID, Type in pairs( Types ) do
self.Filter.Types[Type] = Type
end
return self
end
--- Builds a set of cargos of defined countries.
-- Possible current countries are those known within DCS world.
-- @param #SET_CARGO self
-- @param #string Countries Can take those country strings known within DCS world.
-- @return #SET_CARGO self
function SET_CARGO:FilterCountries( Countries )
if not self.Filter.Countries then
self.Filter.Countries = {}
end
if type( Countries ) ~= "table" then
Countries = { Countries }
end
for CountryID, Country in pairs( Countries ) do
self.Filter.Countries[Country] = Country
end
return self
end
--- Builds a set of cargos of defined cargo prefixes.
-- All the cargos starting with the given prefixes will be included within the set.
-- @param #SET_CARGO self
-- @param #string Prefixes The prefix of which the cargo name starts with.
-- @return #SET_CARGO self
function SET_CARGO:FilterPrefixes( Prefixes )
if not self.Filter.CargoPrefixes then
self.Filter.CargoPrefixes = {}
end
if type( Prefixes ) ~= "table" then
Prefixes = { Prefixes }
end
for PrefixID, Prefix in pairs( Prefixes ) do
self.Filter.CargoPrefixes[Prefix] = Prefix
end
return self
end
--- Starts the filtering.
-- @param #SET_CARGO self
-- @return #SET_CARGO self
function SET_CARGO:FilterStart()
if _DATABASE then
self:_FilterStart()
end
self:HandleEvent( EVENTS.NewCargo )
self:HandleEvent( EVENTS.DeleteCargo )
return self
end
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
-- @param #SET_CARGO self
-- @param Core.Event#EVENTDATA Event
-- @return #string The name of the CARGO
-- @return #table The CARGO
function SET_CARGO:AddInDatabase( Event )
self:F3( { Event } )
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
end
--- Handles the Database to check on any event that Object exists in the Database.
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
-- @param #SET_CARGO self
-- @param Core.Event#EVENTDATA Event
-- @return #string The name of the CARGO
-- @return #table The CARGO
function SET_CARGO:FindInDatabase( Event )
self:F3( { Event } )
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
end
--- Iterate the SET_CARGO and call an interator function for each CARGO, providing the CARGO and optional parameters.
-- @param #SET_CARGO self
-- @param #function IteratorFunction The function that will be called when there is an alive CARGO in the SET_CARGO. The function needs to accept a CARGO parameter.
-- @return #SET_CARGO self
function SET_CARGO:ForEachCargo( IteratorFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self.Set )
return self
end
--- Iterate the SET_CARGO while identifying the nearest @{Cargo#CARGO} from a @{Point#POINT_VEC2}.
-- @param #SET_CARGO self
-- @param Core.Point#POINT_VEC2 PointVec2 A @{Point#POINT_VEC2} object from where to evaluate the closest @{Cargo#CARGO}.
-- @return Wrapper.Cargo#CARGO The closest @{Cargo#CARGO}.
function SET_CARGO:FindNearestCargoFromPointVec2( PointVec2 )
self:F2( PointVec2 )
local NearestCargo = self:FindNearestObjectFromPointVec2( PointVec2 )
return NearestCargo
end
---
-- @param #SET_CARGO self
-- @param AI.AI_Cargo#AI_CARGO MCargo
-- @return #SET_CARGO self
function SET_CARGO:IsIncludeObject( MCargo )
self:F2( MCargo )
local MCargoInclude = true
if MCargo then
local MCargoName = MCargo:GetName()
if self.Filter.Coalitions then
local MCargoCoalition = false
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
local CargoCoalitionID = MCargo:GetCoalition()
self:T3( { "Coalition:", CargoCoalitionID, self.FilterMeta.Coalitions[CoalitionName], CoalitionName } )
if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == CargoCoalitionID then
MCargoCoalition = true
end
end
self:T( { "Evaluated Coalition", MCargoCoalition } )
MCargoInclude = MCargoInclude and MCargoCoalition
end
if self.Filter.Types then
local MCargoType = false
for TypeID, TypeName in pairs( self.Filter.Types ) do
self:T3( { "Type:", MCargo:GetType(), TypeName } )
if TypeName == MCargo:GetType() then
MCargoType = true
end
end
self:T( { "Evaluated Type", MCargoType } )
MCargoInclude = MCargoInclude and MCargoType
end
if self.Filter.CargoPrefixes then
local MCargoPrefix = false
for CargoPrefixId, CargoPrefix in pairs( self.Filter.CargoPrefixes ) do
self:T3( { "Prefix:", string.find( MCargo.Name, CargoPrefix, 1 ), CargoPrefix } )
if string.find( MCargo.Name, CargoPrefix, 1 ) then
MCargoPrefix = true
end
end
self:T( { "Evaluated Prefix", MCargoPrefix } )
MCargoInclude = MCargoInclude and MCargoPrefix
end
end
self:T2( MCargoInclude )
return MCargoInclude
end
--- Handles the OnEventNewCargo event for the Set.
-- @param #SET_CARGO self
-- @param Core.Event#EVENTDATA EventData
function SET_CARGO:OnEventNewCargo( EventData )
if EventData.Cargo then
if EventData.Cargo and self:IsIncludeObject( EventData.Cargo ) then
self:Add( EventData.Cargo.Name , EventData.Cargo )
end
end
end
--- Handles the OnDead or OnCrash event for alive units set.
-- @param #SET_CARGO self
-- @param Core.Event#EVENTDATA EventData
function SET_CARGO:OnEventDeleteCargo( EventData )
self:F3( { EventData } )
if EventData.Cargo then
local Cargo = _DATABASE:FindCargo( EventData.Cargo.Name )
if Cargo and Cargo.Name then
self:Remove( Cargo.Name )
end
end
end

View File

@@ -0,0 +1,177 @@
--- **Core** -- Spawn dynamically new STATICs in your missions.
--
-- ![Banner Image](..\Presentations\SPAWNSTATIC\Dia1.JPG)
--
-- ====
--
-- SPAWNSTATIC spawns static structures in your missions dynamically. See below the SPAWNSTATIC class documentation.
--
-- ====
--
-- # Demo Missions
--
-- ### [SPAWNSTATIC Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPS - Spawning Statics)
--
-- ### [SPAWNSTATIC Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPS%20-%20Spawning%20Statics)
--
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
--
-- ====
--
-- # YouTube Channel
--
-- ### [SPAWNSTATIC YouTube Channel]()
--
-- ====
--
-- # **API CHANGE HISTORY**
--
-- The underlying change log documents the API changes. Please read this carefully. The following notation is used:
--
-- * **Added** parts are expressed in bold type face.
-- * _Removed_ parts are expressed in italic type face.
--
-- Hereby the change log:
--
-- ===
--
-- # **AUTHORS and CONTRIBUTIONS**
--
-- ### Contributions:
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
--
-- @module SpawnStatic
--- @type SPAWNSTATIC
-- @extends Core.Base#BASE
--- # SPAWNSTATIC class, extends @{Base#BASE}
--
-- The SPAWNSTATIC class allows to spawn dynamically new @{Static}s.
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME),
-- SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc), and "copy"
-- these properties to create a new static object and place it at the desired coordinate.
--
-- New spawned @{Static}s get **the same name** as the name of the template Static,
-- or gets the given name when a new name is provided at the Spawn method.
-- By default, spawned @{Static}s will follow a naming convention at run-time:
--
-- * Spawned @{Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**,
-- and _nnn_ is a **counter from 0 to 99999**.
--
--
-- ## SPAWNSTATIC construction methods
--
-- Create a new SPAWNSTATIC object with the @{#SPAWNSTATIC.NewFromStatic}():
--
-- * @{#SPAWNSTATIC.NewFromStatic}(): Creates a new SPAWNSTATIC object given a name that is used as the base of the naming of each spawned Static.
--
-- ## **Spawn** methods
--
-- Groups can be spawned at different times and methods:
--
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(): Spawn a new group from a POINT_VEC2 coordinate.
-- (The group will be spawned at land height ).
-- * @{#SPAWNSTATIC.SpawnFromZone}(): Spawn a new group in a @{Zone}.
--
-- @field #SPAWNSTATIC SPAWNSTATIC
--
SPAWNSTATIC = {
ClassName = "SPAWNSTATIC",
}
--- @type SPAWNSTATIC.SpawnZoneTable
-- @list <Core.Zone#ZONE_BASE> SpawnZone
--- Creates the main object to spawn a @{Static} defined in the ME.
-- @param #SPAWNSTATIC self
-- @param #string SpawnTemplatePrefix is the name of the Group in the ME that defines the Template. Each new group will have the name starting with SpawnTemplatePrefix.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:NewFromStatic( SpawnTemplatePrefix, CountryID )
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
self:F( { SpawnTemplatePrefix } )
local TemplateStatic = StaticObject.getByName( SpawnTemplatePrefix )
if TemplateStatic then
self.SpawnTemplatePrefix = SpawnTemplatePrefix
self.CountryID = CountryID
self.SpawnIndex = 0
else
error( "SPAWNSTATIC:New: There is no group declared in the mission editor with SpawnTemplatePrefix = '" .. SpawnTemplatePrefix .. "'" )
end
self:SetEventPriority( 5 )
return self
end
--- Creates the main object to spawn a @{Static} based on a type name.
-- @param #SPAWNSTATIC self
-- @param #string SpawnTypeName is the name of the type.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory, CountryID )
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWNSTATIC
self:F( { SpawnTypeName } )
self.SpawnTypeName = SpawnTypeName
self.CountryID = CountryID
self.SpawnIndex = 0
self:SetEventPriority( 5 )
return self
end
--- Creates a new @{Static} from a POINT_VEC2.
-- @param #SPAWNSTATIC self
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
-- @param #string (optional) The name of the new static.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName )
self:F( { PointVec2, Heading, NewName } )
local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID]
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
StaticTemplate.x = PointVec2:GetLat()
StaticTemplate.y = PointVec2:GetLon()
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
StaticTemplate.heading = ( Heading / 180 ) * math.pi
StaticTemplate.CountryID = nil
StaticTemplate.CoalitionID = nil
StaticTemplate.CategoryID = nil
local Static = coalition.addStaticObject( self.CountryID, StaticTemplate )
self.SpawnIndex = self.SpawnIndex + 1
return Static
end
--- Creates a new @{Static} from a @{Zone}.
-- @param #SPAWNSTATIC self
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
-- @param #string (optional) The name of the new static.
-- @return #SPAWNSTATIC
function SPAWNSTATIC:SpawnFromZone( Zone, Heading, NewName )
self:F( { Zone, Heading, NewName } )
local Static = self:SpawnFromPointVec2( Zone:GetPointVec2(), Heading, NewName )
return Static
end

View File

@@ -66,48 +66,53 @@
-- @module Zone
--- The ZONE_BASE class
-- @type ZONE_BASE
--- @type ZONE_BASE
-- @field #string ZoneName Name of the zone.
-- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability.
-- @extends Core.Base#BASE
--- # 1) ZONE_BASE class, extends @{Base#BASE}
--- # ZONE_BASE class, extends @{Base#BASE}
--
-- This class is an abstract BASE class for derived classes, and is not meant to be instantiated.
--
-- ## 1.1) Each zone has a name:
-- ## Each zone has a name:
--
-- * @{#ZONE_BASE.GetName}(): Returns the name of the zone.
--
-- ## 1.2) Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}:
-- ## Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}:
--
-- * @{#ZONE_BASE.IsVec2InZone}(): Returns if a Vec2 is within the zone.
-- * @{#ZONE_BASE.IsVec3InZone}(): Returns if a Vec3 is within the zone.
-- * @{#ZONE_BASE.IsVec2InZone}(): Returns if a 2D vector is within the zone.
-- * @{#ZONE_BASE.IsVec3InZone}(): Returns if a 3D vector is within the zone.
-- * @{#ZONE_BASE.IsPointVec2InZone}(): Returns if a 2D point vector is within the zone.
-- * @{#ZONE_BASE.IsPointVec3InZone}(): Returns if a 3D point vector is within the zone.
--
-- ## 1.3) A zone has a probability factor that can be set to randomize a selection between zones:
-- ## A zone has a probability factor that can be set to randomize a selection between zones:
--
-- * @{#ZONE_BASE.SetRandomizeProbability}(): Set the randomization probability of a zone to be selected, taking a value between 0 and 1 ( 0 = 0%, 1 = 100% )
-- * @{#ZONE_BASE.GetRandomizeProbability}(): Get the randomization probability of a zone to be selected, passing a value between 0 and 1 ( 0 = 0%, 1 = 100% )
-- * @{#ZONE_BASE.SetZoneProbability}(): Set the randomization probability of a zone to be selected, taking a value between 0 and 1 ( 0 = 0%, 1 = 100% )
-- * @{#ZONE_BASE.GetZoneProbability}(): Get the randomization probability of a zone to be selected, passing a value between 0 and 1 ( 0 = 0%, 1 = 100% )
-- * @{#ZONE_BASE.GetZoneMaybe}(): Get the zone taking into account the randomization probability. nil is returned if this zone is not a candidate.
--
-- ## 1.4) A zone manages Vectors:
-- ## A zone manages vectors:
--
-- * @{#ZONE_BASE.GetVec2}(): Returns the @{DCSTypes#Vec2} coordinate of the zone.
-- * @{#ZONE_BASE.GetRandomVec2}(): Define a random @{DCSTypes#Vec2} within the zone.
-- * @{#ZONE_BASE.GetVec2}(): Returns the 2D vector coordinate of the zone.
-- * @{#ZONE_BASE.GetVec3}(): Returns the 3D vector coordinate of the zone.
-- * @{#ZONE_BASE.GetPointVec2}(): Returns the 2D point vector coordinate of the zone.
-- * @{#ZONE_BASE.GetPointVec3}(): Returns the 3D point vector coordinate of the zone.
-- * @{#ZONE_BASE.GetRandomVec2}(): Define a random 2D vector within the zone.
-- * @{#ZONE_BASE.GetRandomPointVec2}(): Define a random 2D point vector within the zone.
-- * @{#ZONE_BASE.GetRandomPointVec3}(): Define a random 3D point vector within the zone.
--
-- ## 1.5) A zone has a bounding square:
-- ## A zone has a bounding square:
--
-- * @{#ZONE_BASE.GetBoundingSquare}(): Get the outer most bounding square of the zone.
--
-- ## 1.6) A zone can be marked:
-- ## A zone can be marked:
--
-- * @{#ZONE_BASE.SmokeZone}(): Smokes the zone boundaries in a color.
-- * @{#ZONE_BASE.FlareZone}(): Flares the zone boundaries in a color.
--
-- ===
-- @field #ZONE_BASE ZONE_BASE
-- @field #ZONE_BASE
ZONE_BASE = {
ClassName = "ZONE_BASE",
ZoneName = "",
@@ -144,20 +149,21 @@ function ZONE_BASE:GetName()
return self.ZoneName
end
--- Returns if a location is within the zone.
--- Returns if a Vec2 is within the zone.
-- @param #ZONE_BASE self
-- @param Dcs.DCSTypes#Vec2 Vec2 The location to test.
-- @return #boolean true if the location is within the zone.
-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 to test.
-- @return #boolean true if the Vec2 is within the zone.
function ZONE_BASE:IsVec2InZone( Vec2 )
self:F2( Vec2 )
return false
end
--- Returns if a point is within the zone.
--- Returns if a Vec3 is within the zone.
-- @param #ZONE_BASE self
-- @param Dcs.DCSTypes#Vec3 Vec3 The point to test.
-- @return #boolean true if the point is within the zone.
-- @return #boolean true if the Vec3 is within the zone.
function ZONE_BASE:IsVec3InZone( Vec3 )
self:F2( Vec3 )
@@ -166,6 +172,31 @@ function ZONE_BASE:IsVec3InZone( Vec3 )
return InZone
end
--- Returns if a PointVec2 is within the zone.
-- @param #ZONE_BASE self
-- @param Core.Point#POINT_VEC2 PointVec2 The PointVec2 to test.
-- @return #boolean true if the PointVec2 is within the zone.
function ZONE_BASE:IsPointVec2InZone( PointVec2 )
self:F2( PointVec2 )
local InZone = self:IsVec2InZone( PointVec2:GetVec2() )
return InZone
end
--- Returns if a PointVec3 is within the zone.
-- @param #ZONE_BASE self
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 to test.
-- @return #boolean true if the PointVec3 is within the zone.
function ZONE_BASE:IsPointVec3InZone( PointVec3 )
self:F2( PointVec3 )
local InZone = self:IsPointVec2InZone( PointVec3 )
return InZone
end
--- Returns the @{DCSTypes#Vec2} coordinate of the zone.
-- @param #ZONE_BASE self
-- @return #nil.
@@ -310,29 +341,29 @@ end
-- @type ZONE_RADIUS
-- @field Dcs.DCSTypes#Vec2 Vec2 The current location of the zone.
-- @field Dcs.DCSTypes#Distance Radius The radius of the zone.
-- @extends Core.Zone#ZONE_BASE
-- @extends #ZONE_BASE
--- # 2) @{Zone#ZONE_RADIUS} class, extends @{Zone#ZONE_BASE}
--- # ZONE_RADIUS class, extends @{Zone#ZONE_BASE}
--
-- The ZONE_RADIUS class defined by a zone name, a location and a radius.
-- This class implements the inherited functions from Core.Zone#ZONE_BASE taking into account the own zone format and properties.
--
-- ## 2.1) @{Zone#ZONE_RADIUS} constructor
-- ## ZONE_RADIUS constructor
--
-- * @{#ZONE_RADIUS.New}(): Constructor.
--
-- ## 2.2) Manage the radius of the zone
-- ## Manage the radius of the zone
--
-- * @{#ZONE_RADIUS.SetRadius}(): Sets the radius of the zone.
-- * @{#ZONE_RADIUS.GetRadius}(): Returns the radius of the zone.
--
-- ## 2.3) Manage the location of the zone
-- ## Manage the location of the zone
--
-- * @{#ZONE_RADIUS.SetVec2}(): Sets the @{DCSTypes#Vec2} of the zone.
-- * @{#ZONE_RADIUS.GetVec2}(): Returns the @{DCSTypes#Vec2} of the zone.
-- * @{#ZONE_RADIUS.GetVec3}(): Returns the @{DCSTypes#Vec3} of the zone, taking an additional height parameter.
--
-- ## 2.4) Zone point randomization
-- ## Zone point randomization
--
-- Various functions exist to find random points within the zone.
--
@@ -340,10 +371,7 @@ end
-- * @{#ZONE_RADIUS.GetRandomPointVec2}(): Gets a @{Point#POINT_VEC2} object representing a random 2D point in the zone.
-- * @{#ZONE_RADIUS.GetRandomPointVec3}(): Gets a @{Point#POINT_VEC3} object representing a random 3D point in the zone. Note that the height of the point is at landheight.
--
-- ===
--
-- @field #ZONE_RADIUS ZONE_RADIUS
--
-- @field #ZONE_RADIUS
ZONE_RADIUS = {
ClassName="ZONE_RADIUS",
}
@@ -615,19 +643,16 @@ end
-- @type ZONE
-- @extends Core.Zone#ZONE_RADIUS
--- @type ZONE
-- @extends #ZONE_RADIUS
--- # 3) ZONE class, extends @{Zone#ZONE_RADIUS}
--- # ZONE class, extends @{Zone#ZONE_RADIUS}
--
-- The ZONE class, defined by the zone name as defined within the Mission Editor.
-- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties.
--
-- ===
--
-- @field #ZONE ZONE
--
-- @field #ZONE
ZONE = {
ClassName="ZONE",
}
@@ -655,20 +680,16 @@ function ZONE:New( ZoneName )
end
--- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius.
-- @type ZONE_UNIT
--- @type ZONE_UNIT
-- @field Wrapper.Unit#UNIT ZoneUNIT
-- @extends Core.Zone#ZONE_RADIUS
--- # 4) #ZONE_UNIT class, extends @{Zone#ZONE_RADIUS}
--- # ZONE_UNIT class, extends @{Zone#ZONE_RADIUS}
--
-- The ZONE_UNIT class defined by a zone around a @{Unit#UNIT} with a radius.
-- This class implements the inherited functions from @{#ZONE_RADIUS} taking into account the own zone format and properties.
--
-- ===
--
-- @field #ZONE_UNIT ZONE_UNIT
--
-- @field #ZONE_UNIT
ZONE_UNIT = {
ClassName="ZONE_UNIT",
}
@@ -750,19 +771,15 @@ function ZONE_UNIT:GetVec3( Height )
end
--- @type ZONE_GROUP
-- @field Wrapper.Group#GROUP ZoneGROUP
-- @extends Core.Zone#ZONE_RADIUS
-- @extends #ZONE_RADIUS
--- # 5) #ZONE_GROUP class, extends @{Zone#ZONE_RADIUS}
--- # ZONE_GROUP class, extends @{Zone#ZONE_RADIUS}
--
-- The ZONE_GROUP class defines by a zone around a @{Group#GROUP} with a radius. The current leader of the group defines the center of the zone.
-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties.
--
-- ===
--
-- @field #ZONE_GROUP ZONE_GROUP
--
-- @field #ZONE_GROUP
ZONE_GROUP = {
ClassName="ZONE_GROUP",
}
@@ -777,7 +794,7 @@ function ZONE_GROUP:New( ZoneName, ZoneGROUP, Radius )
local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneGROUP:GetVec2(), Radius ) )
self:F( { ZoneName, ZoneGROUP:GetVec2(), Radius } )
self.ZoneGROUP = ZoneGROUP
self._.ZoneGROUP = ZoneGROUP
return self
end
@@ -789,7 +806,7 @@ end
function ZONE_GROUP:GetVec2()
self:F( self.ZoneName )
local ZoneVec2 = self.ZoneGROUP:GetVec2()
local ZoneVec2 = self._.ZoneGROUP:GetVec2()
self:T( { ZoneVec2 } )
@@ -803,7 +820,7 @@ function ZONE_GROUP:GetRandomVec2()
self:F( self.ZoneName )
local Point = {}
local Vec2 = self.ZoneGROUP:GetVec2()
local Vec2 = self._.ZoneGROUP:GetVec2()
local angle = math.random() * math.pi*2;
Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius();
@@ -817,17 +834,17 @@ end
--- @type ZONE_POLYGON_BASE
-- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCSTypes#Vec2}.
-- @extends Core.Zone#ZONE_BASE
-- --@field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCSTypes#Vec2}.
-- @extends #ZONE_BASE
--- # 6) ZONE_POLYGON_BASE class, extends @{Zone#ZONE_BASE}
--- # ZONE_POLYGON_BASE class, extends @{Zone#ZONE_BASE}
--
-- The ZONE_POLYGON_BASE class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon.
-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties.
-- This class is an abstract BASE class for derived classes, and is not meant to be instantiated.
--
-- ## 6.1) Zone point randomization
-- ## Zone point randomization
--
-- Various functions exist to find random points within the zone.
--
@@ -835,10 +852,7 @@ end
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec2}(): Return a @{Point#POINT_VEC2} object representing a random 2D point within the zone.
-- * @{#ZONE_POLYGON_BASE.GetRandomPointVec3}(): Return a @{Point#POINT_VEC3} object representing a random 3D point at landheight within the zone.
--
-- ===
--
-- @field #ZONE_POLYGON_BASE ZONE_POLYGON_BASE
--
-- @field #ZONE_POLYGON_BASE
ZONE_POLYGON_BASE = {
ClassName="ZONE_POLYGON_BASE",
}
@@ -859,24 +873,35 @@ function ZONE_POLYGON_BASE:New( ZoneName, PointsArray )
local i = 0
self.Polygon = {}
self._.Polygon = {}
for i = 1, #PointsArray do
self.Polygon[i] = {}
self.Polygon[i].x = PointsArray[i].x
self.Polygon[i].y = PointsArray[i].y
self._.Polygon[i] = {}
self._.Polygon[i].x = PointsArray[i].x
self._.Polygon[i].y = PointsArray[i].y
end
return self
end
--- Returns the center location of the polygon.
-- @param #ZONE_GROUP self
-- @return Dcs.DCSTypes#Vec2 The location of the zone based on the @{Group} location.
function ZONE_POLYGON_BASE:GetVec2()
self:F( self.ZoneName )
local Bounds = self:GetBoundingSquare()
return { x = ( Bounds.x2 + Bounds.x1 ) / 2, y = ( Bounds.y2 + Bounds.y1 ) / 2 }
end
--- Flush polygon coordinates as a table in DCS.log.
-- @param #ZONE_POLYGON_BASE self
-- @return #ZONE_POLYGON_BASE self
function ZONE_POLYGON_BASE:Flush()
self:F2()
self:E( { Polygon = self.ZoneName, Coordinates = self.Polygon } )
self:E( { Polygon = self.ZoneName, Coordinates = self._.Polygon } )
return self
end
@@ -892,17 +917,17 @@ function ZONE_POLYGON_BASE:BoundZone( UnBound )
local Segments = 10
i = 1
j = #self.Polygon
j = #self._.Polygon
while i <= #self.Polygon do
self:T( { i, j, self.Polygon[i], self.Polygon[j] } )
while i <= #self._.Polygon do
self:T( { i, j, self._.Polygon[i], self._.Polygon[j] } )
local DeltaX = self.Polygon[j].x - self.Polygon[i].x
local DeltaY = self.Polygon[j].y - self.Polygon[i].y
local DeltaX = self._.Polygon[j].x - self._.Polygon[i].x
local DeltaY = self._.Polygon[j].y - self._.Polygon[i].y
for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line.
local PointX = self.Polygon[i].x + ( Segment * DeltaX / Segments )
local PointY = self.Polygon[i].y + ( Segment * DeltaY / Segments )
local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments )
local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments )
local Tire = {
["country"] = "USA",
["category"] = "Fortifications",
@@ -942,17 +967,17 @@ function ZONE_POLYGON_BASE:SmokeZone( SmokeColor )
local Segments = 10
i = 1
j = #self.Polygon
j = #self._.Polygon
while i <= #self.Polygon do
self:T( { i, j, self.Polygon[i], self.Polygon[j] } )
while i <= #self._.Polygon do
self:T( { i, j, self._.Polygon[i], self._.Polygon[j] } )
local DeltaX = self.Polygon[j].x - self.Polygon[i].x
local DeltaY = self.Polygon[j].y - self.Polygon[i].y
local DeltaX = self._.Polygon[j].x - self._.Polygon[i].x
local DeltaY = self._.Polygon[j].y - self._.Polygon[i].y
for Segment = 0, Segments do -- We divide each line in 5 segments and smoke a point on the line.
local PointX = self.Polygon[i].x + ( Segment * DeltaX / Segments )
local PointY = self.Polygon[i].y + ( Segment * DeltaY / Segments )
local PointX = self._.Polygon[i].x + ( Segment * DeltaX / Segments )
local PointY = self._.Polygon[i].y + ( Segment * DeltaY / Segments )
POINT_VEC2:New( PointX, PointY ):Smoke( SmokeColor )
end
j = i
@@ -978,12 +1003,12 @@ function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 )
local InPolygon = false
Next = 1
Prev = #self.Polygon
Prev = #self._.Polygon
while Next <= #self.Polygon do
self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } )
if ( ( ( self.Polygon[Next].y > Vec2.y ) ~= ( self.Polygon[Prev].y > Vec2.y ) ) and
( Vec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( Vec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x )
while Next <= #self._.Polygon do
self:T( { Next, Prev, self._.Polygon[Next], self._.Polygon[Prev] } )
if ( ( ( self._.Polygon[Next].y > Vec2.y ) ~= ( self._.Polygon[Prev].y > Vec2.y ) ) and
( Vec2.x < ( self._.Polygon[Prev].x - self._.Polygon[Next].x ) * ( Vec2.y - self._.Polygon[Next].y ) / ( self._.Polygon[Prev].y - self._.Polygon[Next].y ) + self._.Polygon[Next].x )
) then
InPolygon = not InPolygon
end
@@ -1054,17 +1079,17 @@ end
-- @return #ZONE_POLYGON_BASE.BoundingSquare The bounding square.
function ZONE_POLYGON_BASE:GetBoundingSquare()
local x1 = self.Polygon[1].x
local y1 = self.Polygon[1].y
local x2 = self.Polygon[1].x
local y2 = self.Polygon[1].y
local x1 = self._.Polygon[1].x
local y1 = self._.Polygon[1].y
local x2 = self._.Polygon[1].x
local y2 = self._.Polygon[1].y
for i = 2, #self.Polygon do
self:T2( { self.Polygon[i], x1, y1, x2, y2 } )
x1 = ( x1 > self.Polygon[i].x ) and self.Polygon[i].x or x1
x2 = ( x2 < self.Polygon[i].x ) and self.Polygon[i].x or x2
y1 = ( y1 > self.Polygon[i].y ) and self.Polygon[i].y or y1
y2 = ( y2 < self.Polygon[i].y ) and self.Polygon[i].y or y2
for i = 2, #self._.Polygon do
self:T2( { self._.Polygon[i], x1, y1, x2, y2 } )
x1 = ( x1 > self._.Polygon[i].x ) and self._.Polygon[i].x or x1
x2 = ( x2 < self._.Polygon[i].x ) and self._.Polygon[i].x or x2
y1 = ( y1 > self._.Polygon[i].y ) and self._.Polygon[i].y or y1
y2 = ( y2 < self._.Polygon[i].y ) and self._.Polygon[i].y or y2
end
@@ -1073,18 +1098,15 @@ end
--- @type ZONE_POLYGON
-- @extends Core.Zone#ZONE_POLYGON_BASE
-- @extends #ZONE_POLYGON_BASE
--- # 7) ZONE_POLYGON class, extends @{Zone#ZONE_POLYGON_BASE}
--- # ZONE_POLYGON class, extends @{Zone#ZONE_POLYGON_BASE}
--
-- The ZONE_POLYGON class defined by a sequence of @{Group#GROUP} waypoints within the Mission Editor, forming a polygon.
-- This class implements the inherited functions from @{Zone#ZONE_RADIUS} taking into account the own zone format and properties.
--
-- ===
--
-- @field #ZONE_POLYGON ZONE_POLYGON
--
-- @field #ZONE_POLYGON
ZONE_POLYGON = {
ClassName="ZONE_POLYGON",
}
@@ -1100,7 +1122,7 @@ function ZONE_POLYGON:New( ZoneName, ZoneGroup )
local GroupPoints = ZoneGroup:GetTaskRoute()
local self = BASE:Inherit( self, ZONE_POLYGON_BASE:New( ZoneName, GroupPoints ) )
self:F( { ZoneName, ZoneGroup, self.Polygon } )
self:F( { ZoneName, ZoneGroup, self._.Polygon } )
return self
end