diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 4731ab3d5..a48e917f6 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 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/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 21b5caa61..99bb0ebae 100644 --- a/Moose Development/Moose/Ops/Airboss.lua +++ b/Moose Development/Moose/Ops/Airboss.lua @@ -2847,7 +2847,7 @@ function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW) --Check if V/STOL Carrier if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then - + -- allow a larger GSE for V/STOL operations --Pene Testing self.gle._max=_max or 0.7 self.gle.High=High or 1.4 @@ -2864,7 +2864,7 @@ function AIRBOSS:SetGlideslopeErrorThresholds(_max,_min, High, HIGH, Low, LOW) self.gle.Low=Low or -0.6 self.gle.LOW=LOW or -0.9 end - + return self end @@ -2884,7 +2884,7 @@ function AIRBOSS:SetLineupErrorThresholds(_max,_min, Left, LeftMed, LEFT, Right, --Check if V/STOL Carrier -- Pene testing if self.carriertype == AIRBOSS.CarrierType.INVINCIBLE or self.carriertype == AIRBOSS.CarrierType.HERMES or self.carriertype == AIRBOSS.CarrierType.TARAWA or self.carriertype == AIRBOSS.CarrierType.AMERICA or self.carriertype == AIRBOSS.CarrierType.JCARLOS or self.carriertype == AIRBOSS.CarrierType.CANBERRA then - + -- V/STOL Values -- allow a larger LUE for V/STOL operations self.lue._max=_max or 1.8 self.lue._min=_min or -1.8 @@ -2905,7 +2905,7 @@ function AIRBOSS:SetLineupErrorThresholds(_max,_min, Left, LeftMed, LEFT, Right, self.lue.RightMed=RightMed or 2.0 self.lue.RIGHT=RIGHT or 3.0 end - + return self end @@ -3268,7 +3268,7 @@ function AIRBOSS:SetExtraVoiceOversAI(status) self.xtVoiceOversAI=status return self end - + --- Do not handle AI aircraft. -- @param #AIRBOSS self -- @return #AIRBOSS self @@ -3383,9 +3383,9 @@ end -- @param #string Host Host. Default `"127.0.0.1"`. -- @return #AIRBOSS self function AIRBOSS:SetFunkManOn(Port, Host) - + self.funkmanSocket=SOCKET:New(Port, Host) - + return self end @@ -6364,7 +6364,7 @@ function AIRBOSS:_LandAI( flight ) -- Aircraft speed when flying the pattern. local Speed = UTILS.KnotsToKmph( 200 ) - if flight.actype == AIRBOSS.AircraftCarrier.HORNET + if flight.actype == AIRBOSS.AircraftCarrier.HORNET or flight.actype == AIRBOSS.AircraftCarrier.FA18C or flight.actype == AIRBOSS.AircraftCarrier.RHINOE or flight.actype == AIRBOSS.AircraftCarrier.RHINOF @@ -8115,6 +8115,8 @@ function AIRBOSS:OnEventBirth( EventData ) return end + if EventData.IniObjectCategory ~= Object.Category.UNIT then return end + local _unitName = EventData.IniUnitName local _unit, _playername = self:_GetPlayerUnitAndName( _unitName ) @@ -9192,9 +9194,9 @@ function AIRBOSS:_DirtyUp( playerData ) self:_PlayerHint( playerData ) -- Radio call "Say/Fly needles". Delayed by 10/15 seconds. - if playerData.actype == AIRBOSS.AircraftCarrier.HORNET - or playerData.actype == AIRBOSS.AircraftCarrier.F14A - or playerData.actype == AIRBOSS.AircraftCarrier.F14B + if playerData.actype == AIRBOSS.AircraftCarrier.HORNET + or playerData.actype == AIRBOSS.AircraftCarrier.F14A + or playerData.actype == AIRBOSS.AircraftCarrier.F14B or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER @@ -9791,24 +9793,24 @@ function AIRBOSS:_Groove( playerData ) return 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. - + 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. + --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 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. @@ -10006,7 +10008,7 @@ function AIRBOSS:_CheckWaveOff( glideslopeError, lineupError, AoA, playerData ) waveoff = true end - -- Too slow or too fast? Only for pros. + -- Too slow or too fast? Only for pros. if playerData.difficulty == AIRBOSS.Difficulty.HARD and playerData.actype ~= AIRBOSS.AircraftCarrier.AV8B then -- Get aircraft specific AoA values. Not for AV-8B due to transition to Stable Hover. @@ -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 ) @@ -10311,7 +10313,7 @@ function AIRBOSS:_Trapped( playerData ) -- Get current wire (estimate). This now based on the position where the player comes to a standstill which should reflect the trapped wire better. local dcorr = 100 - if playerData.actype == AIRBOSS.AircraftCarrier.HORNET + if playerData.actype == AIRBOSS.AircraftCarrier.HORNET or playerData.actype == AIRBOSS.AircraftCarrier.RHINOE or playerData.actype == AIRBOSS.AircraftCarrier.RHINOF or playerData.actype == AIRBOSS.AircraftCarrier.GROWLER then @@ -10836,7 +10838,7 @@ function AIRBOSS:_GetZoneAbeamLandingSpot() -- Coordinate array. Pene Testing extended Abeam landing spot V/STOL. local p={} - + -- Points. p[1] = S:Translate( 15, FB ):Translate( 15, FB + 90 ) -- Top-Right p[2] = S:Translate( -45, FB ):Translate( 15, FB + 90 ) -- Bottom-Right @@ -11284,7 +11286,7 @@ function AIRBOSS:_GetOptLandingCoordinate() -- set Case III V/STOL abeam landing spot over deck -- Pene Testing if self.carriertype==AIRBOSS.CarrierType.INVINCIBLE or self.carriertype==AIRBOSS.CarrierType.HERMES or self.carriertype==AIRBOSS.CarrierType.TARAWA or self.carriertype==AIRBOSS.CarrierType.AMERICA or self.carriertype==AIRBOSS.CarrierType.JCARLOS or self.carriertype==AIRBOSS.CarrierType.CANBERRA then - + if case==3 then -- Landing coordinate. @@ -11292,7 +11294,7 @@ function AIRBOSS:_GetOptLandingCoordinate() -- Altitude 120ft -- is this corect for Case III? self.landingcoord:SetAltitude(UTILS.FeetToMeters(120)) - + elseif case==2 or case==1 then -- Landing 100 ft abeam, 120 ft alt. @@ -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. @@ -11897,7 +11899,7 @@ function AIRBOSS:_LSOgrade( playerData ) local nS=count(G, '%(') local nN=N-nS-nL local nNv=Nv-nS-nL - + -- Groove time 15-18.99 sec for a unicorn. Or 60-65 for V/STOL unicorn. local Tgroove=playerData.Tgroove local TgrooveUnicorn=Tgroove and (Tgroove>=15.0 and Tgroove<=18.99) or false @@ -12014,7 +12016,7 @@ function AIRBOSS:_LSOgrade( playerData ) elseif not playerData.hover and playerData.actype == AIRBOSS.AircraftCarrier.AV8B then ------------------------------- - -- AV-8B not cleared to land -- -- Landing clearence is carrier from LC to Landing + -- AV-8B not cleared to land -- -- Landing clearence is carrier from LC to Landing ------------------------------- if playerData.landed then -- AIRBOSS wants your balls! @@ -15244,13 +15246,13 @@ end -- @param #string modex Tail number. function AIRBOSS:_MarshallInboundCall(unit, modex) - -- Calculate + -- Calculate local vectorCarrier = self:GetCoordinate():GetDirectionVec3(unit:GetCoordinate()) local bearing = UTILS.Round(unit:GetCoordinate():GetAngleDegrees( vectorCarrier ), 0) local distance = UTILS.Round(UTILS.MetersToNM(unit:GetCoordinate():Get2DDistance(self:GetCoordinate())),0) local angels = UTILS.Round(UTILS.MetersToFeet(unit:GetHeight()/1000),0) local state = UTILS.Round(self:_GetFuelState(unit)/1000,1) - + -- Pilot: "Marshall, [modex], marking mom's [bearing] for [distance], angels [XX], state [X.X]" local text=string.format("Marshal, %s, marking mom's %d for %d, angels %d, state %.1f", modex, bearing, distance, angels, state) -- Debug message. @@ -16077,8 +16079,8 @@ function AIRBOSS:_RequestMarshal( _unitName ) -- Voice over of inbound call (regardless of airboss rejecting it or not) if self.xtVoiceOvers then self:_MarshallInboundCall(_unit, playerData.onboard) - end - + end + -- Check if player is in CCA local inCCA = playerData.unit:IsInZone( self.zoneCCA ) @@ -16326,12 +16328,12 @@ function AIRBOSS:_RequestCommence( _unitName ) local playerData = self.players[_playername] -- #AIRBOSS.PlayerData if playerData then - + -- Voice over of Commencing call (regardless of Airboss will rejected or not) if self.xtVoiceOvers then self:_CommencingCall(_unit, playerData.onboard) end - + -- Check if unit is in CCA. local text = "" local cleared = false diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index de81e6604..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 @@ -1220,7 +1219,7 @@ CTLD.UnitTypes = { --- CTLD class version. -- @field #string version -CTLD.version="1.0.34" +CTLD.version="1.0.35" --- Instantiate a new CTLD. -- @param #CTLD self @@ -4731,6 +4730,7 @@ end -- @param Ops.CTLD#CTLD_CARGO Cargo The #CTLD_CARGO object to spawn. -- @param #table Surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type! -- @param #boolean PreciseLocation (Optional) Don't try to get a random position in the zone but use the dead center. Caution not to stack up stuff on another! + -- @param #string Structure (Optional) String object describing the current structure of the injected group; mainly for load/save to keep current state setup. -- @return #CTLD self -- @usage Use this function to pre-populate the field with Troops or Engineers at a random coordinate in a zone: -- -- create a matching #CTLD_CARGO type @@ -4739,7 +4739,7 @@ end -- local dropzone = ZONE:New("InjectZone") -- Core.Zone#ZONE -- -- and go: -- my_ctld:InjectTroops(dropzone,InjectTroopsType,{land.SurfaceType.LAND}) - function CTLD:InjectTroops(Zone,Cargo,Surfacetypes,PreciseLocation) + function CTLD:InjectTroops(Zone,Cargo,Surfacetypes,PreciseLocation,Structure) self:T(self.lid.." InjectTroops") local cargo = Cargo -- #CTLD_CARGO @@ -4757,6 +4757,49 @@ end return match end + local function Cruncher(group,typename,anzahl) + local units = group:GetUnits() + local reduced = 0 + for _,_unit in pairs (units) do + local typo = _unit:GetTypeName() + if typename == typo then + _unit:Destroy(false) + reduced = reduced + 1 + if reduced == anzahl then break end + end + end + end + + local function PostSpawn(args) + local group = args[1] + local structure = args[2] + if structure then + + local loadedstructure = {} + local strcset = UTILS.Split(structure,";") + for _,_data in pairs(strcset) do + local datasplit = UTILS.Split(_data,"==") + loadedstructure[datasplit[1]] = tonumber(datasplit[2]) + end + + local originalstructure = UTILS.GetCountPerTypeName(group) + + for _name,_number in pairs(originalstructure) do + local loadednumber = 0 + if loadedstructure[_name] then + loadednumber = loadedstructure[_name] + end + local reduce = false + if loadednumber < _number then reduce = true end + + if reduce then + Cruncher(group,_name,_number-loadednumber) + end + + end + end + end + if not IsTroopsMatch(cargo) then self.CargoCounter = self.CargoCounter + 1 cargo.ID = self.CargoCounter @@ -4793,6 +4836,11 @@ end local grpname = self.DroppedTroops[self.TroopCounter]:GetName() self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname) end + + if Structure then + BASE:ScheduleOnce(0.5,PostSpawn,{self.DroppedTroops[self.TroopCounter],Structure}) + end + if self.eventoninject then self:__TroopsDeployed(1,nil,nil,self.DroppedTroops[self.TroopCounter],type) end @@ -4806,6 +4854,7 @@ end -- @param Ops.CTLD#CTLD_CARGO Cargo The #CTLD_CARGO object to spawn. -- @param #table Surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type! -- @param #boolean PreciseLocation (Optional) Don't try to get a random position in the zone but use the dead center. Caution not to stack up stuff on another! + -- @param #string Structure (Optional) String object describing the current structure of the injected group; mainly for load/save to keep current state setup. -- @return #CTLD self -- @usage Use this function to pre-populate the field with Vehicles or FOB at a random coordinate in a zone: -- -- create a matching #CTLD_CARGO type @@ -4814,7 +4863,7 @@ end -- local dropzone = ZONE:New("InjectZone") -- Core.Zone#ZONE -- -- and go: -- my_ctld:InjectVehicles(dropzone,InjectVehicleType) - function CTLD:InjectVehicles(Zone,Cargo,Surfacetypes,PreciseLocation) + function CTLD:InjectVehicles(Zone,Cargo,Surfacetypes,PreciseLocation,Structure) self:T(self.lid.." InjectVehicles") local cargo = Cargo -- #CTLD_CARGO @@ -4832,6 +4881,49 @@ end return match end + local function Cruncher(group,typename,anzahl) + local units = group:GetUnits() + local reduced = 0 + for _,_unit in pairs (units) do + local typo = _unit:GetTypeName() + if typename == typo then + _unit:Destroy(false) + reduced = reduced + 1 + if reduced == anzahl then break end + end + end + end + + local function PostSpawn(args) + local group = args[1] + local structure = args[2] + if structure then + + local loadedstructure = {} + local strcset = UTILS.Split(structure,";") + for _,_data in pairs(strcset) do + local datasplit = UTILS.Split(_data,"==") + loadedstructure[datasplit[1]] = tonumber(datasplit[2]) + end + + local originalstructure = UTILS.GetCountPerTypeName(group) + + for _name,_number in pairs(originalstructure) do + local loadednumber = 0 + if loadedstructure[_name] then + loadednumber = loadedstructure[_name] + end + local reduce = false + if loadednumber < _number then reduce = true end + + if reduce then + Cruncher(group,_name,_number-loadednumber) + end + + end + end + end + if not IsVehicMatch(cargo) then self.CargoCounter = self.CargoCounter + 1 cargo.ID = self.CargoCounter @@ -4866,6 +4958,11 @@ end :InitDelayOff() :SpawnFromVec2(randomcoord) end + + if Structure then + BASE:ScheduleOnce(0.5,PostSpawn,{self.DroppedTroops[self.TroopCounter],Structure}) + end + if self.eventoninject then self:__CratesBuild(1,nil,nil,self.DroppedTroops[self.TroopCounter]) end @@ -5250,6 +5347,7 @@ end -- name matching a template in the table local match = false local cargo = nil + name = string.gsub(name,"-"," ") for _ind,_cargo in pairs (table) do local thiscargo = _cargo -- #CTLD_CARGO local template = thiscargo:GetTemplates() @@ -5257,6 +5355,7 @@ end template = { template } end for _,_name in pairs (template) do + _name = string.gsub(_name,"-"," ") if string.find(name,_name) and _cargo:GetType() ~= CTLD_CARGO.Enum.REPAIR then match = true cargo = thiscargo @@ -5269,18 +5368,21 @@ end --local data = "LoadedData = {\n" - local data = "Group,x,y,z,CargoName,CargoTemplates,CargoType,CratesNeeded,CrateMass\n" + local data = "Group,x,y,z,CargoName,CargoTemplates,CargoType,CratesNeeded,CrateMass,Structure\n" local n = 0 for _,_grp in pairs(grouptable) do local group = _grp -- Wrapper.Group#GROUP if group and group:IsAlive() then -- get template name local name = group:GetName() - local template = string.gsub(name,"-(.+)$","") + local template = name + if string.find(template,"#") then template = string.gsub(name,"#(%d+)$","") end + local template = string.gsub(name,"-(%d+)$","") + local match, cargo = FindCargoType(template,cgotable) if not match then match, cargo = FindCargoType(template,cgovehic) @@ -5293,6 +5395,11 @@ end local cgotype = cargo.CargoType local cgoneed = cargo.CratesNeeded local cgomass = cargo.PerCrateMass + local structure = UTILS.GetCountPerTypeName(group) + local strucdata = "" + for typen,anzahl in pairs (structure) do + strucdata = strucdata .. typen .. "=="..anzahl..";" + end if type(cgotemp) == "table" then local templates = "{" @@ -5304,8 +5411,8 @@ end end local location = group:GetVec3() - local txt = string.format("%s,%d,%d,%d,%s,%s,%s,%d,%d\n" - ,template,location.x,location.y,location.z,cgoname,cgotemp,cgotype,cgoneed,cgomass) + local txt = string.format("%s,%d,%d,%d,%s,%s,%s,%d,%d,%s\n" + ,template,location.x,location.y,location.z,cgoname,cgotemp,cgotype,cgoneed,cgomass,strucdata) data = data .. txt end end @@ -5460,7 +5567,7 @@ end for _id,_entry in pairs (loadeddata) do local dataset = UTILS.Split(_entry,",") - -- 1=Group,2=x,3=y,4=z,5=CargoName,6=CargoTemplates,7=CargoType,8=CratesNeeded,9=CrateMass,10=SubCategory + -- 1=Group,2=x,3=y,4=z,5=CargoName,6=CargoTemplates,7=CargoType,8=CratesNeeded,9=CrateMass,10=Structure local groupname = dataset[1] local vec2 = {} vec2.x = tonumber(dataset[2]) @@ -5474,14 +5581,19 @@ end cargotemplates = UTILS.Split(cargotemplates,";") local size = tonumber(dataset[8]) local mass = tonumber(dataset[9]) + local structure = nil + if dataset[10] then + structure = dataset[10] + structure = string.gsub(structure,",","") + end -- inject at Vec2 local dropzone = ZONE_RADIUS:New("DropZone",vec2,20) if cargotype == CTLD_CARGO.Enum.VEHICLE or cargotype == CTLD_CARGO.Enum.FOB then local injectvehicle = CTLD_CARGO:New(nil,cargoname,cargotemplates,cargotype,true,true,size,nil,true,mass) - self:InjectVehicles(dropzone,injectvehicle,self.surfacetypes,self.useprecisecoordloads) + self:InjectVehicles(dropzone,injectvehicle,self.surfacetypes,self.useprecisecoordloads,structure) elseif cargotype == CTLD_CARGO.Enum.TROOPS or cargotype == CTLD_CARGO.Enum.ENGINEERS then local injecttroops = CTLD_CARGO:New(nil,cargoname,cargotemplates,cargotype,true,true,size,nil,true,mass) - self:InjectTroops(dropzone,injecttroops,self.surfacetypes,self.useprecisecoordloads) + self:InjectTroops(dropzone,injecttroops,self.surfacetypes,self.useprecisecoordloads,structure) end elseif (type(groupname) == "string" and groupname == "STATIC") or cargotype == CTLD_CARGO.Enum.REPAIR then local cargotemplates = dataset[6] 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.