Merge branch 'develop' into FF/Ops

This commit is contained in:
Frank
2025-10-25 21:17:01 +02:00
20 changed files with 1120 additions and 798 deletions

View File

@@ -21,7 +21,7 @@
-- * Multiple carrier support due to object oriented approach.
-- * Unlimited number of players.
-- * Persistence of player results (optional). LSO grading data is saved to csv file.
-- * Trap sheet (optional).
-- * Trap sheet (optional).
-- * Finite State Machine (FSM) implementation.
--
-- **Supported Carriers:**
@@ -6950,6 +6950,9 @@ function AIRBOSS:_AddMarshalGroup( flight, stack )
-- Convert to clock string.
local Ccharlie = UTILS.SecondsToClock( flight.Tcharlie )
-- Make sure brc is never above 360
brc = brc % 360
-- Combined marshal call.
self:_MarshalCallArrived( flight.onboard, flight.case, brc, alt, Ccharlie, P )
@@ -7603,7 +7606,7 @@ function AIRBOSS:_InitPlayer( playerData, step )
playerData.landed = false
playerData.Tlso = timer.getTime()
playerData.Tgroove = nil
playerData.TIG0 = nil
playerData.TIG0 = 0 --changed to prevent errors in script when player is not in correct spot
playerData.wire = nil
playerData.flag = -100
playerData.debriefschedulerID = nil
@@ -8142,8 +8145,7 @@ end
--- Check current player status.
-- @param #AIRBOSS self
function AIRBOSS:_CheckPlayerStatus()
-- Loop over all players.
-- Loop over all players.
for _playerName, _playerData in pairs( self.players ) do
local playerData = _playerData -- #AIRBOSS.PlayerData
@@ -8415,7 +8417,7 @@ end
function AIRBOSS:_SetTimeInGroove( playerData )
-- Set time in the groove
if playerData.TIG0 then
if playerData.TIG0 then
playerData.Tgroove = timer.getTime() - playerData.TIG0 - 1.5 -- VNAO Edit - Subtracting an extra 1.5
else
playerData.Tgroove = 999
@@ -9644,7 +9646,7 @@ end
--- Break entry for case I/II recoveries.
-- @param #AIRBOSS self
-- @param #AIRBOSS.PlayerData playerData Player data table.
function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23
function AIRBOSS:_BreakEntry( playerData )
-- Get distances between carrier and player unit (parallel and perpendicular to direction of movement of carrier)
local X, Z = self:_GetDistances( playerData.unit )
@@ -9655,111 +9657,16 @@ function AIRBOSS:_BreakEntry( playerData ) --Adam Edits begin 7/24/23
return
end
local stern = self:_GetSternCoord()
local coord = playerData.unit:GetCoordinate()
local dist = coord:Get2DDistance( stern )
--adam edits
local playerCallsign = playerData.unit:GetCallsign()
--trigger.action.outText(' Hornet is hook down on pre-break entry for testing hook argument ', 5)
--trigger.action.outText(' Hornet callsign is '..playerCallsign, 5)
local playerName = playerData.name
local unit = playerData.unit
--local playerName = unit:GetName()
--trigger.action.outText(' Hornet name is '..playerName, 5)
local unitClient = Unit.getByName(unit:GetName())
local hookArgument = unitClient:getDrawArgumentValue(25)
local hookArgument_Tomcat = unitClient:getDrawArgumentValue(1305)
local speedMPS = playerData.unit:GetVelocityMPS()
local speedKTS = UTILS.MpsToKnots( speedMPS )
local player_alt = playerData.unit:GetAltitude()
player_alt_feet = player_alt * 3.28
player_alt_feet = player_alt_feet/10
player_alt_feet = math.floor(player_alt_feet)*10
local player_velocity_round = speedKTS * 1.00
player_velocity_round = player_velocity_round/10
player_velocity_round = math.floor(player_velocity_round)*10
local player_alt_feet = player_alt * 3.28
player_alt_feet = player_alt_feet/10
player_alt_feet = math.floor(player_alt_feet)*10
local Play_SH_Sound = USERSOUND:New( "Airboss Soundfiles/GreatBallsOfFire.ogg" )
local Play_666SH_Sound = USERSOUND:New( "Airboss Soundfiles/Runninwiththedevil.ogg" )
local playerType = playerData.actype
if dist <1000 and clientSHBFlag == false then
if speedKTS > 450 and speedKTS < 590 then
if player_alt_feet < 1500 then
if hookArgument > 0 or hookArgument_Tomcat > 0 then
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
playerData.shb = true
trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10)
local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
HypeMan.sendBotMessage(sh_message_to_discord)
Play_SH_Sound:ToAll()
clientSHBFlag = true
else
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
playerData.shb = false
end
-- Next step: Early Break.
else
end
elseif speedKTS > 589 then
if player_alt_feet < 625 and player_alt_feet >575 then --SHB 666
if hookArgument > 0 or hookArgument_Tomcat > 0 then
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
playerData.shb = true
trigger.action.outText(playerName..' performing a 666 Sierra Hotel Break in a '..playerType, 10)
local sh_message_to_discord = ('**'..playerName..' is performing a 666 Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
HypeMan.sendBotMessage(sh_message_to_discord)
Play_666SH_Sound:ToAll()
clientSHBFlag = true
else
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
playerData.shb = false
end
else
if hookArgument > 0 or hookArgument_Tomcat > 0 then
--trigger.action.outText(' 1 - Hornet is hook down so SHB!!!! Hook argument is: '..hookArgument, 5)
playerData.shb = true
trigger.action.outText(playerName..' performing a Sierra Hotel Break in a '..playerType, 10)
local sh_message_to_discord = ('**'..playerName..' is performing a Sierra Hotel Break in a '..playerType..' at '..player_velocity_round..' knots and '..player_alt_feet..' feet!**')
HypeMan.sendBotMessage(sh_message_to_discord)
Play_SH_Sound:ToAll()
clientSHBFlag = true
else
--trigger.action.outText(' Hornet is hook up on initial and just fast so no SHB. Hook argument is: '..hookArgument, 5)
playerData.shb = false
end
end
else
--trigger.action.outText(' Hornet is less than 400 kts so not SHB.... ', 5)
end
else
--trigger.action.outText(' ******TEST OF of Break Entry and distance to CVN is: '..dist, 5)
end
-- Check if we are in front of the boat (diffX > 0).
if self:_CheckLimits( X, Z, self.BreakEntry ) then
--trigger.action.outText(' 2 - Hornet is hook down on break entry for testing hook argument ', 5)
-- Hint for player about altitude, AoA etc.
self:_PlayerHint( playerData )
-- Next step: Early Break.
self:_SetPlayerStep( playerData, AIRBOSS.PatternStep.EARLYBREAK )
clientSHBFlag = false
end
end--Adam Edits end 7/24/23
end
--- Break.
-- @param #AIRBOSS self
@@ -10361,19 +10268,19 @@ function AIRBOSS:_Groove( playerData )
if rho >= RAR and rho <= RIM then
if gd.LUE > 0.22 and lineupError < -0.22 then
env.info " Drift Right across centre ==> DR-"
gd.Drift = " DR"
gd.Drift = "DR"
self:T( self.lid .. string.format( "Got Drift Right across centre step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
elseif gd.LUE < -0.22 and lineupError > 0.22 then
env.info " Drift Left ==> DL-"
gd.Drift = " DL"
gd.Drift = "DL"
self:T( self.lid .. string.format( "Got Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
elseif gd.LUE > 0.13 and lineupError < -0.14 then
env.info " Little Drift Right across centre ==> (DR-)"
gd.Drift = " (DR)"
gd.Drift = "(DR)"
self:T( self.lid .. string.format( "Got Little Drift Right across centre at step %s, d=%.3f: Max LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
elseif gd.LUE < -0.13 and lineupError > 0.14 then
env.info " Little Drift Left across centre ==> (DL-)"
gd.Drift = " (DL)"
gd.Drift = "(DL)"
self:E( self.lid .. string.format( "Got Little Drift Left across centre at step %s, d=%.3f: Min LUE=%.3f, lower LUE=%.3f", gs, d, gd.LUE, lineupError ) )
end
end
@@ -12051,10 +11958,12 @@ function AIRBOSS:GetHeading( magnetic )
hdg = hdg - self.magvar
end
-- Adjust negative values.
if hdg < 0 then
hdg = hdg + 360
end
-- -- Adjust negative values.
-- if hdg < 0 then
-- hdg = hdg + 360
-- end
hdg = hdg % 360 -- using this to replace the above function to prevent negative values and BRC higher than 360
return hdg
end
@@ -12321,7 +12230,7 @@ function AIRBOSS:GetHeadingIntoWind_new( vdeck, magnetic, coord )
-- Ship heading so cross wind is min for the given wind.
-- local intowind = (540 + (windto - magvar + math.deg(theta) )) % 360 -- VNAO Edit: Using old heading into wind algorithm
local intowind = self:GetHeadingIntoWind_old(vdeck) -- VNAO Edit: Using old heading into wind algorithm
local intowind = self:GetHeadingIntoWind_old(vdeck,magnetic) -- VNAO Edit: Using old heading into wind algorithm
return intowind, v
end
@@ -12751,7 +12660,7 @@ function AIRBOSS:_LSOgrade( playerData )
local TIG = ""
-- Analyse flight data and convert to LSO text.
if playerData.Tgroove and playerData.Tgroove <= 360 and playerData.case < 3 then --Circuit Added
TIG = self:_EvalGrooveTime( playerData ) --Circuit Added
TIG = self:_EvalGrooveTime( playerData ) or "N/A" --Circuit Added
end --Circuit Added
local GXX, nXX = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.XX )
local GIM, nIM = self:_Flightdata2Text( playerData, AIRBOSS.GroovePos.IM )
@@ -12945,16 +12854,21 @@ function AIRBOSS:_LSOgrade( playerData )
end
-- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore.
if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added
if points == 4 then -- VNAO EDIT: added
points = 3 -- VNAO EDIT: added
grade = "(OK)" -- VNAO EDIT: added
elseif points == 3 then -- VNAO EDIT: added
points = 2 -- VNAO EDIT: added
grade = "--" -- VNAO EDIT: added
end -- VNAO EDIT: added
end -- VNAO EDIT: added
-- -- VNAO EDIT: Subtract 1pt from overall grade if it is a 1 wire. If it's already a 1pt pass, ignore.
-- if playerData.wire == 1 and points > 1 then -- VNAO EDIT: added
-- if points == 4 then -- VNAO EDIT: added
-- points = 3 -- VNAO EDIT: added
-- grade = "(OK)" -- VNAO EDIT: added
-- elseif points == 3 then -- VNAO EDIT: added
-- points = 2 -- VNAO EDIT: added
-- grade = "--" -- VNAO EDIT: added
-- end -- VNAO EDIT: added
-- end -- VNAO EDIT: added
-- Circuit edit only take points awary from a 1 wire if there are more than 4 other deviations
if playerData.wire == 1 and points >= 3 and N > 4 then
points = points -1
end
env.info("Returning: " .. grade .. " " .. points .. " " .. G)
@@ -13030,6 +12944,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep )
-- Speed via AoA. Depends on aircraft type.
local S = nil
local A = nil --circuit moved this line to be seen outside of this scope
if step~=AIRBOSS.PatternStep.GROOVE_IW then -- VNAO Edit - Added To avoid getting an AOA or GS grade in the wires... let's just check left or right in the wires
if AIRBOSS.PatternStep.GROOVE_AR and playerData.waveoff == true and playerData.owo == true then -- VNAO Edit - Added
-- env.info('Adam MOOSE Edit -AR and waved off so do not add AOA or GS errors to comments ') -- VNAO Edit - Added
@@ -13050,7 +12965,7 @@ function AIRBOSS:_Flightdata2Text( playerData, groovestep )
end
-- Glideslope/altitude. Good [-0.3, 0.4] asymmetric!
local A = nil
if GSE > self.gle.HIGH then
A = underline( "H" )
elseif GSE > self.gle.High then

View File

@@ -2324,8 +2324,9 @@ end
-- @param #number Speed Speed in knots.
-- @param #number Altitude Altitude in feet. Only for airborne units. Default 2000 feet ASL.
-- @param #string Formation Formation used by ground units during patrol. Default "Off Road".
-- @param #number StayInZoneTime Stay this many seconds in the zone when done, only then drive back.
-- @return #AUFTRAG self
function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation)
function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation, StayInZoneTime)
local mission=AUFTRAG:New(AUFTRAG.Type.CAPTUREZONE)
@@ -2339,6 +2340,7 @@ function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation)
mission.optionROE=ENUMS.ROE.ReturnFire
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.optionAlarm=ENUMS.AlarmState.Auto
mission.StayInZoneTime = StayInZoneTime
mission.missionFraction=0.1
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil
@@ -4016,6 +4018,23 @@ function AUFTRAG:IsOver()
return over
end
--- Check if mission is repeatable.
-- @param #AUFTRAG self
-- @return #boolean If true, mission is repeatable.
function AUFTRAG:IsRepeatable()
local repeatmeS=self.repeatedSuccess<self.NrepeatSuccess or self.repeated<self.Nrepeat
local repeatmeF=self.repeatedFailure<self.NrepeatFailure or self.repeated<self.Nrepeat
if repeatmeS==true or repeatmeF==true then return true else return false end
return false
end
--- Check if mission is NOT repeatable.
-- @param #AUFTRAG self
-- @return #boolean If true, mission is NOT repeatable.
function AUFTRAG:IsNotRepeatable()
return not self:IsRepeatable()
end
--- Check if mission is NOT over.
-- @param #AUFTRAG self
-- @return #boolean If true, mission is NOT over yet.

View File

@@ -509,7 +509,7 @@ do
-- @field #AWACS
AWACS = {
ClassName = "AWACS", -- #string
version = "0.2.72", -- #string
version = "0.2.73", -- #string
lid = "", -- #string
coalition = coalition.side.BLUE, -- #number
coalitiontxt = "blue", -- #string
@@ -1596,6 +1596,16 @@ function AWACS:SetLocale(Locale)
return self
end
--- [User] Set own coordinate for BullsEye.
-- @param #AWACS self
-- @param Core.Point#COORDINATE
-- @return #AWACS self
function AWACS:SetBullsCoordinate(Coordinate)
self:T(self.lid.."SetBullsCoordinate")
self.AOCoordinate = Coordinate
return self
end
--- [User] Set the max mission range flights can be away from their home base.
-- @param #AWACS self
-- @param #number NM Distance in nautical miles

View File

@@ -31,7 +31,7 @@
-- @image OPS_CSAR.jpg
---
-- Last Update July 2025
-- Last Update Oct 2025
-------------------------------------------------------------------------
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
@@ -315,7 +315,7 @@ CSAR.AircraftType["CH-47Fbl1"] = 31
--- CSAR class version.
-- @field #string version
CSAR.version="1.0.33"
CSAR.version="1.0.34"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ToDo list
@@ -1150,11 +1150,11 @@ function CSAR:_EventHandler(EventData)
local initdcscoord = nil
local initcoord = nil
if _event.id == EVENTS.Ejection then
if _event.id == EVENTS.Ejection and _event.TgtDCSUnit then
initdcscoord = _event.TgtDCSUnit:getPoint()
initcoord = COORDINATE:NewFromVec3(initdcscoord)
self:T({initdcscoord})
else
elseif _event.IniDCSUnit then
initdcscoord = _event.IniDCSUnit:getPoint()
initcoord = COORDINATE:NewFromVec3(initdcscoord)
self:T({initdcscoord})
@@ -1244,7 +1244,10 @@ function CSAR:_EventHandler(EventData)
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
self:__Landed(2,_event.IniUnitName, _place)
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true)
local IsHeloBase = false
local ABName = _place:GetName()
if ABName and string.find(ABName,"^H") then IsHeloBase = true end -- if name starts with an H it's an (possibly elevated) helo base on current maps
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true,IsHeloBase)
else
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
end
@@ -1731,8 +1734,9 @@ end
-- @param #string heliname Heli name
-- @param #string groupname Group name
-- @param #boolean isairport If true, EVENT.Landing took place at an airport or FARP
-- @param #boolean noreschedule If true, do not try to reschedule this is distances are not ok (coming from landing event)
function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule)
-- @param #boolean noreschedule If true, do not try to reschedule this if distances are not ok (coming from landing event)
-- @param #boolean IsHeloBase If true, landing took place at a Helo Base (name "H ..." on current maps)
function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule, IsHeloBase)
self:T(self.lid .. " _ScheduledSARFlight")
self:T({heliname,groupname})
local _heliUnit = self:_GetSARHeli(heliname)
@@ -1758,7 +1762,7 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule)
self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000))
if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then
if ( _dist < self.FARPRescueDistance or isairport ) and ((_heliUnit:InAir() == false) or (IsHeloBase == true)) then
self:T(self.lid.."[Drop off debug] Distance ok, door check")
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true)
@@ -1773,7 +1777,7 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport, noreschedule)
--queue up
if not noreschedule then
self:__Returning(5,heliname,_woundedGroupName, isairport)
self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule)
self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname, isairport, noreschedule, IsHeloBase)
end
return self
end

