From 07c3be9d6ac79d5c43608dbaba553f4614d52b96 Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Tue, 18 Apr 2023 10:24:56 +0200 Subject: [PATCH 1/5] Fixes for `getPlayername()` errors --- .../Moose/Functional/PseudoATC.lua | 146 ++++-------------- Moose Development/Moose/Ops/Airboss.lua | 24 +-- 2 files changed, 41 insertions(+), 129 deletions(-) diff --git a/Moose Development/Moose/Functional/PseudoATC.lua b/Moose Development/Moose/Functional/PseudoATC.lua index 5ee714705..16c530cf3 100644 --- a/Moose Development/Moose/Functional/PseudoATC.lua +++ b/Moose Development/Moose/Functional/PseudoATC.lua @@ -26,9 +26,9 @@ -- -- === -- --- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)** +-- ### Author: **funkyfranky** -- --- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536) +-- ### Contributions: FlightControl, Applevangelist -- -- ==== -- @module Functional.PseudoATC @@ -44,7 +44,7 @@ -- @field #number mrefresh Interval in seconds after which the F10 menu is refreshed. E.g. by the closest airports. Default is 120 sec. -- @field #number talt Interval in seconds between reporting altitude until touchdown. Default 3 sec. -- @field #boolean chatty Display some messages on events like take-off and touchdown. --- @field #boolean eventsmoose If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. +-- @field #boolean eventsmoose [Deprecated] If true, events are handled by MOOSE. If false, events are handled directly by DCS eventhandler. -- @field #boolean reportplayername If true, use playername not callsign on callouts -- @extends Core.Base#BASE @@ -100,13 +100,14 @@ PSEUDOATC.id="PseudoATC | " --- PSEUDOATC version. -- @field #number version -PSEUDOATC.version="0.9.5" +PSEUDOATC.version="0.10.5" ----------------------------------------------------------------------------------------------------------------------------------------- -- TODO list -- DONE: Add takeoff event. -- DONE: Add user functions. +-- DONE: Refactor to use Moose event handling only ----------------------------------------------------------------------------------------------------------------------------------------- @@ -131,23 +132,14 @@ function PSEUDOATC:Start() self:F() -- Debug info - self:E(PSEUDOATC.id.."Starting PseudoATC") + self:I(PSEUDOATC.id.."Starting PseudoATC") -- Handle events. - if self.eventsmoose then - self:T(PSEUDOATC.id.."Events are handled by MOOSE.") - self:HandleEvent(EVENTS.Birth, self._OnBirth) - self:HandleEvent(EVENTS.Land, self._PlayerLanded) - self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeOff) - self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft) - self:HandleEvent(EVENTS.Crash, self._PlayerLeft) - --self:HandleEvent(EVENTS.Ejection, self._PlayerLeft) - --self:HandleEvent(EVENTS.PilotDead, self._PlayerLeft) - else - self:T(PSEUDOATC.id.."Events are handled by DCS.") - -- Events are handled directly by DCS. - world.addEventHandler(self) - end + self:HandleEvent(EVENTS.Birth, self._OnBirth) + self:HandleEvent(EVENTS.Land, self._PlayerLanded) + self:HandleEvent(EVENTS.Takeoff, self._PlayerTakeOff) + self:HandleEvent(EVENTS.PlayerLeaveUnit, self._PlayerLeft) + self:HandleEvent(EVENTS.Crash, self._PlayerLeft) end @@ -199,7 +191,7 @@ function PSEUDOATC:SetMenuRefresh(interval) self.mrefresh=interval or 120 end ---- Enable/disable event handling by MOOSE or DCS. +--- [Deprecated] Enable/disable event handling by MOOSE or DCS. -- @param #PSEUDOATC self -- @param #boolean switch If true, events are handled by MOOSE (default). If false, events are handled directly by DCS. function PSEUDOATC:SetEventsMoose(switch) @@ -216,84 +208,6 @@ end ----------------------------------------------------------------------------------------------------------------------------------------- -- Event Handling ---- Event handler for suppressed groups. ---@param #PSEUDOATC self ---@param #table Event Event data table. Holds event.id, event.initiator and event.target etc. -function PSEUDOATC:onEvent(Event) - if Event == nil or Event.initiator == nil or Unit.getByName(Event.initiator:getName()) == nil then - return true - end - - local DCSiniunit = Event.initiator - local DCSplace = Event.place - local DCSsubplace = Event.subplace - - local EventData={} - local _playerunit=nil - local _playername=nil - - if Event.initiator then - EventData.IniUnitName = Event.initiator:getName() - EventData.IniDCSGroup = Event.initiator:getGroup() - EventData.IniGroupName = Event.initiator:getGroup():getName() - -- Get player unit and name. This returns nil,nil if the event was not fired by a player unit. And these are the only events we are interested in. - _playerunit, _playername = self:_GetPlayerUnitAndName(EventData.IniUnitName) - end - - if Event.place then - EventData.Place=Event.place - EventData.PlaceName=Event.place:getName() - end - if Event.subplace then - EventData.SubPlace=Event.subplace - EventData.SubPlaceName=Event.subplace:getName() - end - - -- Event info. - self:T3(PSEUDOATC.id..string.format("EVENT: Event in onEvent with ID = %s", tostring(Event.id))) - self:T3(PSEUDOATC.id..string.format("EVENT: Ini unit = %s" , tostring(EventData.IniUnitName))) - self:T3(PSEUDOATC.id..string.format("EVENT: Ini group = %s" , tostring(EventData.IniGroupName))) - self:T3(PSEUDOATC.id..string.format("EVENT: Ini player = %s" , tostring(_playername))) - self:T3(PSEUDOATC.id..string.format("EVENT: Place = %s" , tostring(EventData.PlaceName))) - self:T3(PSEUDOATC.id..string.format("EVENT: SubPlace = %s" , tostring(EventData.SubPlaceName))) - - -- Event birth. - if Event.id == world.event.S_EVENT_BIRTH and _playername then - self:_OnBirth(EventData) - end - - -- Event takeoff. - if Event.id == world.event.S_EVENT_TAKEOFF and _playername and EventData.Place then - self:_PlayerTakeOff(EventData) - end - - -- Event land. - if Event.id == world.event.S_EVENT_LAND and _playername and EventData.Place then - self:_PlayerLanded(EventData) - end - - -- Event player left unit - if Event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT and _playername then - self:_PlayerLeft(EventData) - end - - -- Event crash ==> player left unit - if Event.id == world.event.S_EVENT_CRASH and _playername then - self:_PlayerLeft(EventData) - end - ---[[ - -- Event eject ==> player left unit - if Event.id == world.event.S_EVENT_EJECTION and _playername then - self:_PlayerLeft(EventData) - end - - -- Event pilot dead ==> player left unit - if Event.id == world.event.S_EVENT_PILOT_DEAD and _playername then - self:_PlayerLeft(EventData) - end -]] -end --- Function called my MOOSE event handler when a player enters a unit. -- @param #PSEUDOATC self @@ -303,7 +217,9 @@ function PSEUDOATC:_OnBirth(EventData) -- Get unit and player. local _unitName=EventData.IniUnitName - local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + --local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + local _unit = EventData.IniUnit + local _playername = EventData.IniPlayerName -- Check if a player entered. if _unit and _playername then @@ -320,7 +236,10 @@ function PSEUDOATC:_PlayerLeft(EventData) -- Get unit and player. local _unitName=EventData.IniUnitName - local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + --local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + + local _unit = EventData.IniUnit + local _playername = EventData.IniPlayerName -- Check if a player left. if _unit and _playername then @@ -335,18 +254,16 @@ function PSEUDOATC:_PlayerLanded(EventData) self:F({EventData=EventData}) -- Get unit, player and place. - local _unitName=EventData.IniUnitName - local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) + local _unitName=EventData.IniUnitName + local _unit = EventData.IniUnit + local _playername = EventData.IniPlayerName + --local _unit, _playername=self:_GetPlayerUnitAndName(_unitName) local _base=nil local _baseName=nil if EventData.place then _base=EventData.place _baseName=EventData.place:getName() end --- if EventData.subplace then --- local _subPlace=EventData.subplace --- local _subPlaceName=EventData.subplace:getName() --- end -- Call landed function. if _unit and _playername and _base then @@ -361,8 +278,10 @@ function PSEUDOATC:_PlayerTakeOff(EventData) self:F({EventData=EventData}) -- Get unit, player and place. - local _unitName=EventData.IniUnitName - local _unit,_playername=self:_GetPlayerUnitAndName(_unitName) + local _unitName=EventData.IniUnitName + local _unit = EventData.IniUnit + local _playername = EventData.IniPlayerName + --local _unit,_playername=self:_GetPlayerUnitAndName(_unitName) local _base=nil local _baseName=nil if EventData.place then @@ -450,9 +369,6 @@ function PSEUDOATC:PlayerLanded(unit, place) local group=unit:GetGroup() local GID=group:GetID() local UID=unit:GetDCSObject():getID() - --local PlayerName=self.group[GID].player[UID].playername - --local UnitName=self.group[GID].player[UID].unitname - --local GroupName=self.group[GID].player[UID].groupname local PlayerName = unit:GetPlayerName() or "Ghost" local UnitName = unit:GetName() or "Ghostplane" local GroupName = group:GetName() or "Ghostgroup" @@ -483,12 +399,6 @@ function PSEUDOATC:PlayerTakeOff(unit, place) -- Gather some information. local group=unit:GetGroup() - --local GID=group:GetID() - --local UID=unit:GetDCSObject():getID() - --local PlayerName=self.group[GID].player[UID].playername - --local CallSign=self.group[GID].player[UID].callsign - --local UnitName=self.group[GID].player[UID].unitname - --local GroupName=self.group[GID].player[UID].groupname local PlayerName = unit:GetPlayerName() or "Ghost" local UnitName = unit:GetName() or "Ghostplane" local GroupName = group:GetName() or "Ghostgroup" @@ -926,7 +836,7 @@ function PSEUDOATC:AltitudeTimeStart(GID, UID) self:T(PSEUDOATC.id..string.format("Starting altitude report timer for player ID %d.", UID)) -- Start timer. Altitude is reported every ~3 seconds. - self.group[GID].player[UID].altimer, self.group[GID].player[UID].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, GID, UID, 0.1, true}, 1, 3) + self.group[GID].player[UID].altimer, self.group[GID].player[UID].altimerid=SCHEDULER:New(nil, self.ReportHeight, {self, GID, UID, 1, true}, 1, 3) end --- Stop/destroy DCS scheduler function for reporting altitude. diff --git a/Moose Development/Moose/Ops/Airboss.lua b/Moose Development/Moose/Ops/Airboss.lua index 9f6a38038..6a0a032d5 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -5826,7 +5826,7 @@ function AIRBOSS:_ScanCarrierZone() if knownflight then -- Check if flight is AI and if we want to handle it at all. - if knownflight.ai and knownflight.flag == -100 and self.handleai and false then --Disabled AI handling because of incorrect OPSGROUP reference! + if knownflight.ai and knownflight.flag == -100 and self.handleai and false then --Disabled AI handling because of incorrect OPSGROUP reference! local putintomarshal = false @@ -8102,7 +8102,7 @@ end -- @param Core.Event#EVENTDATA EventData function AIRBOSS:OnEventBirth( EventData ) self:F3( { eventbirth = EventData } ) - + -- Nil checks. if EventData == nil then self:E( self.lid .. "ERROR: EventData=nil in event BIRTH!" ) @@ -8114,7 +8114,9 @@ function AIRBOSS:OnEventBirth( EventData ) self:E( EventData ) return end - + + if EventData.IniObjectCategory ~= Object.Category.UNIT then return end + local _unitName = EventData.IniUnitName local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) @@ -9792,23 +9794,23 @@ function AIRBOSS:_Groove( playerData ) end end - - -- Long V/STOL groove time Wave Off over 75 seconds to IC - TOPGUN level Only. --pene testing (WIP)--- Need to think more about this. - + + -- Long V/STOL groove time Wave Off over 75 seconds to IC - TOPGUN level Only. --pene testing (WIP)--- Need to think more about this. + --if rho>=RAR and rho<=RIC and not playerData.waveoff and playerData.difficulty==AIRBOSS.Difficulty.HARD and playerData.actype== AIRBOSS.AircraftCarrier.AV8B then -- Get groove time --local vSlow=groovedata.time -- If too slow wave off. --if vSlow >75 then - + -- LSO Wave off! --self:RadioTransmission(self.LSORadio, self.LSOCall.WAVEOFF, nil, nil, nil, true) --playerData.Tlso=timer.getTime() - + -- Player was waved Off --playerData.waveoff=true --return - --end + --end --end -- Groovedata step. @@ -10162,7 +10164,7 @@ function AIRBOSS:_GetSternCoord() elseif case==2 or case==1 then -- V/Stol: Translate 8 meters port. self.sterncoord:Translate(self.carrierparam.sterndist, hdg, true, true):Translate(8, FB-90, true, true) - end + end elseif self.carriertype==AIRBOSS.CarrierType.STENNIS then -- Stennis: translate 7 meters starboard wrt Final bearing. self.sterncoord:Translate( self.carrierparam.sterndist, hdg, true, true ):Translate( 7, FB + 90, true, true ) @@ -11302,7 +11304,7 @@ function AIRBOSS:_GetOptLandingCoordinate() self.landingcoord:SetAltitude(UTILS.FeetToMeters(120)) end - + else -- Ideally we want to land between 2nd and 3rd wire. From 9414096de700823e905559ae1e8816cb75f3f8cb Mon Sep 17 00:00:00 2001 From: Thomas <72444570+Applevangelist@users.noreply.github.com> Date: Wed, 19 Apr 2023 09:51:53 +0200 Subject: [PATCH 2/5] Added active ZONE filtering (#1935) for groups, units, clients entering/leaving zones to be used with `FilterStart()` --- Moose Development/Moose/Core/Set.lua | 170 ++++++++++++++++++++++++++- 1 file changed, 169 insertions(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 4731ab3d5..fa64aae62 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -904,6 +904,8 @@ end do -- SET_GROUP --- @type SET_GROUP #SET_GROUP + -- @field Core.Timer#TIMER ZoneTimer + -- @field #number ZoneTimerInterval -- @extends Core.Set#SET_BASE --- Mission designers can use the @{Core.Set#SET_GROUP} class to build sets of groups belonging to certain: @@ -1343,6 +1345,25 @@ do -- SET_GROUP end return self end + + --- [Internal] Private function for use of continous zone filter + -- @param #SET_GROUP self + -- @return #SET_GROUP self + function SET_GROUP:_ContinousZoneFilter() + + local Database = _DATABASE.GROUPS + + for ObjectName, Object in pairs( Database ) do + if self:IsIncludeObject( Object ) and self:IsNotInSet(Object) then + self:Add( ObjectName, Object ) + elseif (not self:IsIncludeObject( Object )) and self:IsInSet(Object) then + self:Remove(ObjectName) + end + end + + return self + + end --- Builds a set of groups that are only active. -- Only the groups that are active will be included within the set. @@ -1381,10 +1402,46 @@ do -- SET_GROUP self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash ) + if self.Filter.Zones then + self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self) + local timing = self.ZoneTimerInterval or 30 + self.ZoneTimer:Start(timing,timing) + end end return self end + + --- Set filter timer interval for FilterZones if using active filtering with FilterStart(). + -- @param #SET_GROUP self + -- @param #number Seconds Seconds between check intervals, defaults to 30. **Caution** - do not be too agressive with timing! Groups are usually not moving fast enough + -- to warrant a check of below 10 seconds. + -- @return #SET_GROUP self + function SET_GROUP:FilterZoneTimer(Seconds) + self.ZoneTimerInterval = Seconds or 30 + return self + end + + --- Stops the filtering. + -- @param #SET_GROUP self + -- @return #SET_GROUP self + function SET_GROUP:FilterStop() + + if _DATABASE then + + self:UnHandleEvent(EVENTS.Birth) + self:UnHandleEvent(EVENTS.Dead) + self:UnHandleEvent(EVENTS.Crash) + self:UnHandleEvent(EVENTS.RemoveUnit) + + if self.Filter.Zones and self.ZoneTimer and self.ZoneTimer:IsRunning() then + self.ZoneTimer:Stop() + end + end + + return self + end + --- Handles the OnDead or OnCrash event for alive groups set. -- Note: The GROUP object in the SET_GROUP collection will only be removed if the last unit is destroyed of the GROUP. @@ -1888,7 +1945,7 @@ do -- SET_GROUP if self.Filter.Zones then local MGroupZone = false for ZoneName, Zone in pairs( self.Filter.Zones ) do - self:T3( "Zone:", ZoneName ) + self:I( "Zone:", ZoneName ) if MGroup:IsInZone(Zone) then MGroupZone = true end @@ -1956,6 +2013,8 @@ end do -- SET_UNIT --- @type SET_UNIT + -- @field Core.Timer#TIMER ZoneTimer + -- @field #number ZoneTimerInterval -- @extends Core.Set#SET_BASE --- Mission designers can use the SET_UNIT class to build sets of units belonging to certain: @@ -2347,7 +2406,56 @@ do -- SET_UNIT return CountU end + + --- [Internal] Private function for use of continous zone filter + -- @param #SET_UNIT self + -- @return #SET_UNIT self + function SET_UNIT:_ContinousZoneFilter() + + local Database = _DATABASE.UNITS + + for ObjectName, Object in pairs( Database ) do + if self:IsIncludeObject( Object ) and self:IsNotInSet(Object) then + self:Add( ObjectName, Object ) + elseif (not self:IsIncludeObject( Object )) and self:IsInSet(Object) then + self:Remove(ObjectName) + end + end + + return self + + end + + --- Set filter timer interval for FilterZones if using active filtering with FilterStart(). + -- @param #SET_UNIT self + -- @param #number Seconds Seconds between check intervals, defaults to 30. **Caution** - do not be too agressive with timing! Groups are usually not moving fast enough + -- to warrant a check of below 10 seconds. + -- @return #SET_UNIT self + function SET_UNIT:FilterZoneTimer(Seconds) + self.ZoneTimerInterval = Seconds or 30 + return self + end + + --- Stops the filtering. + -- @param #SET_UNIT self + -- @return #SET_UNIT self + function SET_UNIT:FilterStop() + if _DATABASE then + + self:UnHandleEvent(EVENTS.Birth) + self:UnHandleEvent(EVENTS.Dead) + self:UnHandleEvent(EVENTS.Crash) + self:UnHandleEvent(EVENTS.RemoveUnit) + + if self.Filter.Zones and self.ZoneTimer and self.ZoneTimer:IsRunning() then + self.ZoneTimer:Stop() + end + end + + return self + end + --- Starts the filtering. -- @param #SET_UNIT self -- @return #SET_UNIT self @@ -2359,6 +2467,11 @@ do -- SET_UNIT self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.RemoveUnit, self._EventOnDeadOrCrash ) + if self.Filter.Zones then + self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self) + local timing = self.ZoneTimerInterval or 30 + self.ZoneTimer:Start(timing,timing) + end end return self @@ -3834,6 +3947,8 @@ end do -- SET_CLIENT --- @type SET_CLIENT + -- @field Core.Timer#TIMER ZoneTimer + -- @field #number ZoneTimerInterval -- @extends Core.Set#SET_BASE --- Mission designers can use the @{Core.Set#SET_CLIENT} class to build sets of units belonging to certain: @@ -4141,6 +4256,54 @@ do -- SET_CLIENT return self end + --- [Internal] Private function for use of continous zone filter + -- @param #SET_CLIENT self + -- @return #SET_CLIENT self + function SET_CLIENT:_ContinousZoneFilter() + + local Database = _DATABASE.CLIENTS + + for ObjectName, Object in pairs( Database ) do + if self:IsIncludeObject( Object ) and self:IsNotInSet(Object) then + self:Add( ObjectName, Object ) + elseif (not self:IsIncludeObject( Object )) and self:IsInSet(Object) then + self:Remove(ObjectName) + end + end + + return self + + end + + --- Set filter timer interval for FilterZones if using active filtering with FilterStart(). + -- @param #SET_CLIENT self + -- @param #number Seconds Seconds between check intervals, defaults to 30. **Caution** - do not be too agressive with timing! Groups are usually not moving fast enough + -- to warrant a check of below 10 seconds. + -- @return #SET_CLIENT self + function SET_CLIENT:FilterZoneTimer(Seconds) + self.ZoneTimerInterval = Seconds or 30 + return self + end + + --- Stops the filtering. + -- @param #SET_CLIENT self + -- @return #SET_CLIENT self + function SET_CLIENT:FilterStop() + + if _DATABASE then + + self:UnHandleEvent(EVENTS.Birth) + self:UnHandleEvent(EVENTS.Dead) + self:UnHandleEvent(EVENTS.Crash) + + if self.Filter.Zones and self.ZoneTimer and self.ZoneTimer:IsRunning() then + self.ZoneTimer:Stop() + end + end + + return self + end + --- Starts the filtering. -- @param #SET_CLIENT self -- @return #SET_CLIENT self @@ -4151,6 +4314,11 @@ do -- SET_CLIENT self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) + if self.Filter.Zones then + self.ZoneTimer = TIMER:New(self._ContinousZoneFilter,self) + local timing = self.ZoneTimerInterval or 30 + self.ZoneTimer:Start(timing,timing) + end end return self From 90c74bd82c45812cb1c8442bf47856d60b36b91d Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 20 Apr 2023 08:06:43 +0200 Subject: [PATCH 3/5] #SET - Minus one log entry --- Moose Development/Moose/Core/Set.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index fa64aae62..a48e917f6 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -1945,7 +1945,7 @@ do -- SET_GROUP if self.Filter.Zones then local MGroupZone = false for ZoneName, Zone in pairs( self.Filter.Zones ) do - self:I( "Zone:", ZoneName ) + --self:I( "Zone:", ZoneName ) if MGroup:IsInZone(Zone) then MGroupZone = true end From 240307ef940e67744fbf0980e9c34341b66bba5f Mon Sep 17 00:00:00 2001 From: Applevangelist Date: Thu, 20 Apr 2023 08:23:03 +0200 Subject: [PATCH 4/5] #CTLD * Docu changes --- Moose Development/Moose/Ops/CTLD.lua | 589 +++++++++++++-------------- 1 file changed, 294 insertions(+), 295 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 394a22138..1dca93f05 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -24,6 +24,299 @@ -- Last Update Apr 2023 +do + +------------------------------------------------------ +--- **CTLD_CARGO** class, extends Core.Base#BASE +-- @type CTLD_CARGO +-- @field #string ClassName Class name. +-- @field #number ID ID of this cargo. +-- @field #string Name Name for menu. +-- @field #table Templates Table of #POSITIONABLE objects. +-- @field #string CargoType Enumerator of Type. +-- @field #boolean HasBeenMoved Flag for moving. +-- @field #boolean LoadDirectly Flag for direct loading. +-- @field #number CratesNeeded Crates needed to build. +-- @field Wrapper.Positionable#POSITIONABLE Positionable Representation of cargo in the mission. +-- @field #boolean HasBeenDropped True if dropped from heli. +-- @field #number PerCrateMass Mass in kg. +-- @field #number Stock Number of builds available, -1 for unlimited. +-- @field #string Subcategory Sub-category name. +-- @extends Core.Base#BASE + +--- +-- @field #CTLD_CARGO CTLD_CARGO +CTLD_CARGO = { + ClassName = "CTLD_CARGO", + ID = 0, + Name = "none", + Templates = {}, + CargoType = "none", + HasBeenMoved = false, + LoadDirectly = false, + CratesNeeded = 0, + Positionable = nil, + HasBeenDropped = false, + PerCrateMass = 0, + Stock = nil, + Mark = nil, + } + + --- Define cargo types. + -- @type CTLD_CARGO.Enum + -- @field #string VEHICLE + -- @field #string TROOPS + -- @field #string FOB + -- @field #string CRATE + -- @field #string REPAIR + -- @field #string ENGINEERS + -- @field #string STATIC + CTLD_CARGO.Enum = { + VEHICLE = "Vehicle", -- #string vehicles + TROOPS = "Troops", -- #string troops + FOB = "FOB", -- #string FOB + CRATE = "Crate", -- #string crate + REPAIR = "Repair", -- #string repair + ENGINEERS = "Engineers", -- #string engineers + STATIC = "Static", -- #string statics + } + + --- Function to create new CTLD_CARGO object. + -- @param #CTLD_CARGO self + -- @param #number ID ID of this #CTLD_CARGO + -- @param #string Name Name for menu. + -- @param #table Templates Table of #POSITIONABLE objects. + -- @param #CTLD_CARGO.Enum Sorte Enumerator of Type. + -- @param #boolean HasBeenMoved Flag for moving. + -- @param #boolean LoadDirectly Flag for direct loading. + -- @param #number CratesNeeded Crates needed to build. + -- @param Wrapper.Positionable#POSITIONABLE Positionable Representation of cargo in the mission. + -- @param #boolean Dropped Cargo/Troops have been unloaded from a chopper. + -- @param #number PerCrateMass Mass in kg + -- @param #number Stock Number of builds available, nil for unlimited + -- @param #string Subcategory Name of subcategory, handy if using > 10 types to load. + -- @return #CTLD_CARGO self + function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory) + -- Inherit everything from BASE class. + local self=BASE:Inherit(self, BASE:New()) -- #CTLD_CARGO + self:T({ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped}) + self.ID = ID or math.random(100000,1000000) + self.Name = Name or "none" -- #string + self.Templates = Templates or {} -- #table + self.CargoType = Sorte or "type" -- #CTLD_CARGO.Enum + self.HasBeenMoved = HasBeenMoved or false -- #boolean + self.LoadDirectly = LoadDirectly or false -- #boolean + self.CratesNeeded = CratesNeeded or 0 -- #number + self.Positionable = Positionable or nil -- Wrapper.Positionable#POSITIONABLE + self.HasBeenDropped = Dropped or false --#boolean + self.PerCrateMass = PerCrateMass or 0 -- #number + self.Stock = Stock or nil --#number + self.Mark = nil + self.Subcategory = Subcategory or "Other" + return self + end + + --- Query ID. + -- @param #CTLD_CARGO self + -- @return #number ID + function CTLD_CARGO:GetID() + return self.ID + end + + --- Query Subcategory + -- @param #CTLD_CARGO self + -- @return #string SubCategory + function CTLD_CARGO:GetSubCat() + return self.Subcategory + end + + --- Query Mass. + -- @param #CTLD_CARGO self + -- @return #number Mass in kg + function CTLD_CARGO:GetMass() + return self.PerCrateMass + end + + --- Query Name. + -- @param #CTLD_CARGO self + -- @return #string Name + function CTLD_CARGO:GetName() + return self.Name + end + + --- Query Templates. + -- @param #CTLD_CARGO self + -- @return #table Templates + function CTLD_CARGO:GetTemplates() + return self.Templates + end + + --- Query has moved. + -- @param #CTLD_CARGO self + -- @return #boolean Has moved + function CTLD_CARGO:HasMoved() + return self.HasBeenMoved + end + + --- Query was dropped. + -- @param #CTLD_CARGO self + -- @return #boolean Has been dropped. + function CTLD_CARGO:WasDropped() + return self.HasBeenDropped + end + + --- Query directly loadable. + -- @param #CTLD_CARGO self + -- @return #boolean loadable + function CTLD_CARGO:CanLoadDirectly() + return self.LoadDirectly + end + + --- Query number of crates or troopsize. + -- @param #CTLD_CARGO self + -- @return #number Crates or size of troops. + function CTLD_CARGO:GetCratesNeeded() + return self.CratesNeeded + end + + --- Query type. + -- @param #CTLD_CARGO self + -- @return #CTLD_CARGO.Enum Type + function CTLD_CARGO:GetType() + return self.CargoType + end + + --- Query type. + -- @param #CTLD_CARGO self + -- @return Wrapper.Positionable#POSITIONABLE Positionable + function CTLD_CARGO:GetPositionable() + return self.Positionable + end + + --- Set HasMoved. + -- @param #CTLD_CARGO self + -- @param #boolean moved + function CTLD_CARGO:SetHasMoved(moved) + self.HasBeenMoved = moved or false + end + + --- Query if cargo has been loaded. + -- @param #CTLD_CARGO self + -- @param #boolean loaded + function CTLD_CARGO:Isloaded() + if self.HasBeenMoved and not self.WasDropped() then + return true + else + return false + end + end + + --- Set WasDropped. + -- @param #CTLD_CARGO self + -- @param #boolean dropped + function CTLD_CARGO:SetWasDropped(dropped) + self.HasBeenDropped = dropped or false + end + + --- Get Stock. + -- @param #CTLD_CARGO self + -- @return #number Stock + function CTLD_CARGO:GetStock() + if self.Stock then + return self.Stock + else + return -1 + end + end + + --- Add Stock. + -- @param #CTLD_CARGO self + -- @param #number Number to add, none if nil. + -- @return #CTLD_CARGO self + function CTLD_CARGO:AddStock(Number) + if self.Stock then -- Stock nil? + local number = Number or 1 + self.Stock = self.Stock + number + end + return self + end + + --- Remove Stock. + -- @param #CTLD_CARGO self + -- @param #number Number to reduce, none if nil. + -- @return #CTLD_CARGO self + function CTLD_CARGO:RemoveStock(Number) + if self.Stock then -- Stock nil? + local number = Number or 1 + self.Stock = self.Stock - number + if self.Stock < 0 then self.Stock = 0 end + end + return self + end + + --- Set Stock. + -- @param #CTLD_CARGO self + -- @param #number Number to set, nil means unlimited. + -- @return #CTLD_CARGO self + function CTLD_CARGO:SetStock(Number) + self.Stock = Number + return self + end + + --- Query crate type for REPAIR + -- @param #CTLD_CARGO self + -- @param #boolean + function CTLD_CARGO:IsRepair() + if self.CargoType == "Repair" then + return true + else + return false + end + end + + --- Query crate type for STATIC + -- @param #CTLD_CARGO self + -- @return #boolean + function CTLD_CARGO:IsStatic() + if self.CargoType == "Static" then + return true + else + return false + end + end + + --- Add mark + -- @param #CTLD_CARGO self + -- @return #CTLD_CARGO self + function CTLD_CARGO:AddMark(Mark) + self.Mark = Mark + return self + end + + --- Get mark + -- @param #CTLD_CARGO self + -- @return #string Mark + function CTLD_CARGO:GetMark(Mark) + return self.Mark + end + + --- Wipe mark + -- @param #CTLD_CARGO self + -- @return #CTLD_CARGO self + function CTLD_CARGO:WipeMark() + self.Mark = nil + return self + end + + --- Get overall mass of a cargo object, i.e. crates needed x mass per crate + -- @param #CTLD_CARGO self + -- @return #number mass + function CTLD_CARGO:GetNetMass() + return self.CratesNeeded * self.PerCrateMass + end + +end + do ------------------------------------------------------ @@ -40,7 +333,7 @@ do -- @extends Core.Base#BASE --- --- @field #CTLD_ENGINEERING +-- @field #CTLD_ENGINEERING CTLD_ENGINEERING CTLD_ENGINEERING = { ClassName = "CTLD_ENGINEERING", lid = "", @@ -287,300 +580,6 @@ CTLD_ENGINEERING = { end - -do - ------------------------------------------------------- ---- **CTLD_CARGO** class, extends Core.Base#BASE --- @type CTLD_CARGO --- @field #string ClassName Class name. --- @field #number ID ID of this cargo. --- @field #string Name Name for menu. --- @field #table Templates Table of #POSITIONABLE objects. --- @field #string CargoType Enumerator of Type. --- @field #boolean HasBeenMoved Flag for moving. --- @field #boolean LoadDirectly Flag for direct loading. --- @field #number CratesNeeded Crates needed to build. --- @field Wrapper.Positionable#POSITIONABLE Positionable Representation of cargo in the mission. --- @field #boolean HasBeenDropped True if dropped from heli. --- @field #number PerCrateMass Mass in kg. --- @field #number Stock Number of builds available, -1 for unlimited. --- @field #string Subcategory Sub-category name. --- @extends Core.Base#BASE - ---- --- @field #CTLD_CARGO CTLD_CARGO -CTLD_CARGO = { - ClassName = "CTLD_CARGO", - ID = 0, - Name = "none", - Templates = {}, - CargoType = "none", - HasBeenMoved = false, - LoadDirectly = false, - CratesNeeded = 0, - Positionable = nil, - HasBeenDropped = false, - PerCrateMass = 0, - Stock = nil, - Mark = nil, - } - - --- Define cargo types. - -- @type CTLD_CARGO.Enum - -- @field #string VEHICLE - -- @field #string TROOPS - -- @field #string FOB - -- @field #string CRATE - -- @field #string REPAIR - -- @field #string ENGINEERS - -- @field #string STATIC - CTLD_CARGO.Enum = { - VEHICLE = "Vehicle", -- #string vehicles - TROOPS = "Troops", -- #string troops - FOB = "FOB", -- #string FOB - CRATE = "Crate", -- #string crate - REPAIR = "Repair", -- #string repair - ENGINEERS = "Engineers", -- #string engineers - STATIC = "Static", -- #string statics - } - - --- Function to create new CTLD_CARGO object. - -- @param #CTLD_CARGO self - -- @param #number ID ID of this #CTLD_CARGO - -- @param #string Name Name for menu. - -- @param #table Templates Table of #POSITIONABLE objects. - -- @param #CTLD_CARGO.Enum Sorte Enumerator of Type. - -- @param #boolean HasBeenMoved Flag for moving. - -- @param #boolean LoadDirectly Flag for direct loading. - -- @param #number CratesNeeded Crates needed to build. - -- @param Wrapper.Positionable#POSITIONABLE Positionable Representation of cargo in the mission. - -- @param #boolean Dropped Cargo/Troops have been unloaded from a chopper. - -- @param #number PerCrateMass Mass in kg - -- @param #number Stock Number of builds available, nil for unlimited - -- @param #string Subcategory Name of subcategory, handy if using > 10 types to load. - -- @return #CTLD_CARGO self - function CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory) - -- Inherit everything from BASE class. - local self=BASE:Inherit(self, BASE:New()) -- #CTLD - self:T({ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped}) - self.ID = ID or math.random(100000,1000000) - self.Name = Name or "none" -- #string - self.Templates = Templates or {} -- #table - self.CargoType = Sorte or "type" -- #CTLD_CARGO.Enum - self.HasBeenMoved = HasBeenMoved or false -- #boolean - self.LoadDirectly = LoadDirectly or false -- #boolean - self.CratesNeeded = CratesNeeded or 0 -- #number - self.Positionable = Positionable or nil -- Wrapper.Positionable#POSITIONABLE - self.HasBeenDropped = Dropped or false --#boolean - self.PerCrateMass = PerCrateMass or 0 -- #number - self.Stock = Stock or nil --#number - self.Mark = nil - self.Subcategory = Subcategory or "Other" - return self - end - - --- Query ID. - -- @param #CTLD_CARGO self - -- @return #number ID - function CTLD_CARGO:GetID() - return self.ID - end - - --- Query Subcategory - -- @param #CTLD_CARGO self - -- @return #string SubCategory - function CTLD_CARGO:GetSubCat() - return self.Subcategory - end - - --- Query Mass. - -- @param #CTLD_CARGO self - -- @return #number Mass in kg - function CTLD_CARGO:GetMass() - return self.PerCrateMass - end - - --- Query Name. - -- @param #CTLD_CARGO self - -- @return #string Name - function CTLD_CARGO:GetName() - return self.Name - end - - --- Query Templates. - -- @param #CTLD_CARGO self - -- @return #table Templates - function CTLD_CARGO:GetTemplates() - return self.Templates - end - - --- Query has moved. - -- @param #CTLD_CARGO self - -- @return #boolean Has moved - function CTLD_CARGO:HasMoved() - return self.HasBeenMoved - end - - --- Query was dropped. - -- @param #CTLD_CARGO self - -- @return #boolean Has been dropped. - function CTLD_CARGO:WasDropped() - return self.HasBeenDropped - end - - --- Query directly loadable. - -- @param #CTLD_CARGO self - -- @return #boolean loadable - function CTLD_CARGO:CanLoadDirectly() - return self.LoadDirectly - end - - --- Query number of crates or troopsize. - -- @param #CTLD_CARGO self - -- @return #number Crates or size of troops. - function CTLD_CARGO:GetCratesNeeded() - return self.CratesNeeded - end - - --- Query type. - -- @param #CTLD_CARGO self - -- @return #CTLD_CARGO.Enum Type - function CTLD_CARGO:GetType() - return self.CargoType - end - - --- Query type. - -- @param #CTLD_CARGO self - -- @return Wrapper.Positionable#POSITIONABLE Positionable - function CTLD_CARGO:GetPositionable() - return self.Positionable - end - - --- Set HasMoved. - -- @param #CTLD_CARGO self - -- @param #boolean moved - function CTLD_CARGO:SetHasMoved(moved) - self.HasBeenMoved = moved or false - end - - --- Query if cargo has been loaded. - -- @param #CTLD_CARGO self - -- @param #boolean loaded - function CTLD_CARGO:Isloaded() - if self.HasBeenMoved and not self.WasDropped() then - return true - else - return false - end - end - - --- Set WasDropped. - -- @param #CTLD_CARGO self - -- @param #boolean dropped - function CTLD_CARGO:SetWasDropped(dropped) - self.HasBeenDropped = dropped or false - end - - --- Get Stock. - -- @param #CTLD_CARGO self - -- @return #number Stock - function CTLD_CARGO:GetStock() - if self.Stock then - return self.Stock - else - return -1 - end - end - - --- Add Stock. - -- @param #CTLD_CARGO self - -- @param #number Number to add, none if nil. - -- @return #CTLD_CARGO self - function CTLD_CARGO:AddStock(Number) - if self.Stock then -- Stock nil? - local number = Number or 1 - self.Stock = self.Stock + number - end - return self - end - - --- Remove Stock. - -- @param #CTLD_CARGO self - -- @param #number Number to reduce, none if nil. - -- @return #CTLD_CARGO self - function CTLD_CARGO:RemoveStock(Number) - if self.Stock then -- Stock nil? - local number = Number or 1 - self.Stock = self.Stock - number - if self.Stock < 0 then self.Stock = 0 end - end - return self - end - - --- Set Stock. - -- @param #CTLD_CARGO self - -- @param #number Number to set, nil means unlimited. - -- @return #CTLD_CARGO self - function CTLD_CARGO:SetStock(Number) - self.Stock = Number - return self - end - - --- Query crate type for REPAIR - -- @param #CTLD_CARGO self - -- @param #boolean - function CTLD_CARGO:IsRepair() - if self.CargoType == "Repair" then - return true - else - return false - end - end - - --- Query crate type for STATIC - -- @param #CTLD_CARGO self - -- @return #boolean - function CTLD_CARGO:IsStatic() - if self.CargoType == "Static" then - return true - else - return false - end - end - - --- Add mark - -- @param #CTLD_CARGO self - -- @return #CTLD_CARGO self - function CTLD_CARGO:AddMark(Mark) - self.Mark = Mark - return self - end - - --- Get mark - -- @param #CTLD_CARGO self - -- @return #string Mark - function CTLD_CARGO:GetMark(Mark) - return self.Mark - end - - --- Wipe mark - -- @param #CTLD_CARGO self - -- @return #CTLD_CARGO self - function CTLD_CARGO:WipeMark() - self.Mark = nil - return self - end - - --- Get overall mass of a cargo object, i.e. crates needed x mass per crate - -- @param #CTLD_CARGO self - -- @return #number mass - function CTLD_CARGO:GetNetMass() - return self.CratesNeeded * self.PerCrateMass - end - -end - do ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -- TODO CTLD From 1507cc0b42e40edeaf8eabced7d000ac478aa612 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 22 Apr 2023 14:02:18 +0200 Subject: [PATCH 5/5] Remove Junk **ZONE** - Added `ZONE_RADIUS:RemoveJunk()` function - Added `ZONE_POLYGON_BASE:RemoveJunk()` function (not working) **POSITIONABLE** - Added `Explosion` --- Moose Development/Moose/Core/Zone.lua | 47 +++++++++++++++++++ .../Moose/Wrapper/Positionable.lua | 29 ++++++++++++ 2 files changed, 76 insertions(+) diff --git a/Moose Development/Moose/Core/Zone.lua b/Moose Development/Moose/Core/Zone.lua index 891e5fc7d..f38fe83c4 100644 --- a/Moose Development/Moose/Core/Zone.lua +++ b/Moose Development/Moose/Core/Zone.lua @@ -1001,6 +1001,24 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories ) end +--- Remove junk inside the zone using the `world.removeJunk` function. +-- @param #ZONE_RADIUS self +-- @return #number Number of deleted objects. +function ZONE_RADIUS:RemoveJunk() + + local radius=self.Radius + local vec3=self:GetVec3() + + local volS = { + id = world.VolumeType.SPHERE, + params = {point = vec3, radius = radius} + } + + local n=world.removeJunk(volS) + + return n +end + --- Count the number of different coalitions inside the zone. -- @param #ZONE_RADIUS self -- @return #table Table of DCS units and DCS statics inside the zone. @@ -2141,6 +2159,35 @@ function ZONE_POLYGON_BASE:GetZoneQuad(ZoneName, DoNotRegisterZone) return zone end +--- Remove junk inside the zone. Due to DCS limitations, this works only for rectangular zones. So we get the smallest rectangular zone encompassing all points points of the polygon zone. +-- @param #ZONE_POLYGON_BASE self +-- @param #number Height Height of the box in meters. Default 1000. +-- @return #number Number of removed objects. +function ZONE_POLYGON_BASE:RemoveJunk(Height) + + Height=Height or 1000 + + local vec2SW, vec2NE=self:GetBoundingVec2() + + local vec3SW={x=vec2SW.x, y=-Height, z=vec2SW.y} --DCS#Vec3 + local vec3NE={x=vec2NE.x, y= Height, z=vec2NE.y} --DCS#Vec3 + + --local coord1=COORDINATE:NewFromVec3(vec3SW):MarkToAll("SW") + --local coord1=COORDINATE:NewFromVec3(vec3NE):MarkToAll("NE") + + local volume = { + id = world.VolumeType.BOX, + params = { + min=vec3SW, + max=vec3SW + } + } + + local n=world.removeJunk(volume) + + return n +end + --- Smokes the zone boundaries in a color. -- @param #ZONE_POLYGON_BASE self -- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color. diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua index 21dd5f633..5016aac7f 100644 --- a/Moose Development/Moose/Wrapper/Positionable.lua +++ b/Moose Development/Moose/Wrapper/Positionable.lua @@ -394,6 +394,35 @@ function POSITIONABLE:GetCoordinate() return nil end + +--- Triggers an explosion at the coordinates of the positionable. +-- @param #POSITIONABLE self +-- @param #number power Power of the explosion in kg TNT. Default 100 kg TNT. +-- @param #number delay (Optional) Delay of explosion in seconds. +-- @return #POSITIONABLE self +function POSITIONABLE:Explode(power, delay) + + -- Default. + power=power or 100 + + -- Check if delay or not. + if delay and delay>0 then + -- Delayed call. + self:ScheduleOnce(delay, POSITIONABLE.Explode, self, power, 0) + else + + local coord=self:GetCoord() + + if coord then + -- Create an explotion at the coordinate of the positionable. + coord:Explosion(power) + end + + end + + return self +end + --- Returns a COORDINATE object, which is offset with respect to the orientation of the POSITIONABLE. -- @param #POSITIONABLE self -- @param #number x Offset in the direction "the nose" of the unit is pointing in meters. Default 0 m.