diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua index 9b5251f46..179f10d24 100644 --- a/Moose Development/Moose/Core/Event.lua +++ b/Moose Development/Moose/Core/Event.lua @@ -1,98 +1,98 @@ --- **Core** - Models DCS event dispatching using a publish-subscribe model. --- +-- -- === --- +-- -- ## Features: --- +-- -- * Capture DCS events and dispatch them to the subscribed objects. -- * Generate DCS events to the subscribed objects from within the code. --- +-- -- === --- +-- -- # Event Handling Overview --- +-- -- ![Objects](..\Presentations\EVENT\Dia2.JPG) --- +-- -- Within a running mission, various DCS events occur. Units are dynamically created, crash, die, shoot stuff, get hit etc. -- This module provides a mechanism to dispatch those events occuring within your running mission, to the different objects orchestrating your mission. --- +-- -- ![Objects](..\Presentations\EVENT\Dia3.JPG) --- +-- -- Objects can subscribe to different events. The Event dispatcher will publish the received DCS events to the subscribed MOOSE objects, in a specified order. -- In this way, the subscribed MOOSE objects are kept in sync with your evolving running mission. --- +-- -- ## 1. Event Dispatching --- +-- -- ![Objects](..\Presentations\EVENT\Dia4.JPG) --- --- The _EVENTDISPATCHER object is automatically created within MOOSE, --- and handles the dispatching of DCS Events occurring --- in the simulator to the subscribed objects +-- +-- The _EVENTDISPATCHER object is automatically created within MOOSE, +-- and handles the dispatching of DCS Events occurring +-- in the simulator to the subscribed objects -- in the correct processing order. -- -- ![Objects](..\Presentations\EVENT\Dia5.JPG) --- +-- -- There are 5 levels of kind of objects that the _EVENTDISPATCHER services: --- +-- -- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database. -- * SET_ derived classes: Subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority. -- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to teh subscribed UNIT object. -- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object. -- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object. --- +-- -- ![Objects](..\Presentations\EVENT\Dia6.JPG) --- +-- -- For most DCS events, the above order of updating will be followed. --- +-- -- ![Objects](..\Presentations\EVENT\Dia7.JPG) --- +-- -- But for some DCS events, the publishing order is reversed. This is due to the fact that objects need to be **erased** instead of added. --- +-- -- # 2. Event Handling --- +-- -- ![Objects](..\Presentations\EVENT\Dia8.JPG) --- +-- -- The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the @{BASE} class, @{UNIT} class and @{GROUP} class. -- The _EVENTDISPATCHER is a component that is quietly working in the background of MOOSE. --- +-- -- ![Objects](..\Presentations\EVENT\Dia9.JPG) --- --- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator, +-- +-- The BASE class provides methods to catch DCS Events. These are events that are triggered from within the DCS simulator, -- and handled through lua scripting. MOOSE provides an encapsulation to handle these events more efficiently. --- +-- -- ## 2.1. Subscribe to / Unsubscribe from DCS Events. --- +-- -- At first, the mission designer will need to **Subscribe** to a specific DCS event for the class. -- So, when the DCS event occurs, the class will be notified of that event. -- There are two functions which you use to subscribe to or unsubscribe from an event. --- +-- -- * @{Core.Base#BASE.HandleEvent}(): Subscribe to a DCS Event. -- * @{Core.Base#BASE.UnHandleEvent}(): Unsubscribe from a DCS Event. --- +-- -- Note that for a UNIT, the event will be handled **for that UNIT only**! -- Note that for a GROUP, the event will be handled **for all the UNITs in that GROUP only**! --- +-- -- For all objects of other classes, the subscribed events will be handled for **all UNITs within the Mission**! --- So if a UNIT within the mission has the subscribed event for that object, +-- So if a UNIT within the mission has the subscribed event for that object, -- then the object event handler will receive the event for that UNIT! --- +-- -- ## 2.2 Event Handling of DCS Events --- +-- -- Once the class is subscribed to the event, an **Event Handling** method on the object or class needs to be written that will be called -- when the DCS event occurs. The Event Handling method receives an @{Core.Event#EVENTDATA} structure, which contains a lot of information -- about the event that occurred. --- --- Find below an example of the prototype how to write an event handling function for two units: +-- +-- Find below an example of the prototype how to write an event handling function for two units: -- -- local Tank1 = UNIT:FindByName( "Tank A" ) -- local Tank2 = UNIT:FindByName( "Tank B" ) --- +-- -- -- Here we subscribe to the Dead events. So, if one of these tanks dies, the Tank1 or Tank2 objects will be notified. -- Tank1:HandleEvent( EVENTS.Dead ) -- Tank2:HandleEvent( EVENTS.Dead ) --- +-- -- --- This function is an Event Handling function that will be called when Tank1 is Dead. --- -- @param Wrapper.Unit#UNIT self +-- -- @param Wrapper.Unit#UNIT self -- -- @param Core.Event#EVENTDATA EventData -- function Tank1:OnEventDead( EventData ) -- @@ -100,73 +100,73 @@ -- end -- -- --- This function is an Event Handling function that will be called when Tank2 is Dead. --- -- @param Wrapper.Unit#UNIT self +-- -- @param Wrapper.Unit#UNIT self -- -- @param Core.Event#EVENTDATA EventData -- function Tank2:OnEventDead( EventData ) -- -- self:SmokeBlue() -- end --- +-- -- ## 2.3 Event Handling methods that are automatically called upon subscribed DCS events. --- +-- -- ![Objects](..\Presentations\EVENT\Dia10.JPG) --- +-- -- The following list outlines which EVENTS item in the structure corresponds to which Event Handling method. -- Always ensure that your event handling methods align with the events being subscribed to, or nothing will be executed. --- +-- -- # 3. EVENTS type --- --- The EVENTS structure contains names for all the different DCS events that objects can subscribe to using the +-- +-- The EVENTS structure contains names for all the different DCS events that objects can subscribe to using the -- @{Core.Base#BASE.HandleEvent}() method. --- +-- -- # 4. EVENTDATA type --- --- The @{Core.Event#EVENTDATA} structure contains all the fields that are populated with event information before +-- +-- The @{Core.Event#EVENTDATA} structure contains all the fields that are populated with event information before -- an Event Handler method is being called by the event dispatcher. -- The Event Handler received the EVENTDATA object as a parameter, and can be used to investigate further the different events. -- There are basically 4 main categories of information stored in the EVENTDATA structure: --- +-- -- * Initiator Unit data: Several fields documenting the initiator unit related to the event. -- * Target Unit data: Several fields documenting the target unit related to the event. -- * Weapon data: Certain events populate weapon information. -- * Place data: Certain events populate place information. --- +-- -- --- This function is an Event Handling function that will be called when Tank1 is Dead. -- -- EventData is an EVENTDATA structure. -- -- We use the EventData.IniUnit to smoke the tank Green. --- -- @param Wrapper.Unit#UNIT self +-- -- @param Wrapper.Unit#UNIT self -- -- @param Core.Event#EVENTDATA EventData -- function Tank1:OnEventDead( EventData ) -- -- EventData.IniUnit:SmokeGreen() -- end --- --- +-- +-- -- Find below an overview which events populate which information categories: --- +-- -- ![Objects](..\Presentations\EVENT\Dia14.JPG) --- --- **IMPORTANT NOTE:** Some events can involve not just UNIT objects, but also STATIC objects!!! +-- +-- **IMPORTANT NOTE:** Some events can involve not just UNIT objects, but also STATIC objects!!! -- In that case the initiator or target unit fields will refer to a STATIC object! -- In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated. -- The fields **IniObjectCategory** and **TgtObjectCategory** contain the indicator which **kind of object is involved** in the event. -- You can use the enumerator **Object.Category.UNIT** and **Object.Category.STATIC** to check on IniObjectCategory and TgtObjectCategory. -- Example code snippet: --- +-- -- if Event.IniObjectCategory == Object.Category.UNIT then -- ... -- end -- if Event.IniObjectCategory == Object.Category.STATIC then -- ... --- end --- +-- end +-- -- When a static object is involved in the event, the Group and Player fields won't be populated. --- +-- -- === --- +-- -- ### Author: **FlightControl** --- ### Contributions: --- +-- ### Contributions: +-- -- === -- -- @module Core.Event @@ -252,13 +252,13 @@ EVENTS = { --- 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. --- +-- -- @type EVENTDATA -- @field #number id The identifier of the event. --- +-- -- @field DCS#Unit initiator (UNIT/STATIC/SCENERY) The initiating @{DCS#Unit} or @{DCS#StaticObject}. -- @field DCS#Object.Category IniObjectCategory (UNIT/STATIC/SCENERY) The initiator object category ( Object.Category.UNIT or Object.Category.STATIC ). -- @field DCS#Unit IniDCSUnit (UNIT/STATIC) The initiating @{DCS#Unit} or @{DCS#StaticObject}. @@ -273,7 +273,7 @@ EVENTS = { -- @field DCS#coalition.side IniCoalition (UNIT) The coalition of the initiator. -- @field DCS#Unit.Category IniCategory (UNIT) The category of the initiator. -- @field #string IniTypeName (UNIT) The type name of the initiator. --- +-- -- @field DCS#Unit target (UNIT/STATIC) The target @{DCS#Unit} or @{DCS#StaticObject}. -- @field DCS#Object.Category TgtObjectCategory (UNIT/STATIC) The target object category ( Object.Category.UNIT or Object.Category.STATIC ). -- @field DCS#Unit TgtDCSUnit (UNIT/STATIC) The target @{DCS#Unit} or @{DCS#StaticObject}. @@ -288,19 +288,19 @@ EVENTS = { -- @field DCS#coalition.side TgtCoalition (UNIT) The coalition of the target. -- @field DCS#Unit.Category TgtCategory (UNIT) The category of the target. -- @field #string TgtTypeName (UNIT) The type name of the target. --- +-- -- @field DCS#Airbase place The @{DCS#Airbase} -- @field Wrapper.Airbase#AIRBASE Place The MOOSE airbase object. -- @field #string PlaceName The name of the airbase. --- +-- -- @field #table weapon The weapon used during the event. -- @field #table Weapon -- @field #string WeaponName Name of the weapon. -- @field DCS#Unit WeaponTgtDCSUnit Target DCS unit of the weapon. --- +-- -- @field Cargo.Cargo#CARGO Cargo The cargo object. -- @field #string CargoName The name of the cargo object. --- +-- -- @field Core.ZONE#ZONE Zone The zone object. -- @field #string ZoneName The name of the zone. @@ -311,255 +311,255 @@ local _EVENTMETA = { Order = 1, Side = "I", Event = "OnEventShot", - Text = "S_EVENT_SHOT" + Text = "S_EVENT_SHOT" }, [world.event.S_EVENT_HIT] = { Order = 1, Side = "T", Event = "OnEventHit", - Text = "S_EVENT_HIT" + Text = "S_EVENT_HIT" }, [world.event.S_EVENT_TAKEOFF] = { Order = 1, Side = "I", Event = "OnEventTakeoff", - Text = "S_EVENT_TAKEOFF" + Text = "S_EVENT_TAKEOFF" }, [world.event.S_EVENT_LAND] = { Order = 1, Side = "I", Event = "OnEventLand", - Text = "S_EVENT_LAND" + Text = "S_EVENT_LAND" }, [world.event.S_EVENT_CRASH] = { Order = -1, Side = "I", Event = "OnEventCrash", - Text = "S_EVENT_CRASH" + Text = "S_EVENT_CRASH" }, [world.event.S_EVENT_EJECTION] = { Order = 1, Side = "I", Event = "OnEventEjection", - Text = "S_EVENT_EJECTION" + Text = "S_EVENT_EJECTION" }, [world.event.S_EVENT_REFUELING] = { Order = 1, Side = "I", Event = "OnEventRefueling", - Text = "S_EVENT_REFUELING" + Text = "S_EVENT_REFUELING" }, [world.event.S_EVENT_DEAD] = { Order = -1, Side = "I", Event = "OnEventDead", - Text = "S_EVENT_DEAD" + Text = "S_EVENT_DEAD" }, [world.event.S_EVENT_PILOT_DEAD] = { Order = 1, Side = "I", Event = "OnEventPilotDead", - Text = "S_EVENT_PILOT_DEAD" + Text = "S_EVENT_PILOT_DEAD" }, [world.event.S_EVENT_BASE_CAPTURED] = { Order = 1, Side = "I", Event = "OnEventBaseCaptured", - Text = "S_EVENT_BASE_CAPTURED" + Text = "S_EVENT_BASE_CAPTURED" }, [world.event.S_EVENT_MISSION_START] = { Order = 1, Side = "N", Event = "OnEventMissionStart", - Text = "S_EVENT_MISSION_START" + Text = "S_EVENT_MISSION_START" }, [world.event.S_EVENT_MISSION_END] = { Order = 1, Side = "N", Event = "OnEventMissionEnd", - Text = "S_EVENT_MISSION_END" + Text = "S_EVENT_MISSION_END" }, [world.event.S_EVENT_TOOK_CONTROL] = { Order = 1, Side = "N", Event = "OnEventTookControl", - Text = "S_EVENT_TOOK_CONTROL" + Text = "S_EVENT_TOOK_CONTROL" }, [world.event.S_EVENT_REFUELING_STOP] = { Order = 1, Side = "I", Event = "OnEventRefuelingStop", - Text = "S_EVENT_REFUELING_STOP" + Text = "S_EVENT_REFUELING_STOP" }, [world.event.S_EVENT_BIRTH] = { Order = 1, Side = "I", Event = "OnEventBirth", - Text = "S_EVENT_BIRTH" + Text = "S_EVENT_BIRTH" }, [world.event.S_EVENT_HUMAN_FAILURE] = { Order = 1, Side = "I", Event = "OnEventHumanFailure", - Text = "S_EVENT_HUMAN_FAILURE" + Text = "S_EVENT_HUMAN_FAILURE" }, [world.event.S_EVENT_ENGINE_STARTUP] = { Order = 1, Side = "I", Event = "OnEventEngineStartup", - Text = "S_EVENT_ENGINE_STARTUP" + Text = "S_EVENT_ENGINE_STARTUP" }, [world.event.S_EVENT_ENGINE_SHUTDOWN] = { Order = 1, Side = "I", Event = "OnEventEngineShutdown", - Text = "S_EVENT_ENGINE_SHUTDOWN" + Text = "S_EVENT_ENGINE_SHUTDOWN" }, [world.event.S_EVENT_PLAYER_ENTER_UNIT] = { Order = 1, Side = "I", Event = "OnEventPlayerEnterUnit", - Text = "S_EVENT_PLAYER_ENTER_UNIT" + 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" + Text = "S_EVENT_PLAYER_LEAVE_UNIT" }, [world.event.S_EVENT_PLAYER_COMMENT] = { Order = 1, Side = "I", Event = "OnEventPlayerComment", - Text = "S_EVENT_PLAYER_COMMENT" + Text = "S_EVENT_PLAYER_COMMENT" }, [world.event.S_EVENT_SHOOTING_START] = { Order = 1, Side = "I", Event = "OnEventShootingStart", - Text = "S_EVENT_SHOOTING_START" + Text = "S_EVENT_SHOOTING_START" }, [world.event.S_EVENT_SHOOTING_END] = { Order = 1, Side = "I", Event = "OnEventShootingEnd", - Text = "S_EVENT_SHOOTING_END" + Text = "S_EVENT_SHOOTING_END" }, [world.event.S_EVENT_MARK_ADDED] = { Order = 1, Side = "I", Event = "OnEventMarkAdded", - Text = "S_EVENT_MARK_ADDED" + Text = "S_EVENT_MARK_ADDED" }, [world.event.S_EVENT_MARK_CHANGE] = { Order = 1, Side = "I", Event = "OnEventMarkChange", - Text = "S_EVENT_MARK_CHANGE" + Text = "S_EVENT_MARK_CHANGE" }, [world.event.S_EVENT_MARK_REMOVED] = { Order = 1, Side = "I", Event = "OnEventMarkRemoved", - Text = "S_EVENT_MARK_REMOVED" + Text = "S_EVENT_MARK_REMOVED" }, [EVENTS.NewCargo] = { Order = 1, Event = "OnEventNewCargo", - Text = "S_EVENT_NEW_CARGO" + Text = "S_EVENT_NEW_CARGO" }, [EVENTS.DeleteCargo] = { Order = 1, Event = "OnEventDeleteCargo", - Text = "S_EVENT_DELETE_CARGO" + Text = "S_EVENT_DELETE_CARGO" }, [EVENTS.NewZone] = { Order = 1, Event = "OnEventNewZone", - Text = "S_EVENT_NEW_ZONE" + Text = "S_EVENT_NEW_ZONE" }, [EVENTS.DeleteZone] = { Order = 1, Event = "OnEventDeleteZone", - Text = "S_EVENT_DELETE_ZONE" + Text = "S_EVENT_DELETE_ZONE" }, [EVENTS.NewZoneGoal] = { Order = 1, Event = "OnEventNewZoneGoal", - Text = "S_EVENT_NEW_ZONE_GOAL" + Text = "S_EVENT_NEW_ZONE_GOAL" }, [EVENTS.DeleteZoneGoal] = { Order = 1, Event = "OnEventDeleteZoneGoal", - Text = "S_EVENT_DELETE_ZONE_GOAL" + Text = "S_EVENT_DELETE_ZONE_GOAL" }, [EVENTS.RemoveUnit] = { Order = -1, Event = "OnEventRemoveUnit", - Text = "S_EVENT_REMOVE_UNIT" + Text = "S_EVENT_REMOVE_UNIT" }, [EVENTS.PlayerEnterAircraft] = { Order = 1, Event = "OnEventPlayerEnterAircraft", - Text = "S_EVENT_PLAYER_ENTER_AIRCRAFT" - }, + Text = "S_EVENT_PLAYER_ENTER_AIRCRAFT" + }, -- Added with DCS 2.5.6 [EVENTS.DetailedFailure] = { Order = 1, Event = "OnEventDetailedFailure", - Text = "S_EVENT_DETAILED_FAILURE" + Text = "S_EVENT_DETAILED_FAILURE" }, [EVENTS.Kill] = { Order = 1, Event = "OnEventKill", - Text = "S_EVENT_KILL" + Text = "S_EVENT_KILL" }, [EVENTS.Score] = { Order = 1, Event = "OnEventScore", - Text = "S_EVENT_SCORE" + Text = "S_EVENT_SCORE" }, [EVENTS.UnitLost] = { Order = 1, Event = "OnEventUnitLost", - Text = "S_EVENT_UNIT_LOST" + Text = "S_EVENT_UNIT_LOST" }, [EVENTS.LandingAfterEjection] = { Order = 1, Event = "OnEventLandingAfterEjection", - Text = "S_EVENT_LANDING_AFTER_EJECTION" + Text = "S_EVENT_LANDING_AFTER_EJECTION" }, -- Added with DCS 2.7.0 [EVENTS.ParatrooperLanding] = { Order = 1, Event = "OnEventParatrooperLanding", - Text = "S_EVENT_PARATROOPER_LENDING" + Text = "S_EVENT_PARATROOPER_LENDING" }, [EVENTS.DiscardChairAfterEjection] = { Order = 1, Event = "OnEventDiscardChairAfterEjection", - Text = "S_EVENT_DISCARD_CHAIR_AFTER_EJECTION" + Text = "S_EVENT_DISCARD_CHAIR_AFTER_EJECTION" }, [EVENTS.WeaponAdd] = { Order = 1, Event = "OnEventWeaponAdd", - Text = "S_EVENT_WEAPON_ADD" + Text = "S_EVENT_WEAPON_ADD" }, [EVENTS.TriggerZone] = { Order = 1, Event = "OnEventTriggerZone", - Text = "S_EVENT_TRIGGER_ZONE" + Text = "S_EVENT_TRIGGER_ZONE" }, [EVENTS.LandingQualityMark] = { Order = 1, Event = "OnEventLandingQualityMark", - Text = "S_EVENT_LANDING_QUALITYMARK" + Text = "S_EVENT_LANDING_QUALITYMARK" }, [EVENTS.BDA] = { Order = 1, Event = "OnEventBDA", - Text = "S_EVENT_BDA" - }, + Text = "S_EVENT_BDA" + }, } @@ -574,10 +574,10 @@ function EVENT:New() -- Inherit base. local self = BASE:Inherit( self, BASE:New() ) - + -- Add world event handler. self.EventHandler = world.addEventHandler(self) - + return self end @@ -590,22 +590,22 @@ end function EVENT:Init( EventID, EventClass ) self:F3( { _EVENTMETA[EventID].Text, EventClass } ) - if not self.Events[EventID] then + 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] = {} end - + -- Each event has a subtable of EventClasses, ordered by EventPriority. local EventPriority = EventClass:GetEventPriority() - + if not self.Events[EventID][EventPriority] then self.Events[EventID][EventPriority] = setmetatable( {}, { __mode = "k" } ) - end + end if not self.Events[EventID][EventPriority][EventClass] then self.Events[EventID][EventPriority][EventClass] = {} end - + return self.Events[EventID][EventPriority][EventClass] end @@ -625,11 +625,11 @@ function EVENT:RemoveEvent( EventClass, EventID ) -- Events. self.Events = self.Events or {} self.Events[EventID] = self.Events[EventID] or {} - self.Events[EventID][EventPriority] = self.Events[EventID][EventPriority] or {} - + self.Events[EventID][EventPriority] = self.Events[EventID][EventPriority] or {} + -- Remove self.Events[EventID][EventPriority][EventClass] = nil - + return self end @@ -643,7 +643,7 @@ function EVENT:Reset( EventObject ) --R2.1 self:F( { "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 @@ -665,14 +665,14 @@ end function EVENT:RemoveAll(EventClass) local EventClassName = EventClass:GetClassNameAndID() - + -- Get Event prio. local EventPriority = EventClass:GetEventPriority() - + for EventID, EventData in pairs( self.Events ) do self.Events[EventID][EventPriority][EventClass] = nil end - + return self end @@ -705,7 +705,7 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID ) local EventData = self:Init( EventID, EventClass ) EventData.EventFunction = EventFunction - + return self end @@ -753,12 +753,12 @@ do -- OnBirth -- @return #EVENT self function EVENT:OnBirthForTemplate( EventTemplate, EventFunction, EventClass ) self:F2( EventTemplate.name ) - + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Birth ) - + return self end - + end do -- OnCrash @@ -771,16 +771,16 @@ do -- OnCrash -- @return #EVENT function EVENT:OnCrashForTemplate( EventTemplate, EventFunction, EventClass ) self:F2( EventTemplate.name ) - + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Crash ) - + return self end end do -- OnDead - + --- Create an OnDead event handler for a group -- @param #EVENT self -- @param Wrapper.Group#GROUP EventGroup The GROUP object. @@ -789,12 +789,12 @@ do -- OnDead -- @return #EVENT self function EVENT:OnDeadForTemplate( EventTemplate, EventFunction, EventClass ) self:F2( EventTemplate.name ) - + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Dead ) - + return self end - + end @@ -808,12 +808,12 @@ do -- OnLand -- @return #EVENT self function EVENT:OnLandForTemplate( EventTemplate, EventFunction, EventClass ) self:F2( EventTemplate.name ) - + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Land ) - + return self end - + end do -- OnTakeOff @@ -826,12 +826,12 @@ do -- OnTakeOff -- @return #EVENT self function EVENT:OnTakeOffForTemplate( EventTemplate, EventFunction, EventClass ) self:F2( EventTemplate.name ) - + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.Takeoff ) - + return self end - + end do -- OnEngineShutDown @@ -844,12 +844,12 @@ do -- OnEngineShutDown -- @return #EVENT function EVENT:OnEngineShutDownForTemplate( EventTemplate, EventFunction, EventClass ) self:F2( EventTemplate.name ) - + self:OnEventForTemplate( EventTemplate, EventFunction, EventClass, EVENTS.EngineShutdown ) - + return self end - + end do -- Event Creation @@ -859,13 +859,13 @@ do -- Event Creation -- @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 @@ -874,13 +874,13 @@ do -- Event Creation -- @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 @@ -889,13 +889,13 @@ do -- Event Creation -- @param Core.Zone#ZONE_BASE Zone The Zone created. function EVENT:CreateEventNewZone( Zone ) self:F( { Zone } ) - + local Event = { id = EVENTS.NewZone, time = timer.getTime(), zone = Zone, } - + world.onEvent( Event ) end @@ -904,13 +904,13 @@ do -- Event Creation -- @param Core.Zone#ZONE_BASE Zone The Zone created. function EVENT:CreateEventDeleteZone( Zone ) self:F( { Zone } ) - + local Event = { id = EVENTS.DeleteZone, time = timer.getTime(), zone = Zone, } - + world.onEvent( Event ) end @@ -919,13 +919,13 @@ do -- Event Creation -- @param Core.Functional#ZONE_GOAL ZoneGoal The ZoneGoal created. function EVENT:CreateEventNewZoneGoal( ZoneGoal ) self:F( { ZoneGoal } ) - + local Event = { id = EVENTS.NewZoneGoal, time = timer.getTime(), ZoneGoal = ZoneGoal, } - + world.onEvent( Event ) end @@ -935,13 +935,13 @@ do -- Event Creation -- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created. function EVENT:CreateEventDeleteZoneGoal( ZoneGoal ) self:F( { ZoneGoal } ) - + local Event = { id = EVENTS.DeleteZoneGoal, time = timer.getTime(), ZoneGoal = ZoneGoal, } - + world.onEvent( Event ) end @@ -951,30 +951,30 @@ do -- Event Creation -- @param Wrapper.Unit#UNIT PlayerUnit. function EVENT:CreateEventPlayerEnterUnit( PlayerUnit ) self:F( { PlayerUnit } ) - + local Event = { id = EVENTS.PlayerEnterUnit, time = timer.getTime(), initiator = PlayerUnit:GetDCSObject() } - + world.onEvent( Event ) end - + --- Creation of a S_EVENT_PLAYER_ENTER_AIRCRAFT event. -- @param #EVENT self -- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered. function EVENT:CreateEventPlayerEnterAircraft( PlayerUnit ) self:F( { PlayerUnit } ) - + local Event = { id = EVENTS.PlayerEnterAircraft, time = timer.getTime(), initiator = PlayerUnit:GetDCSObject() } - + world.onEvent( Event ) - end + end end @@ -989,31 +989,31 @@ function EVENT:onEvent( Event ) if BASE.Debug ~= nil then env.info( debug.traceback() ) end - + return errmsg end -- Get event meta data. local EventMeta = _EVENTMETA[Event.id] - + -- Check if this is a known event? if EventMeta then - - if self and - self.Events and + + if self and + self.Events and self.Events[Event.id] and self.MissionEnd == false and ( Event.initiator ~= nil or ( Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit ) ) then - + if Event.id and Event.id == EVENTS.MissionEnd then self.MissionEnd = true end - - if Event.initiator then - + + if Event.initiator then + Event.IniObjectCategory = Event.initiator:getCategory() - + if Event.IniObjectCategory == Object.Category.UNIT then Event.IniDCSUnit = Event.initiator Event.IniDCSUnitName = Event.IniDCSUnit:getName() @@ -1037,7 +1037,7 @@ function EVENT:onEvent( Event ) Event.IniTypeName = Event.IniDCSUnit:getTypeName() Event.IniCategory = Event.IniDCSUnit:getDesc().category end - + if Event.IniObjectCategory == Object.Category.STATIC then if Event.id==31 then --env.info("FF event 31") @@ -1049,6 +1049,14 @@ function EVENT:onEvent( Event ) Event.IniCoalition = 0 Event.IniCategory = 0 Event.IniTypeName = "Ejected Pilot" + elseif Event.id == 33 then -- ejection seat discarded + Event.IniDCSUnit = Event.initiator + local ID=Event.initiator.id_ + Event.IniDCSUnitName = string.format("Ejection Seat ID %s", tostring(ID)) + Event.IniUnitName = Event.IniDCSUnitName + Event.IniCoalition = 0 + Event.IniCategory = 0 + Event.IniTypeName = "Ejection Seat" else Event.IniDCSUnit = Event.initiator Event.IniDCSUnitName = Event.IniDCSUnit:getName() @@ -1059,7 +1067,7 @@ function EVENT:onEvent( Event ) Event.IniTypeName = Event.IniDCSUnit:getTypeName() end end - + if Event.IniObjectCategory == Object.Category.CARGO then Event.IniDCSUnit = Event.initiator Event.IniDCSUnitName = Event.IniDCSUnit:getName() @@ -1069,7 +1077,7 @@ function EVENT:onEvent( Event ) Event.IniCategory = Event.IniDCSUnit:getDesc().category Event.IniTypeName = Event.IniDCSUnit:getTypeName() end - + if Event.IniObjectCategory == Object.Category.SCENERY then Event.IniDCSUnit = Event.initiator Event.IniDCSUnitName = Event.IniDCSUnit:getName() @@ -1078,7 +1086,7 @@ function EVENT:onEvent( Event ) Event.IniCategory = Event.IniDCSUnit:getDesc().category Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY" -- TODO: Bug fix for 2.1! end - + if Event.IniObjectCategory == Object.Category.BASE then Event.IniDCSUnit = Event.initiator Event.IniDCSUnitName = Event.IniDCSUnit:getName() @@ -1086,15 +1094,15 @@ function EVENT:onEvent( Event ) Event.IniUnit = AIRBASE:FindByName(Event.IniDCSUnitName) Event.IniCoalition = Event.IniDCSUnit:getCoalition() Event.IniCategory = Event.IniDCSUnit:getDesc().category - Event.IniTypeName = Event.IniDCSUnit:getTypeName() + Event.IniTypeName = Event.IniDCSUnit:getTypeName() end end - + if Event.target then - + Event.TgtObjectCategory = Event.target:getCategory() - - if Event.TgtObjectCategory == Object.Category.UNIT then + + if Event.TgtObjectCategory == Object.Category.UNIT then Event.TgtDCSUnit = Event.target Event.TgtDCSGroup = Event.TgtDCSUnit:getGroup() Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() @@ -1113,31 +1121,39 @@ function EVENT:onEvent( Event ) Event.TgtCategory = Event.TgtDCSUnit:getDesc().category Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() end - + env.info("FF I am here first") if Event.TgtObjectCategory == Object.Category.STATIC then - env.info("FF I am here") - BASE:T({Event = Event}) - Event.TgtDCSUnit = Event.target + BASE:T({StaticTgtEvent = Event.id}) + -- get base data + Event.TgtDCSUnit = Event.target + if Event.target:isExist() and Event.id ~= 33 then -- leave out ejected seat object Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() Event.TgtUnitName = Event.TgtDCSUnitName Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false ) Event.TgtCoalition = Event.TgtDCSUnit:getCoalition() Event.TgtCategory = Event.TgtDCSUnit:getDesc().category Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() - -- Same as for Event Initiator above 2.7 issue - --[[ - Event.TgtDCSUnit = Event.target - local ID=Event.initiator.id_ - Event.TgtDCSUnitName = string.format("Ejected Pilot ID %s", tostring(ID)) - Event.TgtUnitName = Event.TgtDCSUnitName - --Event.TgtUnit = STATIC:FindByName( Event.TgtDCSUnitName, false ) - Event.TgtCoalition = Event.IniCoalition - Event.TgtCategory = Event.IniCategory - Event.TgtTypeName = "Ejected Pilot" - ]] + else + Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id)) + Event.TgtUnitName = Event.TgtDCSUnitName + Event.TgtUnit = nil + Event.TgtCoalition = 0 + Event.TgtCategory = 0 + if Event.id == 6 then + Event.TgtTypeName = "Ejected Pilot" + Event.TgtDCSUnitName = string.format("Ejected Pilot ID %s", tostring(Event.IniDCSUnitName)) + Event.TgtUnitName = Event.TgtDCSUnitName + elseif Event.id == 33 then + Event.TgtTypeName = "Ejection Seat" + Event.TgtDCSUnitName = string.format("Ejection Seat ID %s", tostring(Event.IniDCSUnitName)) + Event.TgtUnitName = Event.TgtDCSUnitName + else + Event.TgtTypeName = "Static" + end + end end - + if Event.TgtObjectCategory == Object.Category.SCENERY then Event.TgtDCSUnit = Event.target Event.TgtDCSUnitName = Event.TgtDCSUnit:getName() @@ -1147,7 +1163,7 @@ function EVENT:onEvent( Event ) Event.TgtTypeName = Event.TgtDCSUnit:getTypeName() end end - + if Event.weapon then Event.Weapon = Event.weapon Event.WeaponName = Event.Weapon:getTypeName() @@ -1158,20 +1174,20 @@ function EVENT:onEvent( Event ) Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName() --Event.WeaponTgtDCSUnit = Event.Weapon:getTarget() end - - -- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase. - if Event.place then + + -- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase. + if Event.place then if Event.id==EVENTS.LandingAfterEjection then -- Place is here the UNIT of which the pilot ejected. --local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :( -- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground. --Event.Place=UNIT:Find(Event.place) - else + else Event.Place=AIRBASE:Find(Event.place) Event.PlaceName=Event.Place:GetName() end end - + -- Mark points. if Event.idx then Event.MarkID=Event.idx @@ -1181,80 +1197,80 @@ function EVENT:onEvent( Event ) Event.MarkCoalition=Event.coalition Event.MarkGroupID = Event.groupID end - + if Event.cargo then Event.Cargo = Event.cargo Event.CargoName = Event.cargo.Name end - + if Event.zone then Event.Zone = Event.zone Event.ZoneName = Event.zone.ZoneName end - + local PriorityOrder = EventMeta.Order local PriorityBegin = PriorityOrder == -1 and 5 or 1 local PriorityEnd = PriorityOrder == -1 and 1 or 5 - + if Event.IniObjectCategory ~= Object.Category.STATIC then self:F( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } ) end - + for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do - + if self.Events[Event.id][EventPriority] then - + -- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called. for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do - + --if Event.IniObjectCategory ~= Object.Category.STATIC then -- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } ) --end - + 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 EventData.EventUnit then - + -- So now the EventClass must be a UNIT class!!! We check if it is still "Alive". if EventClass:IsAlive() or - Event.id == EVENTS.PlayerEnterUnit or - Event.id == EVENTS.Crash or - Event.id == EVENTS.Dead or + Event.id == EVENTS.PlayerEnterUnit or + Event.id == EVENTS.Crash or + Event.id == EVENTS.Dead or Event.id == EVENTS.RemoveUnit then - + local UnitName = EventClass:GetName() - - if ( EventMeta.Side == "I" and UnitName == Event.IniDCSUnitName ) or + + 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:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) end - - local Result, Value = xpcall( - function() - return EventData.EventFunction( EventClass, Event ) + + 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:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) end - - local Result, Value = xpcall( - function() - return EventFunction( EventClass, Event ) + + local Result, Value = xpcall( + function() + return EventFunction( EventClass, Event ) end, ErrorHandler ) end end @@ -1263,102 +1279,102 @@ function EVENT:onEvent( Event ) -- The EventClass is not alive anymore, we remove it from the EventHandlers... self:RemoveEvent( 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 EventData.EventGroup then - + -- So now the EventClass must be a GROUP class!!! We check if it is still "Alive". if EventClass:IsAlive() or Event.id == EVENTS.PlayerEnterUnit or Event.id == EVENTS.Crash or Event.id == EVENTS.Dead or Event.id == EVENTS.RemoveUnit then - + -- 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 + + if ( EventMeta.Side == "I" and GroupName == Event.IniDCSGroupName ) or ( EventMeta.Side == "T" and GroupName == Event.TgtDCSGroupName ) then - + -- First test if a EventFunction is Set, otherwise search for the default function if EventData.EventFunction then - + if Event.IniObjectCategory ~= 3 then self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } ) end - - local Result, Value = xpcall( - function() - return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) ) + + local Result, Value = xpcall( + function() + return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) ) end, ErrorHandler ) - + else - + -- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object. local EventFunction = EventClass[ EventMeta.Event ] if EventFunction and type( EventFunction ) == "function" then - + -- Now call the default event function. if Event.IniObjectCategory ~= 3 then self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } ) end - - local Result, Value = xpcall( - function() - return EventFunction( EventClass, Event, unpack( EventData.Params ) ) + + local Result, Value = xpcall( + function() + return EventFunction( EventClass, Event, unpack( EventData.Params ) ) end, ErrorHandler ) end end end else -- The EventClass is not alive anymore, we remove it from the EventHandlers... - --self:RemoveEvent( EventClass, Event.id ) + --self:RemoveEvent( EventClass, Event.id ) end else - + -- 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:F2( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } ) - end - local Result, Value = xpcall( - function() - return EventData.EventFunction( EventClass, Event ) + 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:F2( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } ) end - - local Result, Value = xpcall( - function() + + local Result, Value = xpcall( + function() local Result, Value = EventFunction( EventClass, Event ) - return Result, Value + return Result, Value end, ErrorHandler ) end end - + end end end end end end - + -- When cargo was deleted, it may probably be because of an S_EVENT_DEAD. -- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call. -- And this is a problem because it will remove all entries from the SET_CARGOs. @@ -1369,12 +1385,12 @@ function EVENT:onEvent( Event ) Event.Cargo.NoDestroy = nil end else - self:T( { EventMeta.Text, Event } ) + self:T( { EventMeta.Text, Event } ) end else self:E(string.format("WARNING: Could not get EVENTMETA data for event ID=%d! Is this an unknown/new DCS event?", tostring(Event.id))) end - + Event = nil end diff --git a/Moose Development/Moose/Functional/Mantis.lua b/Moose Development/Moose/Functional/Mantis.lua index 4d6565262..23faabb3f 100644 --- a/Moose Development/Moose/Functional/Mantis.lua +++ b/Moose Development/Moose/Functional/Mantis.lua @@ -51,7 +51,7 @@ -- @field #number adv_state Advanced mode state tracker -- @field #boolean advAwacs Boolean switch to use Awacs as a separate detection stream -- @field #number awacsrange Detection range of an optional Awacs unit --- @field #boolean UseAIOnOff Decide if we are using AI on/off (true) or AlarmState red/green (default) +-- @field #boolean UseEmOnOff Decide if we are using Emissions on/off (true) or AlarmState red/green (default) -- @field Functional.Shorad#SHORAD Shorad SHORAD Object, if available -- @field #boolean ShoradLink If true, #MANTIS has #SHORAD enabled -- @field #number ShoradTime Timer in seconds, how long #SHORAD will be active after a detection inside of the defense range @@ -191,7 +191,7 @@ MANTIS = { ShoradLink = false, ShoradTime = 600, ShoradActDistance = 15000, - UseAIOnOff = false, + UseEmOnOff = true, } ----------------------------------------------------------------------- @@ -208,7 +208,7 @@ do --@param #string coaltion Coalition side of your setup, e.g. "blue", "red" or "neutral" --@param #boolean dynamic Use constant (true) filtering or just filter once (false, default) (optional) --@param #string awacs Group name of your Awacs (optional) - --@param #boolean AIOnOff Make MANTIS switch AI on and off instead of changing the alarm state between RED and GREEN (optional) + --@param #boolean EmOnOff Make MANTIS switch Emissions on and off instead of changing the alarm state between RED and GREEN (optional, deault true) --@return #MANTIS self --@usage Start up your MANTIS with a basic setting -- @@ -230,7 +230,7 @@ do -- `mybluemantis = MANTIS:New("bluemantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")` -- `mybluemantis:Start()` -- - function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, AIOnOff) + function MANTIS:New(name,samprefix,ewrprefix,hq,coaltion,dynamic,awacs, EmOnOff) -- DONE: Create some user functions for these -- DONE: Make HQ useful @@ -264,7 +264,11 @@ do self.ShoradTime = 600 self.ShoradActDistance = 15000 -- TODO: add emissions on/off when available .... in 2 weeks - self.UseAIOnOff = AIOnOff or false + if EmOnOff then + if EmOnOff == false then + self.UseEmOnOff = false + end + end if type(awacs) == "string" then self.advAwacs = true @@ -304,7 +308,7 @@ do end -- @field #string version - self.version="0.4.0" + self.version="0.4.1" self:I(string.format("***** Starting MANTIS Version %s *****", self.version)) return self @@ -463,11 +467,11 @@ do end end - --- Set using AI on/off instead of changing alarm state + --- Set using Emissions on/off instead of changing alarm state -- @param #MANTIS self - -- @param #boolean switch Decide if we are changing alarm state or AI state - function MANTIS:SetUsingAIOnOff(switch) - self.UseAIOnOff = switch or false + -- @param #boolean switch Decide if we are changing alarm state or Emission state + function MANTIS:SetUsingEmOnOff(switch) + self.UseEmOnOff = switch or false end --- [Internal] Function to check if HQ is alive @@ -714,8 +718,9 @@ do for _i,_group in pairs (SAM_Grps) do local group = _group -- TODO: add emissions on/off - if self.UseAIOnOff then - group:SetAIOff() + if self.UseEmOnOff then + group:EnableEmission(false) + --group:SetAIOff() else group:OptionAlarmStateGreen() -- AI off end @@ -822,9 +827,10 @@ do if IsInZone then --check any target in zone if samgroup:IsAlive() then -- switch on SAM - if self.UseAIOnOff then + if self.UseEmOnOff then -- TODO: add emissions on/off - samgroup:SetAIOn() + --samgroup:SetAIOn() + samgroup:EnableEmission(true) end samgroup:OptionAlarmStateRed() -- link in to SHORAD if available @@ -843,9 +849,10 @@ do else if samgroup:IsAlive() then -- switch off SAM - if self.UseAIOnOff then + if self.UseEmOnOff then -- TODO: add emissions on/off - samgroup:SetAIOff() + samgroup:EnableEmission(false) + --samgroup:SetAIOff() else samgroup:OptionAlarmStateGreen() end @@ -883,9 +890,10 @@ do local name = _data[1] local samgroup = GROUP:FindByName(name) if samgroup:IsAlive() then - if self.UseAIOnOff then + if self.UseEmOnOff then -- TODO: add emissions on/off - samgroup:SetAIOn() + --samgroup:SetAIOn() + samgroup:EnableEmission(true) end samgroup:OptionAlarmStateRed() end -- end alive diff --git a/Moose Development/Moose/Functional/Sead.lua b/Moose Development/Moose/Functional/Sead.lua index 2c5abb451..420ec1a7e 100644 --- a/Moose Development/Moose/Functional/Sead.lua +++ b/Moose Development/Moose/Functional/Sead.lua @@ -109,7 +109,7 @@ function SEAD:New( SEADGroupPrefixes ) end self:HandleEvent( EVENTS.Shot ) - self:I("*** SEAD - Started Version 0.2.5") + self:I("*** SEAD - Started Version 0.2.7") return self end @@ -205,15 +205,18 @@ function SEAD:OnEventShot( EventData ) SEADWeaponName == "weapons.missiles.AGM_84H" --AGM84 anti-radiation missiles fired --]] if self:_CheckHarms(SEADWeaponName) then - + local _targetskill = "Random" + local _targetMimgroupName = "none" local _evade = math.random (1,100) -- random number for chance of evading action local _targetMim = EventData.Weapon:getTarget() -- Identify target - local _targetMimname = Unit.getName(_targetMim) -- Unit name - local _targetMimgroup = Unit.getGroup(Weapon.getTarget(SEADWeapon)) --targeted group - local _targetMimgroupName = _targetMimgroup:getName() -- group name - local _targetskill = _DATABASE.Templates.Units[_targetMimname].Template.skill - self:T( self.SEADGroupPrefixes ) - self:T( _targetMimgroupName ) + local _targetUnit = UNIT:Find(_targetMim) -- Unit name by DCS Object + if _targetUnit and _targetUnit:IsAlive() then + local _targetMimgroup = _targetUnit:GetGroup() + local _targetMimgroupName = _targetMimgroup:GetName() -- group name + --local _targetskill = _DATABASE.Templates.Units[_targetUnit].Template.skill + self:T( self.SEADGroupPrefixes ) + self:T( _targetMimgroupName ) + end -- see if we are shot at local SEADGroupFound = false for SEADGroupPrefixID, SEADGroupPrefix in pairs( self.SEADGroupPrefixes ) do @@ -249,6 +252,7 @@ function SEAD:OnEventShot( EventData ) local range = self.EngagementRange -- Feature Request #1355 self:T(string.format("*** SEAD - Engagement Range is %d", range)) id.ctrl:setOption(AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.RED) + --id.groupName:enableEmission(true) id.ctrl:setOption(AI.Option.Ground.id.AC_ENGAGEMENT_RANGE_RESTRICTION,range) --Feature Request #1355 self.SuppressedGroups[id.groupName] = nil --delete group id from table when done end @@ -261,6 +265,7 @@ function SEAD:OnEventShot( EventData ) SuppressionEndTime = delay } Controller.setOption(_targetMimcont, AI.Option.Ground.id.ALARM_STATE,AI.Option.Ground.val.ALARM_STATE.GREEN) + --_targetMimgroup:enableEmission(false) timer.scheduleFunction(SuppressionEnd, id, SuppressionEndTime) --Schedule the SuppressionEnd() function end end diff --git a/Moose Development/Moose/Functional/Shorad.lua b/Moose Development/Moose/Functional/Shorad.lua index 155a86829..e2f3991f8 100644 --- a/Moose Development/Moose/Functional/Shorad.lua +++ b/Moose Development/Moose/Functional/Shorad.lua @@ -18,7 +18,7 @@ -- @module Functional.Shorad -- @image Functional.Shorad.jpg -- --- Date: Feb 2021 +-- Date: May 2021 ------------------------------------------------------------------------- --- **SHORAD** class, extends Core.Base#BASE @@ -38,7 +38,7 @@ -- @field #boolean DefendMavs Default true, intercept incoming AG-Missiles -- @field #number DefenseLowProb Default 70, minimum detection limit -- @field #number DefenseHighProb Default 90, maximim detection limit --- @field #boolean UseAIOnOff Decide if we are using AI on/off (true) or AlarmState red/green (default). +-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green. -- @extends Core.Base#BASE --- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie) @@ -96,7 +96,7 @@ SHORAD = { DefendMavs = true, DefenseLowProb = 70, DefenseHighProb = 90, - UseAIOnOff = false, + UseEmOnOff = false, } ----------------------------------------------------------------------- @@ -176,8 +176,8 @@ do self.DefendMavs = true self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin - self.UseAIOnOff = false -- Decide if we are using AI on/off (true) or AlarmState red/green (default) - self:I("*** SHORAD - Started Version 0.1.0") + self.UseEmOnOff = false -- Decide if we are using Emission on/off (default) or AlarmState red/green + self:I("*** SHORAD - Started Version 0.2.1") -- Set the string id for output to DCS.log file. self.lid=string.format("SHORAD %s | ", self.name) self:_InitState() @@ -192,8 +192,9 @@ do self:T({set = set}) local aliveset = set:GetAliveSet() --#table for _,_group in pairs (aliveset) do - if self.UseAIOnOff then - _group:SetAIOff() + if self.UseEmOnOff then + --_group:SetAIOff() + _group:EnableEmission(false) else _group:OptionAlarmStateGreen() --Wrapper.Group#GROUP end @@ -279,11 +280,11 @@ do self.Radius = radius end - --- Set using AI on/off instead of changing alarm state + --- Set using Emission on/off instead of changing alarm state -- @param #SHORAD self -- @param #boolean switch Decide if we are changing alarm state or AI state - function SHORAD:SetUsingAIOnOff(switch) - self.UseAIOnOff = switch or false + function SHORAD:SetUsingEmOnOff(switch) + self.UseEmOnOff = switch or false end --- Check if a HARM was fired @@ -410,8 +411,9 @@ do local function SleepShorad(group) local groupname = group:GetName() self.ActiveGroups[groupname] = nil - if self.UseAIOnOff then - group:SetAIOff() + if self.UseEmOnOff then + group:EnableEmission(false) + --group:SetAIOff() else group:OptionAlarmStateGreen() end @@ -425,8 +427,9 @@ do local text = string.format("Waking up SHORAD %s", _group:GetName()) self:T(text) local m = MESSAGE:New(text,10,"SHORAD"):ToAllIf(self.debug) - if self.UseAIOnOff then + if self.UseEmOnOff then _group:SetAIOn() + _group:EnableEmission(true) end _group:OptionAlarmStateRed() local groupname = _group:GetName() @@ -461,23 +464,31 @@ do end local text = string.format("%s Missile Launched = %s | Detected probability state is %s", self.lid, ShootingWeaponName, DetectedText) self:T( text ) - local m = MESSAGE:New(text,15,"Info"):ToAllIf(self.debug) + local m = MESSAGE:New(text,10,"Info"):ToAllIf(self.debug) -- if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then -- get target data local targetdata = EventData.Weapon:getTarget() -- Identify target - local targetunitname = Unit.getName(targetdata) -- Unit name - local targetgroup = Unit.getGroup(Weapon.getTarget(ShootingWeapon)) --targeted group - local targetgroupname = targetgroup:getName() -- group name - -- check if we or a SAM site are the target - --local TargetGroup = EventData.TgtGroup -- Wrapper.Group#GROUP - local shotatus = self:_CheckShotAtShorad(targetgroupname) --#boolean - local shotatsams = self:_CheckShotAtSams(targetgroupname) --#boolean - -- if being shot at, find closest SHORADs to activate - if shotatsams or shotatus then - self:T({shotatsams=shotatsams,shotatus=shotatus}) - self:WakeUpShorad(targetgroupname, self.Radius, self.ActiveTimer) - end + local targetunit = UNIT:Find(targetdata) + --local targetunitname = Unit.getName(targetdata) -- Unit name + if targetunit and targetunit:IsAlive() then + local targetunitname = targetunit:GetName() + --local targetgroup = Unit.getGroup(Weapon.getTarget(ShootingWeapon)) --targeted group + local targetgroup = targetunit:GetGroup() + local targetgroupname = targetgroup:GetName() -- group name + local text = string.format("%s Missile Target = %s", self.lid, tostring(targetgroupname)) + self:T( text ) + local m = MESSAGE:New(text,10,"Info"):ToAllIf(self.debug) + -- check if we or a SAM site are the target + --local TargetGroup = EventData.TgtGroup -- Wrapper.Group#GROUP + local shotatus = self:_CheckShotAtShorad(targetgroupname) --#boolean + local shotatsams = self:_CheckShotAtSams(targetgroupname) --#boolean + -- if being shot at, find closest SHORADs to activate + if shotatsams or shotatus then + self:T({shotatsams=shotatsams,shotatus=shotatus}) + self:WakeUpShorad(targetgroupname, self.Radius, self.ActiveTimer) + end + end end end end diff --git a/Moose Development/Moose/Wrapper/Controllable.lua b/Moose Development/Moose/Wrapper/Controllable.lua index 0e98f49e4..165835229 100644 --- a/Moose Development/Moose/Wrapper/Controllable.lua +++ b/Moose Development/Moose/Wrapper/Controllable.lua @@ -1460,7 +1460,7 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType, Alti DCSTask.params.weaponType=WeaponType end - self:I(DCSTask) + --self:I(DCSTask) return DCSTask end