View File

@@ -25,7 +25,7 @@
-- @module Ops.CTLD
-- @image OPS_CTLD.jpg
-- Last Update July 2025
-- Last Update Oct 2025
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -147,6 +147,7 @@ CTLD_CARGO = {
Location = ZONE:New(Location)
end
self.Location = Location
self.NoMoveToZone = false
return self
end
@@ -783,6 +784,7 @@ do
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10)
-- -- additionally, you can limit **where** the stock is available (one location only!) - this one is available in a zone called "Vehicle Store".
-- my_ctld:AddCratesCargo("Humvee",{"Humvee"},CTLD_CARGO.Enum.VEHICLE,2,2775,10,nil,nil,"Vehicle Store")
-- -- Tip: if you want the spawned/built group NOT to move to a MOVE zone, replace AddCratesCargo with AddCratesCargoNoMove (same parameters).
--
-- -- add infantry unit called "Forward Ops Base" using template "FOB", of type FOB, size 4, i.e. needs four crates to be build:
-- my_ctld:AddCratesCargo("Forward Ops Base",{"FOB"},CTLD_CARGO.Enum.FOB,4)
@@ -1556,6 +1558,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.smokedistance = 2000
self.movetroopstowpzone = true
self.movetroopsdistance = 5000
self.returntroopstobase = true -- if set to false, troops would stay after deployment inside a load zone.
self.troopdropzoneradius = 100
self.VehicleMoveFormation = AI.Task.VehicleFormation.VEE
@@ -3676,7 +3679,7 @@ function CTLD:_UnloadTroops(Group, Unit)
inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
end
if inzone then
droppingatbase = true
droppingatbase = self.returntroopstobase
end
-- check for hover unload
local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters
@@ -4513,7 +4516,8 @@ function CTLD:_RefreshF10Menus()
end
for _,cargoObj in pairs(self.Cargo_Crates) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
local needed = cargoObj:GetCratesNeeded() or 1
local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@@ -4524,7 +4528,8 @@ function CTLD:_RefreshF10Menus()
end
for _,cargoObj in pairs(self.Cargo_Statics) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
local needed = cargoObj:GetCratesNeeded() or 1
local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@@ -4536,7 +4541,8 @@ function CTLD:_RefreshF10Menus()
else
for _,cargoObj in pairs(self.Cargo_Crates) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
local needed = cargoObj:GetCratesNeeded() or 1
local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@@ -4547,7 +4553,8 @@ function CTLD:_RefreshF10Menus()
end
for _,cargoObj in pairs(self.Cargo_Statics) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
local needed = cargoObj:GetCratesNeeded() or 1
local txt = string.format("%d crate%s %s (%dkg)",needed,needed==1 and "" or "s",cargoObj.Name,cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@@ -4559,14 +4566,15 @@ function CTLD:_RefreshF10Menus()
end
end
else
if self.usesubcats then
if self.usesubcats == true then
local subcatmenus = {}
for catName, _ in pairs(self.subcats) do
subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case
end
for _, cargoObj in pairs(self.Cargo_Crates) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
local needed = cargoObj:GetCratesNeeded() or 1
local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@@ -4575,7 +4583,8 @@ function CTLD:_RefreshF10Menus()
end
for _, cargoObj in pairs(self.Cargo_Statics) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
local needed = cargoObj:GetCratesNeeded() or 1
local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@@ -4585,7 +4594,8 @@ function CTLD:_RefreshF10Menus()
else
for _, cargoObj in pairs(self.Cargo_Crates) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
local needed = cargoObj:GetCratesNeeded() or 1
local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@@ -4594,7 +4604,8 @@ function CTLD:_RefreshF10Menus()
end
for _, cargoObj in pairs(self.Cargo_Statics) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
local needed = cargoObj:GetCratesNeeded() or 1
local txt = string.format("%d crate%s %s (%dkg)", needed, needed==1 and "" or "s", cargoObj.Name, cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock >= 0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
@@ -5134,7 +5145,7 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP)
end
if inzone then
droppingatbase = true
droppingatbase = self.returntroopstobase
end
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
@@ -5426,6 +5437,52 @@ function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,Sub
return self
end
--- Identical to AddCratesCargo, but registers the cargo so the spawned/built group does not move to MOVE zones.
--- User function - Add *generic* crate-type loadable as cargo. This type will create crates that need to be loaded, moved, dropped and built.
-- @param #CTLD self
-- @param #string Name Unique name of this type of cargo. E.g. "Humvee".
-- @param #table Templates Table of #string names of late activated Wrapper.Group#GROUP building this cargo.
-- @param #CTLD_CARGO.Enum Type Type of cargo. I.e. VEHICLE or FOB. VEHICLE will move to destination zones when dropped/build, FOB stays put.
-- @param #number NoCrates Number of crates needed to build this cargo.
-- @param #number PerCrateMass Mass in kg of each crate
-- @param #number Stock Number of buildable groups in stock. Nil for unlimited.
-- @param #string SubCategory Name of sub-category (optional).
-- @param #boolean DontShowInMenu (optional) If set to "true" this won't show up in the menu.
-- @param Core.Zone#ZONE Location (optional) If set, the cargo item is **only** available here. Can be a #ZONE object or the name of a zone as #string.
-- @param #string UnitTypes Unit type names (optional). If set, only these unit types can pick up the cargo, e.g. "UH-1H" or {"UH-1H","OH58D"}.
-- @param #string Category Static category name (optional). If set, spawn cargo crate with an alternate category type, e.g. "Cargos".
-- @param #string TypeName Static type name (optional). If set, spawn cargo crate with an alternate type shape, e.g. "iso_container".
-- @param #string ShapeName Static shape name (optional). If set, spawn cargo crate with an alternate type sub-shape, e.g. "iso_container_cargo".
-- @return #CTLD self
function CTLD:AddCratesCargoNoMove(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location,UnitTypes,Category,TypeName,ShapeName)
self:T(self.lid .. " AddCratesCargoNoMove")
if not self:_CheckTemplates(Templates) then
self:E(self.lid .. "Crates Cargo for " .. Name .. " has missing template(s)!" )
return self
end
self.CargoCounter = self.CargoCounter + 1
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
cargo.NoMoveToZone = true
if UnitTypes then
cargo:AddUnitTypeName(UnitTypes)
end
cargo:SetStaticTypeAndShape("Cargos",self.basetype)
if TypeName then
cargo:SetStaticTypeAndShape(Category,TypeName,ShapeName)
end
table.insert(self.Cargo_Crates,cargo)
self.templateToCargoName = self.templateToCargoName or {}
if type(Templates)=="table" then
for _,t in pairs(Templates) do self.templateToCargoName[t] = Name end
else
self.templateToCargoName[Templates] = Name
end
self.nomovetozone_names = self.nomovetozone_names or {}
self.nomovetozone_names[Name] = true
if SubCategory and self.usesubcats ~= true then self.usesubcats=true end
return self
end
--- User function - Add *generic* static-type loadable as cargo. This type will create cargo that needs to be loaded, moved and dropped.
-- @param #CTLD self
-- @param #string Name Unique name of this type of cargo as set in the mission editor (note: UNIT name!), e.g. "Ammunition-1".
@@ -5670,8 +5727,14 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship
return self
end
end
local ctldzone = {} -- #CTLD.CargoZone
local exists = true
local ctldzone = self:GetCTLDZone(Name, Type) -- #CTLD.CargoZone
if not ctldzone then
exists = false
ctldzone = {}
end
ctldzone.active = Active or false
ctldzone.color = Color or SMOKECOLOR.Red
ctldzone.name = Name or "NONE"
@@ -5697,11 +5760,56 @@ function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Ship
ctldzone.shiplength = Shiplength or 100
ctldzone.shipwidth = Shipwidth or 10
end
self:AddZone(ctldzone)
if not exists then
self:AddZone(ctldzone)
end
return self
end
--- User function - find #CTLD.CargoZone zone by name.
-- @param #CTLD self
-- @param #string Name Name of this zone.
-- @param #string Type Type of this zone, #CTLD.CargoZoneType
-- @return #CTLD.CargoZone self
function CTLD:GetCTLDZone(Name, Type)
if Type == CTLD.CargoZoneType.LOAD then
for _, z in pairs(self.pickupZones) do
if z.name == Name then
return z
end
end
elseif Type == CTLD.CargoZoneType.DROP then
for _, z in pairs(self.dropOffZones) do
if z.name == Name then
return z
end
end
elseif Type == CTLD.CargoZoneType.SHIP then
for _, z in pairs(self.shipZones) do
if z.name == Name then
return z
end
end
elseif Type == CTLD.CargoZoneType.BEACON then
for _, z in pairs(self.droppedBeacons) do
if z.name == Name then
return z
end
end
else
for _, z in pairs(self.wpZones) do
if z.name == Name then
return z
end
end
end
return nil
end
--- User function - Creates and adds a #CTLD.CargoZone zone for this CTLD instance from an Airbase or FARP name.
-- Zones of type LOAD: Players load crates and troops here.
-- Zones of type DROP: Players can drop crates here. Note that troops can be unloaded anywhere.
@@ -7443,8 +7551,11 @@ end
-- @return #CTLD self
function CTLD:onafterCratesBuild(From, Event, To, Group, Unit, Vehicle)
self:T({From, Event, To})
if self.movetroopstowpzone then
self:_MoveGroupToZone(Vehicle)
if self.movetroopstowpzone and Vehicle then
local cg = self:GetGenericCargoObjectFromGroupName(Vehicle:GetName())
if not (cg and (cg.NoMoveToZone or (self.nomovetozone_names and self.nomovetozone_names[cg:GetName()]))) then
self:_MoveGroupToZone(Vehicle)
end
end
return self
end

View File

@@ -5029,7 +5029,7 @@ function FLIGHTGROUP:_UpdateMenu(delay)
-- Message to group.
MESSAGE:New(text, 5):ToGroup(self.group)
self:I(self.lid..text)
self:T(self.lid..text)
end
-- Get current position of player.

View File

@@ -662,6 +662,15 @@ function LEGION:CheckMissionQueue()
if mission:IsNotOver() and mission:IsReadyToCancel() then
mission:Cancel()
end
-- Housekeeping
local TNow = timer.getTime()
if mission:IsOver() and mission:IsNotRepeatable() and mission.DeletionTimstamp == nil then
mission.DeletionTimstamp = TNow
end
if mission.DeletionTimstamp ~= nil and TNow - mission.DeletionTimstamp > 1800 then
mission = nil
end
end
-- Check that runway is operational and that carrier is not recovering.
@@ -761,7 +770,7 @@ function LEGION:CheckMissionQueue()
-- Reduce number of reinforcements.
if reinforce then
mission.reinforce=mission.reinforce-#assets
self:I(self.lid..string.format("Reinforced with N=%d Nreinforce=%d", #assets, mission.reinforce))
self:T(self.lid..string.format("Reinforced with N=%d Nreinforce=%d", #assets, mission.reinforce))
end
return true

View File

@@ -4631,7 +4631,12 @@ function OPSGROUP:_UpdateTask(Task, Mission)
self:T(self.lid..string.format("Zone %s captured ==> Task DONE!", zoneCurr:GetName()))
-- Task done.
self:TaskDone(Task)
if Task.StayInZoneTime then
local stay = Task.StayInZoneTime
self:__TaskDone(stay,Task)
else
self:TaskDone(Task)
end
else
-- Current zone NOT captured yet ==> Find Target
@@ -7534,7 +7539,7 @@ end
function OPSGROUP:onafterElementDead(From, Event, To, Element)
-- Debug info.
self:I(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime()))
self:T(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime()))
-- Set element status.
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD)
@@ -8090,7 +8095,7 @@ function OPSGROUP:onafterStop(From, Event, To)
_DATABASE.FLIGHTGROUPS[self.groupname]=nil
-- Debug output.
self:I(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from _DATABASE")
self:T(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from _DATABASE")
end
--- On after "OutOfAmmo" event.