All luals findings solved
PR Prerequisites / Lua Check (pull_request) Failing after 22s
PR Prerequisites / Bundles Without Errors (pull_request) Failing after 23s

This commit is contained in:
2026-09-19 22:27:57 +02:00
parent 5ec7d18fa8
commit 05d47aa969
35 changed files with 356 additions and 149 deletions
@@ -6,7 +6,9 @@ local CapAirbase = require("classes.capClasses.CapAirbase")
---@class GlobalCapManager ---@class GlobalCapManager
local GlobalCapManager = {} local GlobalCapManager = {}
do do
---@type table<string, CapBase[]>
local airbasesPerStage = {} local airbasesPerStage = {}
---@type table<string, CapBase>
local allAirbasesByName = {} local allAirbasesByName = {}
local initiated = false local initiated = false
@@ -5,7 +5,7 @@ local GlobalConfig = require("classes.configuration.GlobalConfig")
local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing") local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing")
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper") local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
---@class AirGroup : OnUnitLostListener ---@class AirGroup : OnUnitLostListener, OnGroupRTBListener, OnGroupRTBInTenListener, OnLandEventListener, OnGroupOnStationListener
---@field protected _logger Logger ---@field protected _logger Logger
---@field protected _groupName string ---@field protected _groupName string
---@field protected _groupType AirGroupType ---@field protected _groupType AirGroupType
@@ -93,6 +93,9 @@ function InterceptGroup:SetTargetUnits(unitNames)
end) end)
end end
---@param selfA InterceptGroup
---@param time number
---@return number?
local updateContinous = function(selfA, time) local updateContinous = function(selfA, time)
local next = selfA:UpdateTask() local next = selfA:UpdateTask()
if next then if next then
@@ -104,6 +107,7 @@ function InterceptGroup:SetTargetUnits(unitNames)
self._updateTaskID = timer.scheduleFunction(updateContinous, self, timer.getTime() + 30) self._updateTaskID = timer.scheduleFunction(updateContinous, self, timer.getTime() + 30)
end end
---@param unit Unit
function InterceptGroup:RemoveTargetUnit(unit) function InterceptGroup:RemoveTargetUnit(unit)
if not unit then return end if not unit then return end
@@ -4,7 +4,7 @@ local Util = require("classes.util.Util")
local MissionEditorWarner = require("classes.util.MissionEditorWarnings") local MissionEditorWarner = require("classes.util.MissionEditorWarnings")
---@class SweepGroup : AirGroup ---@class SweepGroup : AirGroup
---@field _targetZoneIdPerStage table<number, string> ---@field _targetZoneIdPerStage table<string, string>
---@field _currentTargetZoneID string? ---@field _currentTargetZoneID string?
local SweepGroup = {} local SweepGroup = {}
SweepGroup.__index = SweepGroup SweepGroup.__index = SweepGroup
@@ -104,11 +104,10 @@ function RunwayBombingTracker:OnWeaponImpact(weaponDesc, impactPoint)
self._logger:debug("RunwayBombingTracker:OnWeaponImpact") self._logger:debug("RunwayBombingTracker:OnWeaponImpact")
local warhead = weaponDesc.warhead local warhead = weaponDesc.warhead --[[@as table]]
local explosiveMass = warhead.explosiveMass or warhead.shapedExplosiveMass local explosiveMass = (warhead.explosiveMass or warhead.shapedExplosiveMass) --[[@as number]]
for _, strikeMission in pairs(self.trackedRunways) do for _, strikeMission in pairs(self.trackedRunways) do
local zone= strikeMission:GetRunwayZone() local zone= strikeMission:GetRunwayZone()
if Util.is3dPointInZone({ x = impactPoint.x, z = impactPoint.y, y = 0 }, zone) then if Util.is3dPointInZone({ x = impactPoint.x, z = impactPoint.y, y = 0 }, zone) then
+4
View File
@@ -7,6 +7,7 @@ local CAP = {}
---@param attackHelos boolean ---@param attackHelos boolean
---@return table ---@return table
local function GetCAPTargetTypes(attackHelos) local function GetCAPTargetTypes(attackHelos)
---@type Array<string>
local targetTypes = { local targetTypes = {
[1] = "Planes", [1] = "Planes",
} }
@@ -53,7 +54,10 @@ local function GetCAPPointFromTriggerZone(airBase, capZone)
---@type Vec2 ---@type Vec2
local baseVec2 = { x = baseVec3.x, y = baseVec3.z } local baseVec2 = { x = baseVec3.x, y = baseVec3.z }
---@type Vec2
local pointA = capZone.verts[furthestA] local pointA = capZone.verts[furthestA]
---@type Vec2
local pointB = capZone.verts[furthestB] local pointB = capZone.verts[furthestB]
local furthest = pointA local furthest = pointA
local closest = pointB local closest = pointB
@@ -93,7 +93,7 @@ end
---@param currentPoint Vec2 ---@param currentPoint Vec2
---@param targetPosition Vec2 ---@param targetPosition Vec2
---@param targetUnit Unit ---@param targetUnit Unit
---@param airbase any ---@param airbase Airbase
---@param config any ---@param config any
---@param speed number? ---@param speed number?
---@param alt number? ---@param alt number?
+2
View File
@@ -173,6 +173,8 @@ function RTB.getInitialPoint(airbase)
} }
end end
---@param airbase Airbase
---@return table
function RTB.getLandingPoint(airbase) function RTB.getLandingPoint(airbase)
local basePoint = airbase:getPoint() local basePoint = airbase:getPoint()
return { return {
@@ -7,6 +7,7 @@ local SWEEP = {}
---@param attackHelos boolean ---@param attackHelos boolean
---@return table ---@return table
local function GetCAPTargetTypes(attackHelos) local function GetCAPTargetTypes(attackHelos)
---@type Array<string>
local targetTypes = { local targetTypes = {
[1] = "Planes", [1] = "Planes",
} }
@@ -49,7 +50,9 @@ local function GetCAPPointFromTriggerZone(airBase, capZone)
---@type Vec2 ---@type Vec2
local baseVec2 = { x = baseVec3.x, y = baseVec3.z } local baseVec2 = { x = baseVec3.x, y = baseVec3.z }
---@type Vec2
local pointA = capZone.verts[furthestA] local pointA = capZone.verts[furthestA]
---@type Vec2
local pointB = capZone.verts[furthestB] local pointB = capZone.verts[furthestB]
local furthest = pointA local furthest = pointA
local closest = pointB local closest = pointB
@@ -80,6 +83,7 @@ end
---@param airbase Airbase ---@param airbase Airbase
---@param capZone SpearheadTriggerZone ---@param capZone SpearheadTriggerZone
---@param capConfig CapConfig ---@param capConfig CapConfig
---@return table
local GetOutboundTask = function(airbase, capZone, capConfig) local GetOutboundTask = function(airbase, capZone, capConfig)
local airbaseVec3 = airbase:getPoint() local airbaseVec3 = airbase:getPoint()
local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z } local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z }
@@ -121,6 +125,7 @@ end
---@param airbase Airbase ---@param airbase Airbase
---@param capZone SpearheadTriggerZone ---@param capZone SpearheadTriggerZone
---@param capConfig CapConfig ---@param capConfig CapConfig
---@return table
function SWEEP.getAsMissionFromAirbase(groupName, airbase, capZone, capConfig) function SWEEP.getAsMissionFromAirbase(groupName, airbase, capZone, capConfig)
local pointA, pointB, pointC = SWEEP.getAsTasking(groupName, airbase, capZone, capConfig) local pointA, pointB, pointC = SWEEP.getAsTasking(groupName, airbase, capZone, capConfig)
+1 -1
View File
@@ -21,7 +21,7 @@ function DebugMenu:RegisterMenus()
missionCommands.addSubMenu(menuName, {}) missionCommands.addSubMenu(menuName, {})
local refresh = function(params) local refresh = function(params)
local selfA = params.self local selfA = params.self --[[@as DebugMenu]]
selfA:RefreshMenu() selfA:RefreshMenu()
end end
missionCommands.addCommand("Refresh Menu", debugMenuPath, refresh, { self = self }) missionCommands.addCommand("Refresh Menu", debugMenuPath, refresh, { self = self })
+12 -6
View File
@@ -10,7 +10,7 @@ local SpearheadEvents = require("classes.spearhead_events")
---@field private fleetNameIdentifier string ---@field private fleetNameIdentifier string
---@field private targetZonePerStage table<string, string> ---@field private targetZonePerStage table<string, string>
---@field private currentTargetZone string ---@field private currentTargetZone string
---@field private pointsPerZone table<string, {pointA: Vec2, pointB: Vec2}> ---@field private pointsPerZone table<string, {pointA: Vec3, pointB: Vec3}>
local FleetGroup = {} local FleetGroup = {}
FleetGroup.__index = FleetGroup FleetGroup.__index = FleetGroup
@@ -108,7 +108,13 @@ function FleetGroup.new(fleetGroupName, database, logger)
for i = first, second do for i = first, second do
self.targetZonePerStage[tostring(i)] = zoneName self.targetZonePerStage[tostring(i)] = zoneName
end end
self.pointsPerZone[zoneName] = { pointA = { x = pointA.x, z = pointA.y, y = 0 }, pointB = { x = pointB.x, z = pointB.y, y = 0} } ---@type {pointA: Vec3, pointB: Vec3}
local entry = {
pointA = {x = pointA.x, z = pointA.y, y = 0},
pointB = {x = pointB.x, z = pointB.y, y = 0}
}
self.pointsPerZone[zoneName] = entry
else else
MissionEditorWarning.Add("CARRIERROUTE zone stage numbers not in the format _[<number>-<number>]: " .. zoneName) MissionEditorWarning.Add("CARRIERROUTE zone stage numbers not in the format _[<number>-<number>]: " .. zoneName)
end end
@@ -125,10 +131,10 @@ function FleetGroup.new(fleetGroupName, database, logger)
end end
local SetTaskAsync = function(input, _) local SetTaskAsync = function(input, _)
local targetZone = input.targetZone local targetZone = input.targetZone --[[@as string]]
local task = input.task local task = input.task --[[@as table]]
local groupName = input.groupName local groupName = input.groupName --[[@as string]]
local l_logger = input.logger local l_logger = input.logger --[[@as Logger]]
local group = Group.getByName(groupName) local group = Group.getByName(groupName)
if group then if group then
+30 -7
View File
@@ -15,23 +15,45 @@ MizGroupsManager._groupNames = {}
MizGroupsManager._spawnTemplateData = {} MizGroupsManager._spawnTemplateData = {}
do --init do --init
for _, coalition_data in pairs(env.mission.coalition) do
---@param coalition_name string
---@return Coalition
local getCoalitionData = function(coalition_name)
return env.mission.coalition[coalition_name]
end
---@param country Country
---@param key string
---@return Groups?
local getGroupsData = function(country, key)
if key == "planes" then return country.plane end
if key == "helicopters" then return country.helicopter end
if key == "ground" then return country.vehicle end
if key == "ships" then return country.ship end
if key == "statics" then return country.static end
return nil
end
for _, coalition_name in ipairs({"neutral", "blue", "red"}) do
local coalition_data = getCoalitionData(coalition_name)
if coalition_data.country then if coalition_data.country then
for _, country_data in pairs(coalition_data.country) do for _, country_data in pairs(coalition_data.country) do
for category_name, categorydata in pairs(country_data) do for _, category_name in pairs(DcsUtil.getAllGroupCategoryNames()) do
local category_id = DcsUtil.stringToGroupCategory(category_name) local category_id = DcsUtil.stringToGroupCategory(category_name)
if category_id ~= nil and type(categorydata) == "table" and categorydata.group ~= nil and type(categorydata.group) == "table" then local groups_data = getGroupsData(country_data, category_name)
for _, group in pairs(categorydata.group) do
local name = group.name if category_id ~= nil and type(groups_data) == "table" and groups_data.group ~= nil and type(groups_data.group) == "table" then
for _, group in pairs(groups_data.group) do
local name = group.name --[[@as string]]
local skippable = false local skippable = false
local isStatic = false local isStatic = false
if category_id == DcsUtil.GroupCategory.STATIC then if category_id == DcsUtil.GroupCategory.STATIC then
isStatic = true isStatic = true
local unit = group.units[1] local unit = group.units[1] --[[@as table]]
if unit and unit.category == "Heliports" then if unit and unit.category == "Heliports" then
skippable = true skippable = true
elseif unit and unit.name then elseif unit and unit.name then
name = unit.name name = unit.name --[[@as string]]
else else
env.error("Group " .. name .. " has no units, skipping it.") env.error("Group " .. name .. " has no units, skipping it.")
skippable = true skippable = true
@@ -71,6 +93,7 @@ function MizGroupsManager.IsGroupStatic(groupName)
return nil return nil
end end
---@param groupName string
---@return SpawnData? ---@return SpawnData?
function MizGroupsManager.getSpawnTemplateData(groupName) function MizGroupsManager.getSpawnTemplateData(groupName)
return MizGroupsManager._spawnTemplateData[groupName] return MizGroupsManager._spawnTemplateData[groupName]
+13 -9
View File
@@ -16,11 +16,11 @@ SpawnManager.__index = SpawnManager
---@field uncontrolled boolean? Sets the group to be uncontrolled on spawn ---@field uncontrolled boolean? Sets the group to be uncontrolled on spawn
---@param logger Logger ---@param logger Logger
---@return SpawnManager
function SpawnManager.new(logger) function SpawnManager.new(logger)
local self = setmetatable({}, SpawnManager) local self = setmetatable({}, SpawnManager)
self._logger = logger self._logger = logger
self._persistedUnits = {} -- Stores units that should be persisted by name self._persistedUnits = {} -- Stores units that should be persisted by name
return self return self
@@ -133,8 +133,9 @@ do --- privates
]] ]]
if spawnTemplate and spawnTemplate["units"] then if spawnTemplate and spawnTemplate["units"] then
for _, unit in pairs(spawnTemplate["units"]) do local units = spawnTemplate["units"] --[[@as Array<table>]]
local name = unit["name"] for _, unit in pairs(units) do
local name = unit["name"] --[[@as string]]
SpearheadEvents.addOnUnitLostEventListener(name, self) SpearheadEvents.addOnUnitLostEventListener(name, self)
local state = Persistence.UnitState(name) local state = Persistence.UnitState(name)
@@ -146,16 +147,17 @@ do --- privates
if override and override.emptyLoadouts == true then if override and override.emptyLoadouts == true then
if unit["payload"] and unit["payload"]["pylons"] then if unit["payload"] and unit["payload"]["pylons"] then
unit["payload"]["pylons"] = {} local payload = unit["payload"] --[[@as table]]
payload["pylons"] = {} --[[@as table]]
end end
end end
if unit["parking"] then if unit["parking"] then
unit["parking_landing"] = unit["parking"] unit["parking_landing"] = unit["parking"] --[[@as number]]
end end
if unit["parking_id"] then if unit["parking_id"] then
unit["parking_landing_id"] = unit["parking_id"] unit["parking_landing_id"] = unit["parking_id"] --[[@as number]]
end end
end end
@@ -210,9 +212,11 @@ do --- privates
spawnTemplate["x"] = persistentState.pos.x spawnTemplate["x"] = persistentState.pos.x
spawnTemplate["y"] = persistentState.pos.z spawnTemplate["y"] = persistentState.pos.z
if spawnTemplate["units"] and spawnTemplate["units"][1] then if spawnTemplate["units"] and spawnTemplate["units"][1] then
spawnTemplate["units"][1]["x"] = persistentState.pos.x local units = spawnTemplate["units"] --[[@as Array<table>]]
spawnTemplate["units"][1]["y"] = persistentState.pos.z local firstUnit = units[1] --[[@as table]]
spawnTemplate["units"][1]["heading"] = persistentState.heading or 0 firstUnit["x"] = persistentState.pos.x --[[@as number]]
firstUnit["y"] = persistentState.pos.z --[[@as number]]
firstUnit["heading"] = persistentState.heading or 0 --[[@as number]]
end end
end end
end end
+2 -1
View File
@@ -187,7 +187,8 @@ do
local userFileName = SpearheadConfig.Persistence.fileName local userFileName = SpearheadConfig.Persistence.fileName
local split = Util.split_string(userFileName, ".") local split = Util.split_string(userFileName, ".")
if not split and #split < 3 then if not split or #split < 3 then
split = split or {}
split[#split+1] = "0" split[#split+1] = "0"
split[#split+1] = "spearhead" split[#split+1] = "spearhead"
end end
+19 -4
View File
@@ -215,6 +215,8 @@ function Database.New(Logger)
local airbaseData = self:getAirbaseDataForDrawLayer(layer_object) local airbaseData = self:getAirbaseDataForDrawLayer(layer_object)
if airbaseData then if airbaseData then
self._logger:debug("found airbase data for " .. layer_object.name) self._logger:debug("found airbase data for " .. layer_object.name)
if layer_object.primitiveType == "TextBox" then
layer_object = layer_object --[[@as TextBox]]
local number = tonumber(layer_object.text) local number = tonumber(layer_object.text)
airbaseData.buildingKilos = number airbaseData.buildingKilos = number
end end
@@ -224,6 +226,7 @@ function Database.New(Logger)
end end
end end
end end
end
---@type table<integer, boolean> ---@type table<integer, boolean>
do -- custom drawings do -- custom drawings
@@ -263,6 +266,8 @@ function Database.New(Logger)
local zone = DcsUtil.getZoneByName(stageZoneName) local zone = DcsUtil.getZoneByName(stageZoneName)
local vec2 = { x = layer_object.mapX, y = layer_object.mapY } local vec2 = { x = layer_object.mapX, y = layer_object.mapY }
if zone and Util.is2dPointInZone(vec2, zone) == true then if zone and Util.is2dPointInZone(vec2, zone) == true then
if layer_object.primitiveType == "TextBox" then
layer_object = layer_object --[[@as TextBox]]
local description = layer_object.text local description = layer_object.text
if description and description ~= "" then if description and description ~= "" then
stageData.StageBriefing = description stageData.StageBriefing = description
@@ -273,6 +278,7 @@ function Database.New(Logger)
end end
end end
end end
end
-- fill blue sams -- fill blue sams
for _, blueSamStageName in pairs(self._tables.BlueSams) do for _, blueSamStageName in pairs(self._tables.BlueSams) do
@@ -468,6 +474,7 @@ function Database.New(Logger)
return self return self
end end
---@type table<string, boolean>
local is_group_taken = {} local is_group_taken = {}
local getAvailableGroups = function() local getAvailableGroups = function()
@@ -625,8 +632,9 @@ function Database:loadBlueSamUnits()
for _, layer_object in pairs(layer.objects) do for _, layer_object in pairs(layer.objects) do
local vec2 = { x = layer_object.mapX, y = layer_object.mapY } local vec2 = { x = layer_object.mapX, y = layer_object.mapY }
if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then if layer_object.primitiveType == "TextBox" and triggerZone and Util.is2dPointInZone(vec2, triggerZone) then
if layer_object.name and Util.startswith(layer_object.name, "supplybriefing_", true) then if layer_object.name and Util.startswith(layer_object.name, "supplybriefing_", true) then
layer_object = layer_object --[[@as TextBox]]
local description = layer_object.text local description = layer_object.text
if description and description ~= "" then if description and description ~= "" then
samData.briefing = description samData.briefing = description
@@ -725,8 +733,9 @@ function Database:LoadZoneData(missionZoneName)
for _, layer_object in pairs(layer.objects) do for _, layer_object in pairs(layer.objects) do
local vec2 = { x = layer_object.mapX, y = layer_object.mapY } local vec2 = { x = layer_object.mapX, y = layer_object.mapY }
if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then if layer_object.primitiveType == "TextBox" and triggerZone and Util.is2dPointInZone(vec2, triggerZone) then
if layer_object.name and Util.startswith(layer_object.name, "briefing_", true) then if layer_object.name and Util.startswith(layer_object.name, "briefing_", true) then
layer_object = layer_object --[[@as TextBox]]
local description = layer_object.text local description = layer_object.text
if description and description ~= "" then if description and description ~= "" then
self._tables.MissionZoneData[missionZoneName].description = description self._tables.MissionZoneData[missionZoneName].description = description
@@ -781,7 +790,8 @@ function Database:loadFarpData()
for _, layer_object in pairs(layer.objects) do for _, layer_object in pairs(layer.objects) do
local vec2 = { x = layer_object.mapX, y = layer_object.mapY } local vec2 = { x = layer_object.mapX, y = layer_object.mapY }
if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then if layer_object.primitiveType == "TextBox" and triggerZone and Util.is2dPointInZone(vec2, triggerZone) then
layer_object = layer_object --[[@as TextBox]]
if layer_object.name and Util.startswith(layer_object.name, "supplybriefing_", true) then if layer_object.name and Util.startswith(layer_object.name, "supplybriefing_", true) then
local description = layer_object.text local description = layer_object.text
if description and description ~= "" then if description and description ~= "" then
@@ -950,6 +960,7 @@ function Database:getBriefingForStage(stagename)
return stageZone.StageBriefing or "" return stageZone.StageBriefing or ""
end end
---@param stagename string
---@return Array<string> ---@return Array<string>
function Database:getMissionsForStage(stagename) function Database:getMissionsForStage(stagename)
local stageZone = self._tables.StageZones[stagename] local stageZone = self._tables.StageZones[stagename]
@@ -957,6 +968,7 @@ function Database:getMissionsForStage(stagename)
return stageZone.MissionZones return stageZone.MissionZones
end end
---@param stagename string
---@return Array<string> ---@return Array<string>
function Database:getRandomMissionsForStage(stagename) function Database:getRandomMissionsForStage(stagename)
local stageZone = self._tables.StageZones[stagename] local stageZone = self._tables.StageZones[stagename]
@@ -964,13 +976,14 @@ function Database:getRandomMissionsForStage(stagename)
return stageZone.RandomMissionZones return stageZone.RandomMissionZones
end end
---@param missionZoneName string
---@return MissionZoneData? ---@return MissionZoneData?
function Database:getMissionDataForZone(missionZoneName) function Database:getMissionDataForZone(missionZoneName)
return self._tables.MissionZoneData[missionZoneName] return self._tables.MissionZoneData[missionZoneName]
end end
---@param stageName string ---@param stageName string
---@return table result airbase Names ---@return Array<string> result airbase Names
function Database:getAirbaseNamesInStage(stageName) function Database:getAirbaseNamesInStage(stageName)
local stageData = self._tables.StageZones[stageName] local stageData = self._tables.StageZones[stageName]
if not stageData then return {} end if not stageData then return {} end
@@ -984,6 +997,7 @@ function Database:getFarpNamesInStage(stageName)
return stageData.FarpZones or {} return stageData.FarpZones or {}
end end
---@param farpZoneName string
---@return FarpZoneData? ---@return FarpZoneData?
function Database:getFarpDataForZone(farpZoneName) function Database:getFarpDataForZone(farpZoneName)
local farpData = self._tables.FarpZoneData[farpZoneName] local farpData = self._tables.FarpZoneData[farpZoneName]
@@ -999,6 +1013,7 @@ function Database:getAirbaseDataForZone(baseName)
return baseData return baseData
end end
---@param stageName string
---@return string? ---@return string?
function Database:getStageBriefingForStage(stageName) function Database:getStageBriefingForStage(stageName)
local stageData = self._tables.StageZones[stageName] local stageData = self._tables.StageZones[stageName]
+43 -17
View File
@@ -32,7 +32,9 @@ do
---@field OnStageNumberChanged fun(self:OnStageChangedListener, number:integer, laneIdentifier:string?) ---@field OnStageNumberChanged fun(self:OnStageChangedListener, number:integer, laneIdentifier:string?)
do -- STAGE NUMBER CHANGED do -- STAGE NUMBER CHANGED
---@type Array<OnStageChangedListener>
local OnStageNumberChangedListeners = {} local OnStageNumberChangedListeners = {}
---@type Array<fun(number:integer, laneIdentifier:string?)>
local OnStageNumberChangedHandlers = {} local OnStageNumberChangedHandlers = {}
---Add a stage zone number changed listener ---Add a stage zone number changed listener
---@param listener OnStageChangedListener object with function OnStageNumberChanged(self, number, stageLaneIdentifier) ---@param listener OnStageChangedListener object with function OnStageNumberChanged(self, number, stageLaneIdentifier)
@@ -47,6 +49,7 @@ do
---@class OnStageNumberChangeCompleteListener ---@class OnStageNumberChangeCompleteListener
---@field OnStageNumberChangeComplete fun(self:OnStageNumberChangeCompleteListener, number:integer, laneIdentifier:string?) ---@field OnStageNumberChangeComplete fun(self:OnStageNumberChangeCompleteListener, number:integer, laneIdentifier:string?)
---@type Array<OnStageNumberChangeCompleteListener>
local OnStageNumberChangeCompleteListeners = {} local OnStageNumberChangeCompleteListeners = {}
---@param listener OnStageNumberChangeCompleteListener ---@param listener OnStageNumberChangeCompleteListener
SpearheadEvents.AddStageNumberChangeCompleteListener = function(listener) SpearheadEvents.AddStageNumberChangeCompleteListener = function(listener)
@@ -110,6 +113,9 @@ do
table.insert(onWeaponFiredListeners, weaponFiredListener) table.insert(onWeaponFiredListeners, weaponFiredListener)
end end
---@param unit Unit
---@param weapon Weapon
---@param target Unit?
local triggerWeaponFired = function(unit, weapon, target) local triggerWeaponFired = function(unit, weapon, target)
for _, callable in pairs(onWeaponFiredListeners) do for _, callable in pairs(onWeaponFiredListeners) do
local _, err = pcall(function() local _, err = pcall(function()
@@ -122,11 +128,14 @@ do
end end
end end
---@class OnLandEventListener
---@field OnUnitLanded fun(self:OnLandEventListener, initiatorUnit:Unit, airbase:Airbase)
---@type table<string,Array<OnLandEventListener>>
local onLandEventListeners = {} local onLandEventListeners = {}
---Add an event listener to a specific unit ---Add an event listener to a specific unit
---@param unitName string to call when the unit lands ---@param unitName string to call when the unit lands
---@param landListener table table with function OnUnitLanded(self, initiatorUnit, airbase) ---@param landListener OnLandEventListener table with function OnUnitLanded(self, initiatorUnit, airbase)
SpearheadEvents.addOnUnitLandEventListener = function(unitName, landListener) SpearheadEvents.addOnUnitLandEventListener = function(unitName, landListener)
if type(landListener) ~= "table" then if type(landListener) ~= "table" then
warn("Event handler not of type table/object") warn("Event handler not of type table/object")
@@ -162,6 +171,11 @@ do
end end
do -- ON RTB do -- ON RTB
---@class OnGroupRTBListener
---@field OnGroupRTB fun(self:OnGroupRTBListener, groupName:string)
---@type table<string,Array<OnGroupRTBListener>>
local OnGroupRTBListeners = {} local OnGroupRTBListeners = {}
---Adds a function to the events listener that triggers when a group publishes themselves RTB. ---Adds a function to the events listener that triggers when a group publishes themselves RTB.
---This is only available when a ROUTE is created via the Spearhead.RouteUtil ---This is only available when a ROUTE is created via the Spearhead.RouteUtil
@@ -197,11 +211,15 @@ do
end end
end end
---@class OnGroupRTBInTenListener
---@field OnGroupRTBInTen fun(self:OnGroupRTBInTenListener, groupName:string)
---@type table<string,Array<OnGroupRTBInTenListener>>
local OnGroupRTBInTenListeners = {} local OnGroupRTBInTenListeners = {}
---Adds a function to the events listener that triggers when a group publishes themselves RTB. ---Adds a function to the events listener that triggers when a group publishes themselves RTB.
---This is only available when a ROUTE is created via the Spearhead.RouteUtil ---This is only available when a ROUTE is created via the Spearhead.RouteUtil
---@param groupName string the groupname to expect ---@param groupName string the groupname to expect
---@param handlingObject table object with OnGroupRTBInTen(self, groupName) ---@param handlingObject OnGroupRTBInTenListener object with OnGroupRTBInTen(self, groupName)
SpearheadEvents.addOnGroupRTBInTenListener = function(groupName, handlingObject) SpearheadEvents.addOnGroupRTBInTenListener = function(groupName, handlingObject)
if type(handlingObject) ~= "table" then if type(handlingObject) ~= "table" then
warn("Event handler not of type table/object") warn("Event handler not of type table/object")
@@ -234,10 +252,17 @@ do
end end
do -- ON Station do -- ON Station
---@class OnGroupOnStationListener
---@field OnGroupOnStation fun(self:OnGroupOnStationListener, groupName:string)
---@type table<string,Array<OnGroupOnStationListener>>
local OnGroupOnStationListeners = {} local OnGroupOnStationListeners = {}
---Adds a function to the events listener that triggers when a group publishes themselves RTB. ---Adds a function to the events listener that triggers when a group publishes themselves RTB.
---This is only available when a ROUTE is created via the Spearhead.RouteUtil ---This is only available when a ROUTE is created via the Spearhead.RouteUtil
---@param groupName string the groupname to expect ---@param groupName string the groupname to expect
---@param handlingObject OnGroupOnStationListener object with OnGroupOnStation(self, groupName)
SpearheadEvents.addOnGroupOnStationListener = function(groupName, handlingObject) SpearheadEvents.addOnGroupOnStationListener = function(groupName, handlingObject)
if type(handlingObject) ~= "table" then if type(handlingObject) ~= "table" then
warn("Event handler not of type table/object") warn("Event handler not of type table/object")
@@ -270,15 +295,18 @@ do
end end
do -- PLAYER ENTER UNIT do -- PLAYER ENTER UNIT
---@class OnPlayerEnterUnitListener
---@field OnPlayerEntersUnit fun(self:OnPlayerEnterUnitListener, unit:Unit)
---@type Array<OnPlayerEnterUnitListener>
local playerEnterUnitListeners = {} local playerEnterUnitListeners = {}
---comment ---comment
---@param listener table object with OnPlayerEntersUnit(self, unit) ---@param listener OnPlayerEnterUnitListener object with OnPlayerEntersUnit(self, unit)
SpearheadEvents.AddOnPlayerEnterUnitListener = function(listener) SpearheadEvents.AddOnPlayerEnterUnitListener = function(listener)
if type(listener) ~= "table" then if type(listener) ~= "table" then
warn("Unit lost Event listener not of type table/object") warn("Unit lost Event listener not of type table/object")
return return
end end
table.insert(playerEnterUnitListeners, listener) table.insert(playerEnterUnitListeners, listener)
end end
@@ -315,8 +343,8 @@ do
local e = {} local e = {}
function e:onEvent(event) function e:onEvent(event)
if event.id == world.event.S_EVENT_LAND or event.id == world.event.S_EVENT_RUNWAY_TOUCH then if event.id == world.event.S_EVENT_LAND or event.id == world.event.S_EVENT_RUNWAY_TOUCH then
local unit = event.initiator local unit = event.initiator --[[@as Unit]]
local airbase = event.place local airbase = event.place --[[@as Airbase]]
if unit ~= nil then if unit ~= nil then
local name = unit:getName() local name = unit:getName()
if onLandEventListeners[name] then if onLandEventListeners[name] then
@@ -336,7 +364,7 @@ do
event.id == world.event.S_EVENT_CRASH or event.id == world.event.S_EVENT_CRASH or
event.id == world.event.S_EVENT_EJECTION or event.id == world.event.S_EVENT_EJECTION or
event.id == world.event.S_EVENT_UNIT_LOST then event.id == world.event.S_EVENT_UNIT_LOST then
local object = event.initiator local object = event.initiator --[[@as Unit]]
if object and object.getName then if object and object.getName then
logDebug("Receiving death event from: " .. object:getName()) logDebug("Receiving death event from: " .. object:getName())
@@ -355,15 +383,11 @@ do
end end
end end
if event.id == world.event.S_EVENT_EJECTION then
end
if event.id == world.event.S_EVENT_SHOT then if event.id == world.event.S_EVENT_SHOT then
local shooter = event.initiator local shooter = event.initiator --[[@as Unit]]
local weapon = event.weapon local weapon = event.weapon --[[@as Weapon]]
local target = event.target local target = event.target --[[@as Unit?]]
triggerWeaponFired(shooter, weapon, target) triggerWeaponFired(shooter, weapon, target)
end end
@@ -372,10 +396,14 @@ do
Persistence.UpdateNow() Persistence.UpdateNow()
end end
---@type table<string, boolean>
local AI_GROUPS = {} local AI_GROUPS = {}
---@param unit Unit
---@param _ any
local function CheckAndTriggerSpawnAsync(unit, _) local function CheckAndTriggerSpawnAsync(unit, _)
---@param checkUnit Unit
---@return boolean, string?
local function isPlayer(checkUnit) local function isPlayer(checkUnit)
if checkUnit == nil then return false, "unit is nil" end if checkUnit == nil then return false, "unit is nil" end
if checkUnit.getGroup == nil then return false, 'no get group function in unit object, most likely static' end if checkUnit.getGroup == nil then return false, 'no get group function in unit object, most likely static' end
@@ -405,8 +433,6 @@ do
if isPlayer(unit) == true then if isPlayer(unit) == true then
SpearheadEvents.TriggerPlayerEntersUnit(unit) SpearheadEvents.TriggerPlayerEntersUnit(unit)
end end
return nil
end end
if event.id == world.event.S_EVENT_BIRTH then if event.id == world.event.S_EVENT_BIRTH then
+11 -4
View File
@@ -8,6 +8,7 @@ do --setup route util
---@param attackHelos boolean ---@param attackHelos boolean
---@return table ---@return table
local function GetCAPTargetTypes(attackHelos) local function GetCAPTargetTypes(attackHelos)
---@type table<number, string>
local targetTypes = { local targetTypes = {
[1] = "Planes", [1] = "Planes",
} }
@@ -53,8 +54,9 @@ do --setup route util
---comment ---comment
---@param groupName string ---@param groupName string
---@param position table { x, y} ---@param position Vec3
---@param altitude number ---@param altitude number
---@param deviationdistance number
---@param speed number ---@param speed number
---@param duration number ---@param duration number
---@param engageHelos boolean ---@param engageHelos boolean
@@ -181,7 +183,7 @@ do --setup route util
end end
---comment ---comment
---@param position table { x, y} ---@param position Vec3
---@param altitude number ---@param altitude number
---@param speed number ---@param speed number
---@param childTasks table ---@param childTasks table
@@ -210,7 +212,8 @@ do --setup route util
---comment ---comment
---@param groupName string groupName you're creating this route for ---@param groupName string groupName you're creating this route for
---@param airdromeId number airdromeId ---@param airdromeId number airdromeId
---@param capPoint table { x, z } ---@param capPoint Vec3
---@param racetrackSecondPoint Vec3?
---@param altitude number ---@param altitude number
---@param speed number ---@param speed number
---@param durationOnStation number ---@param durationOnStation number
@@ -304,6 +307,7 @@ do --setup route util
end end
local group = Group.getByName(groupName) local group = Group.getByName(groupName)
---@type Vec3?
local pos; local pos;
local i = 1 local i = 1
if group == nil then if group == nil then
@@ -393,6 +397,9 @@ do --setup route util
}, "" }, ""
end end
---@param pointA Vec3
---@param pointB Vec3
---@return table, string?
ROUTE_UTIL.CreateCarrierRacetrack = function(pointA, pointB) ROUTE_UTIL.CreateCarrierRacetrack = function(pointA, pointB)
return { return {
id = "Mission", id = "Mission",
@@ -461,7 +468,7 @@ do --setup route util
} }
} }
} }
}, "" }, nil
end end
end end
@@ -327,12 +327,13 @@ function GlobalStageManager:OnStageNumberChangeComplete(stageNumber, stageLaneId
if stageLaneIdentifier ~= nil then return end if stageLaneIdentifier ~= nil then return end
self.logger:debug("Stage number change complete to: " .. tostring(stageNumber)) self.logger:debug("Stage number change complete to: " .. tostring(stageNumber))
---@type Array<Group>
local groups = {} local groups = {}
for _, player in pairs(DcsUtil.getAllPlayerUnits()) do for _, player in pairs(DcsUtil.getAllPlayerUnits()) do
local group = player:getGroup() local group = player:getGroup()
if group then if group then
groups[group:getID()] = group table.insert(groups, group)
end end
end end
@@ -369,8 +370,11 @@ end
function GlobalStageManager:PrintMermaidStage() function GlobalStageManager:PrintMermaidStage()
local lanes = self._stageRepository:getAllStageLanes() local lanes = self._stageRepository:getAllStageLanes()
---@type table<string, string>
local nodes = {} local nodes = {}
---@type table<string, string>
local edges = {} local edges = {}
---@type table<string, Array<number>>
local stageIndicesByLane = {} -- Track all stage indices per lane local stageIndicesByLane = {} -- Track all stage indices per lane
local mainLaneId = "default" local mainLaneId = "default"
@@ -403,7 +407,9 @@ function GlobalStageManager:PrintMermaidStage()
"#9B59B6", -- 25: Amethyst "#9B59B6", -- 25: Amethyst
"#1ABC9C", -- 26: Turquoise "#1ABC9C", -- 26: Turquoise
} }
---@type table<string, string>
local laneColorMap = {} -- Map lane ID to color local laneColorMap = {} -- Map lane ID to color
---@type number
local colorIndex = 1 local colorIndex = 1
-- Build nodes and collect all stage indices per lane -- Build nodes and collect all stage indices per lane
@@ -430,6 +436,7 @@ function GlobalStageManager:PrintMermaidStage()
local stageName = stage.stageName or stage.zoneName local stageName = stage.stageName or stage.zoneName
-- Generate bracket label: [1], [2] for default, [w1], [e2] for other lanes -- Generate bracket label: [1], [2] for default, [w1], [e2] for other lanes
---@type string
local bracketLabel local bracketLabel
if laneId == "default" then if laneId == "default" then
bracketLabel = "[" .. stageIndex .. "]" bracketLabel = "[" .. stageIndex .. "]"
@@ -496,7 +503,7 @@ function GlobalStageManager:PrintMermaidStage()
for _, lane in ipairs(lanes) do for _, lane in ipairs(lanes) do
if lane:IsDefaultStageLane() == false then if lane:IsDefaultStageLane() == false then
local sideId = lane:GetStageLaneIdentifier() local sideId = lane:GetStageLaneIdentifier()
local sideIndices = stageIndicesByLane[sideId] local sideIndices = stageIndicesByLane[sideId] or {} --[[@as Array<number>]]
-- For each stage in the side lane -- For each stage in the side lane
for _, stageIdx in ipairs(sideIndices) do for _, stageIdx in ipairs(sideIndices) do
@@ -528,7 +535,7 @@ function GlobalStageManager:PrintMermaidStage()
for _, lane in ipairs(lanes) do for _, lane in ipairs(lanes) do
if lane:IsDefaultStageLane() == false then if lane:IsDefaultStageLane() == false then
local sideId = lane:GetStageLaneIdentifier() local sideId = lane:GetStageLaneIdentifier()
local sideIndices = stageIndicesByLane[sideId] local sideIndices = stageIndicesByLane[sideId] or {} --[[@as Array<number>]]
-- Find the appropriate gate node for this side lane -- Find the appropriate gate node for this side lane
-- Use first stage >= nextIdx if it exists, otherwise use the highest stage -- Use first stage >= nextIdx if it exists, otherwise use the highest stage
@@ -91,9 +91,9 @@ function SpearheadGroup:GetCoalition()
end end
---comment ---comment
---@return table result list of objects ---@return Array<Unit|StaticObject> result list of objects
function SpearheadGroup:GetObjects() function SpearheadGroup:GetObjects()
---@type Array<Unit|StaticObject>
local result = {} local result = {}
if self._isStatic == true then if self._isStatic == true then
local staticObject = StaticObject.getByName(self._groupName) local staticObject = StaticObject.getByName(self._groupName)
@@ -113,6 +113,7 @@ end
function StageBase:SpawnRedUnits() function StageBase:SpawnRedUnits()
---comment ---comment
---@param groups Array<SpearheadGroup> ---@param groups Array<SpearheadGroup>
---@return number|nil
local spawnAsync = function(groups) local spawnAsync = function(groups)
for _, group in pairs(groups) do for _, group in pairs(groups) do
group:Spawn() group:Spawn()
@@ -142,6 +143,7 @@ end
function StageBase:SpawnBlueUnits() function StageBase:SpawnBlueUnits()
---comment ---comment
---@param groups Array<SpearheadGroup> ---@param groups Array<SpearheadGroup>
---@return number|nil
local spawnAsync = function(groups) local spawnAsync = function(groups)
for _, group in pairs(groups) do for _, group in pairs(groups) do
group:Spawn() group:Spawn()
@@ -37,6 +37,7 @@ function BuildableZone:New(targetZone, kilosRequired, crateType, buildableGroup
---@param params UnpackCrateParam ---@param params UnpackCrateParam
---@param time number ---@param time number
---@return number|nil
local startUnpackingCrate = function(params, time) local startUnpackingCrate = function(params, time)
local unpacked = params.unpackedKilos + (params.kilosPerSecond * 2) local unpacked = params.unpackedKilos + (params.kilosPerSecond * 2)
local alreadySpawned = params.unpackedItems / params.groupsPerKilo local alreadySpawned = params.unpackedItems / params.groupsPerKilo
@@ -104,6 +105,7 @@ function BuildableZone:OnCrateDroppedOff(_, kilos)
---@param params UnpackCrateParam ---@param params UnpackCrateParam
---@param time number ---@param time number
---@return number|nil
local startUnpackingCrate = function(params, time) local startUnpackingCrate = function(params, time)
local unpacked = params.unpackedKilos + (params.kilosPerSecond * 2) local unpacked = params.unpackedKilos + (params.kilosPerSecond * 2)
local alreadySpawned = params.unpackedItems / params.groupsPerKilo local alreadySpawned = params.unpackedItems / params.groupsPerKilo
+12 -9
View File
@@ -4,8 +4,8 @@
---@field private _isDefaultStageLane boolean ---@field private _isDefaultStageLane boolean
---@field private _stageLaneIdentifier string ---@field private _stageLaneIdentifier string
---@field private _activeStageIndex number ---@field private _activeStageIndex number
---@field private _stagesInLaneByIndex table<number, Array<Stage>> ---@field private _stagesInLaneByIndex table<string, Array<Stage>>
---@field private _chapterStarts table<number, boolean>? ---@field private _chapterStarts table<string, boolean>?
---@field private _stageLaneState StageLaneState ---@field private _stageLaneState StageLaneState
---@field private _maxStageIndex number ---@field private _maxStageIndex number
local StageLane = {} local StageLane = {}
@@ -16,6 +16,7 @@ StageLane.__index = StageLane
---| "BetweenChapters" ---| "BetweenChapters"
---| "Completed" ---| "Completed"
---@type string?
StageLane.DefaultLaneKey = nil StageLane.DefaultLaneKey = nil
function StageLane.New(laneIdentifier) function StageLane.New(laneIdentifier)
@@ -37,21 +38,21 @@ end
---@param stage Stage ---@param stage Stage
function StageLane:AddStage(stage) function StageLane:AddStage(stage)
local stageIndex = stage:GetStageIndex() local stageIndex = stage:GetStageIndex()
if not self._stagesInLaneByIndex[stageIndex] then if not self._stagesInLaneByIndex[tostring(stageIndex)] then
self._stagesInLaneByIndex[stageIndex] = {} self._stagesInLaneByIndex[tostring(stageIndex)] = {}
end end
if not self._maxStageIndex or stageIndex > self._maxStageIndex then if not self._maxStageIndex or stageIndex > self._maxStageIndex then
self._maxStageIndex = stageIndex self._maxStageIndex = stageIndex
end end
table.insert(self._stagesInLaneByIndex[stageIndex], stage) table.insert(self._stagesInLaneByIndex[tostring(stageIndex)], stage)
end end
---@param stageNumber number ---@param stageNumber number
---@return boolean? ---@return boolean?
function StageLane:IsStageIndexComplete(stageNumber) function StageLane:IsStageIndexComplete(stageNumber)
local stages = self._stagesInLaneByIndex[stageNumber] local stages = self._stagesInLaneByIndex[tostring(stageNumber)]
if not stages then if not stages then
return nil return nil
end end
@@ -88,7 +89,7 @@ end
---@param stageNumber number ---@param stageNumber number
function StageLane:SetActiveStageIndex(stageNumber) function StageLane:SetActiveStageIndex(stageNumber)
if self._stagesInLaneByIndex[stageNumber] == nil then if self._stagesInLaneByIndex[tostring(stageNumber)] == nil then
self._stageLaneState = "BetweenChapters" -- stage number is not in this lane, so we are between chapters self._stageLaneState = "BetweenChapters" -- stage number is not in this lane, so we are between chapters
elseif stageNumber > self._maxStageIndex then elseif stageNumber > self._maxStageIndex then
self._stageLaneState = "Completed" -- stage number is beyond the max stage index self._stageLaneState = "Completed" -- stage number is beyond the max stage index
@@ -108,6 +109,7 @@ end
--- Chapter starts are the first StageIndex after a gap in stage numbers. <br> --- Chapter starts are the first StageIndex after a gap in stage numbers. <br>
--- For example, if the stage numbers are 1, 2, 3, 5, 6, 7, then stage number 5 is a chapter start because there is a gap between 3 and 5. <br> --- For example, if the stage numbers are 1, 2, 3, 5, 6, 7, then stage number 5 is a chapter start because there is a gap between 3 and 5. <br>
---@param stageNumber number ---@param stageNumber number
---@return boolean
function StageLane:IsChapterStart(stageNumber) function StageLane:IsChapterStart(stageNumber)
if self._chapterStarts == nil then if self._chapterStarts == nil then
@@ -123,13 +125,14 @@ end
function StageLane:FillChapterStarts() function StageLane:FillChapterStarts()
local previousIndex = nil local previousIndex = nil
---@type table<string, number>
local stageIndices = {} local stageIndices = {}
for stageIndex, _ in pairs(self._stagesInLaneByIndex) do for stageIndex, _ in pairs(self._stagesInLaneByIndex) do
table.insert(stageIndices, tonumber(stageIndex)) table.insert(stageIndices, tonumber(stageIndex))
end end
table.sort(stageIndices) table.sort(stageIndices)
self._chapterStarts = self._chapterStarts or {} if self._chapterStarts == nil then self._chapterStarts = {} end
for _, stageIndex in ipairs(stageIndices) do for _, stageIndex in ipairs(stageIndices) do
if previousIndex == nil then if previousIndex == nil then
-- First stage is always a chapter start -- First stage is always a chapter start
@@ -158,7 +161,7 @@ end
---@param stageIndex number ---@param stageIndex number
---@return Array<Stage>? ---@return Array<Stage>?
function StageLane:GetStagesAtIndex(stageIndex) function StageLane:GetStagesAtIndex(stageIndex)
return self._stagesInLaneByIndex[stageIndex] return self._stagesInLaneByIndex[tostring(stageIndex)]
end end
---@return number? ---@return number?
@@ -162,6 +162,7 @@ function Stage:superNew(database, stageConfig, logger, initData, stageType, miss
---comment ---comment
---@param selfA Stage ---@param selfA Stage
---@param time number? ---@param time number?
---@return number|nil
self.CheckContinuousAsync = function (selfA, time) self.CheckContinuousAsync = function (selfA, time)
selfA:CheckAndUpdateSelf() selfA:CheckAndUpdateSelf()
@@ -325,7 +326,9 @@ function Stage:GetStageName()
return self.stageName return self.stageName
end end
---@return Array<Mission>
function Stage:GetMissions() function Stage:GetMissions()
---@type Array<Mission>
local missions = {} local missions = {}
for _, mission in pairs(self._db.missions) do for _, mission in pairs(self._db.missions) do
table.insert(missions, mission) table.insert(missions, mission)
@@ -674,6 +677,7 @@ function Stage:ActivateBlueStage()
end end
---@param selfA Stage ---@param selfA Stage
---@return number|nil
local ActivateBlueAsync = function(selfA) local ActivateBlueAsync = function(selfA)
pcall(function() pcall(function()
selfA:MarkStage() selfA:MarkStage()
@@ -54,7 +54,7 @@ local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineS
if lineThickness == nil or lineThickness <= 0 then if lineThickness == nil or lineThickness <= 0 then
lineStyle = 0 lineStyle = 0
end end
---@type string
local functionString = "trigger.action.markupToAll(" .. shapeID .. ", -1, " .. drawID .. "," local functionString = "trigger.action.markupToAll(" .. shapeID .. ", -1, " .. drawID .. ","
for _, point in pairs(points) do for _, point in pairs(points) do
@@ -125,14 +125,14 @@ function DrawingHelper.DrawPolygon(object)
local fillColor = DrawingHelper.ColorToColorTable(free.fillColorString) local fillColor = DrawingHelper.ColorToColorTable(free.fillColorString)
local color = DrawingHelper.ColorToColorTable(free.colorString) local color = DrawingHelper.ColorToColorTable(free.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(free.style) local lineStyle = DrawingHelper.ToLineStyleInteger(free.style)
---@type Array<number>
local keys = {} local keys = {}
for k, _ in pairs(free.points) do for k, _ in pairs(free.points) do
table.insert(keys, k) table.insert(keys, k)
end end
table.sort(keys, function(a, b) return a < b end) table.sort(keys, function(a, b) return a < b end)
---@type Array<Vec3>
local points = {} local points = {}
for _, k in ipairs(keys) do for _, k in ipairs(keys) do
local point = free.points[k] local point = free.points[k]
@@ -274,6 +274,7 @@ function DrawingHelper.ColorTableToColorString(rgba)
end end
---@param lineStyle string ---@param lineStyle string
---@return integer
function DrawingHelper.ToLineStyleInteger(lineStyle) function DrawingHelper.ToLineStyleInteger(lineStyle)
lineStyle = lineStyle:lower() lineStyle = lineStyle:lower()
if lineStyle == "no line" then if lineStyle == "no line" then
@@ -36,6 +36,7 @@ end
---@param self BattleManager ---@param self BattleManager
---@param time number ---@param time number
---@return number?
local function CheckTask(self, time) local function CheckTask(self, time)
local interval = self:Update() local interval = self:Update()
if not interval then return end if not interval then return end
@@ -148,7 +149,7 @@ end
---@return number ---@return number
function BattleManager:getBestAmmo(unit) function BattleManager:getBestAmmo(unit)
local ammo = unit:getAmmo() local ammo = unit:getAmmo() --[[@as table<number, table>]]
if not ammo then return 3221225470, 1 end -- Default ammo if no ammo is found if not ammo then return 3221225470, 1 end -- Default ammo if no ammo is found
@@ -162,9 +163,9 @@ function BattleManager:getBestAmmo(unit)
end end
end end
local entry = Util.randomFromList(shells) local entry = Util.randomFromList(shells) --[[@as table]]
if entry and entry.desc and entry.desc.warhead then if entry and entry.desc and entry.desc.warhead then
local caliber = entry.desc.warhead.caliber local caliber = entry.desc.warhead.caliber --[[@as number]]
if caliber > 50 then if caliber > 50 then
return 258503344128, 1 return 258503344128, 1
else else
@@ -209,6 +210,7 @@ function BattleManager:ToShootingHulls(groups)
end end
local hulls = Util.getSeparatedConvexHulls(points, 50) local hulls = Util.getSeparatedConvexHulls(points, 50)
---@type Array<Array<Vec2>>
local enlargedHulls = {} local enlargedHulls = {}
for _, hull in pairs(hulls) do for _, hull in pairs(hulls) do
local enlarged = Util.enlargeConvexHull(hull, 25) local enlarged = Util.enlargeConvexHull(hull, 25)
@@ -7,7 +7,7 @@ local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHel
local StageConfig = require("classes.configuration.StageConfig") local StageConfig = require("classes.configuration.StageConfig")
---@class MissionCommandsHelper ---@class MissionCommandsHelper : OnPlayerEnterUnitListener
---@field missionsByCode table<string, Mission> @table of missions by their code ---@field missionsByCode table<string, Mission> @table of missions by their code
---@field enabledByCode table<string, boolean> @table of enabled missions by their code ---@field enabledByCode table<string, boolean> @table of enabled missions by their code
---@field updateNeeded boolean @flag to indicate if an update is needed ---@field updateNeeded boolean @flag to indicate if an update is needed
@@ -369,7 +369,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID)
do --- secondary missions do --- secondary missions
local count = 0 local count = 0
local path = { [1] = folderNames.secondary } local path = { [1] = folderNames.secondary }
---@type Array<Mission>
local secondaryMissions = {} local secondaryMissions = {}
for code, enabled in pairs(self.enabledByCode) do for code, enabled in pairs(self.enabledByCode) do
if enabled == true then if enabled == true then
@@ -84,6 +84,7 @@ function SupplyConfigHelper.fromObjectName(name)
end end
---@param type CrateType ---@param type CrateType
---@return SupplyConfig?
function SupplyConfigHelper.getSupplyConfig(type) function SupplyConfigHelper.getSupplyConfig(type)
return SupplyConfig[type] return SupplyConfig[type]
end end
@@ -10,7 +10,7 @@ local SupplyLoadConfig = require("classes.stageClasses.helpers.SupplyLoadConfig"
---@field enteredSupplyHub fun(self:SupplyUnitEventListener, unit:Unit, hub:SupplyHub) | nil ---@field enteredSupplyHub fun(self:SupplyUnitEventListener, unit:Unit, hub:SupplyHub) | nil
---@field exitedSupplyHub fun(self:SupplyUnitEventListener, unit:Unit, hub:SupplyHub) | nil ---@field exitedSupplyHub fun(self:SupplyUnitEventListener, unit:Unit, hub:SupplyHub) | nil
---@class SupplyUnitsTracker ---@class SupplyUnitsTracker : OnPlayerEnterUnitListener
---@field private _supplyUnitsByName table<string, Unit> ---@field private _supplyUnitsByName table<string, Unit>
---@field private _cargoInUnits table<string, table<CrateType, number>> ---@field private _cargoInUnits table<string, table<CrateType, number>>
---@field private _logger Logger ---@field private _logger Logger
@@ -43,6 +43,8 @@ function SupplyUnitsTracker.getOrCreate()
SpearheadEvents.AddOnPlayerEnterUnitListener(singleton) SpearheadEvents.AddOnPlayerEnterUnitListener(singleton)
---@param selfA SupplyUnitsTracker ---@param selfA SupplyUnitsTracker
---@param time number
---@return number?
local function updateTask(selfA, time) local function updateTask(selfA, time)
selfA:Update() selfA:Update()
@@ -134,6 +136,7 @@ end
---@private ---@private
---@param unit Unit ---@param unit Unit
---@return boolean
function SupplyUnitsTracker:IsSupplyUnit(unit) function SupplyUnitsTracker:IsSupplyUnit(unit)
if unit == nil then return false end if unit == nil then return false end
@@ -158,15 +161,17 @@ function SupplyUnitsTracker:AddCargoToUnit(unitID, crateType)
local unit = DcsUtil.GetPlayerUnitByID(unitID) local unit = DcsUtil.GetPlayerUnitByID(unitID)
if unit == nil then return end if unit == nil then return end
if self._cargoInUnits[unitID] == nil then local unitIdStr = tostring(unitID)
self._cargoInUnits[unitID] = {}
if self._cargoInUnits[unitIdStr] == nil then
self._cargoInUnits[unitIdStr] = {}
end end
if self._cargoInUnits[unitID][crateType] == nil then if self._cargoInUnits[unitIdStr][crateType] == nil then
self._cargoInUnits[unitID][crateType] = 0 self._cargoInUnits[unitIdStr][crateType] = 0
end end
self._cargoInUnits[unitID][crateType] = self._cargoInUnits[unitID][crateType] + 1 self._cargoInUnits[unitIdStr][crateType] = self._cargoInUnits[unitIdStr][crateType] + 1
end end
@@ -253,7 +258,7 @@ function SupplyUnitsTracker:CheckUnitsInZones()
end end
end end
self._unitPositions[unit:getID()] = pos self._unitPositions[tostring(unit:getID())] = pos
end end
end end
end end
@@ -323,6 +328,7 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType, missionCommandsHe
self:UpdateWeightForUnit(unit) self:UpdateWeightForUnit(unit)
cargoCount = cargoCount + 1 cargoCount = cargoCount + 1
---@type {name: string, type: string, x: number, y: number}
local cargoSpawnObject = { local cargoSpawnObject = {
name = crateType .. "_" .. cargoCount, name = crateType .. "_" .. cargoCount,
type = cargoConfig.staticType, type = cargoConfig.staticType,
@@ -484,7 +490,7 @@ function SupplyUnitsTracker:GetBoundingBoxes(foundObject)
end end
local objPos = foundObject:getPoint() local objPos = foundObject:getPoint()
local box = desc.box local box = desc.box --[[@type table]]
local heading = 0 local heading = 0
-- Try to get object heading from position vector's forward direction -- Try to get object heading from position vector's forward direction
@@ -497,10 +503,10 @@ function SupplyUnitsTracker:GetBoundingBoxes(foundObject)
end) end)
-- For rotated objects, we need to rotate the bounding box -- For rotated objects, we need to rotate the bounding box
local minX = box.min.x local minX = box.min.x --[[@as number]]
local maxX = box.max.x local maxX = box.max.x --[[@as number]]
local minZ = box.min.z local minZ = box.min.z --[[@as number]]
local maxZ = box.max.z local maxZ = box.max.z --[[@as number]]
-- If object has significant rotation, apply rotation to bbox corners -- If object has significant rotation, apply rotation to bbox corners
if math.abs(heading) > 0.1 then if math.abs(heading) > 0.1 then
@@ -517,8 +523,8 @@ function SupplyUnitsTracker:GetBoundingBoxes(foundObject)
minZ, maxZ = math.huge, -math.huge minZ, maxZ = math.huge, -math.huge
for _, corner in ipairs(corners) do for _, corner in ipairs(corners) do
local rotX = corner[1] * math.cos(heading) - corner[2] * math.sin(heading) local rotX = corner[1] * math.cos(heading) - corner[2] * math.sin(heading) --[[@as number]]
local rotZ = corner[1] * math.sin(heading) + corner[2] * math.cos(heading) local rotZ = corner[1] * math.sin(heading) + corner[2] * math.cos(heading) --[[@as number]]
minX = math.min(minX, rotX) minX = math.min(minX, rotX)
maxX = math.max(maxX, rotX) maxX = math.max(maxX, rotX)
minZ = math.min(minZ, rotZ) minZ = math.min(minZ, rotZ)
@@ -587,7 +593,7 @@ function SupplyUnitsTracker:GetCargoPlacePosition(unit, crateTypeName)
return nil return nil
end end
local crateRelativeBBox = crateDesc.box local crateRelativeBBox = crateDesc.box --[[@as table]]
-- Get drop zone config for this unit -- Get drop zone config for this unit
local dropZones = { local dropZones = {
@@ -610,8 +616,11 @@ function SupplyUnitsTracker:GetCargoPlacePosition(unit, crateTypeName)
radius = 100 -- Search a large area radius = 100 -- Search a large area
} }
} }
---@type Array<{ pos: { x: number, y: number, z: number }, bbox: { min: { x: number, y: number, z: number }, max: { x: number, y: number, z: number } } }>
local occupiedObjects = {} local occupiedObjects = {}
---@param foundItem Object
---@param _ any
local found = function(foundItem, _) local found = function(foundItem, _)
local bbox = self:GetBoundingBoxes(foundItem) local bbox = self:GetBoundingBoxes(foundItem)
if bbox then if bbox then
@@ -660,6 +669,7 @@ function SupplyUnitsTracker:GetCargoPlacePosition(unit, crateTypeName)
local candidateY = land.getHeight({ x = candidateX, y = candidateZ }) local candidateY = land.getHeight({ x = candidateX, y = candidateZ })
-- Convert crate's relative bbox to world space at this position -- Convert crate's relative bbox to world space at this position
---@type { min: { x: number, y: number, z: number }, max: { x: number, y: number, z: number } }
local crateBBoxWorldSpace = { local crateBBoxWorldSpace = {
min = { min = {
x = candidateX + crateRelativeBBox.min.x, x = candidateX + crateRelativeBBox.min.x,
@@ -25,6 +25,8 @@ local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelpe
local BuildableMission = {} local BuildableMission = {}
BuildableMission.__index = BuildableMission BuildableMission.__index = BuildableMission
---@param siteType string
---@param coords string
---@return string ---@return string
local function getDefaultBriefing(siteType, coords) local function getDefaultBriefing(siteType, coords)
return "We've dispatched forward units to find a proper spot for a new " .. siteType .. "." .. return "We've dispatched forward units to find a proper spot for a new " .. siteType .. "." ..
@@ -43,6 +45,7 @@ end
---@param noLandingZone SpearheadTriggerZone? ---@param noLandingZone SpearheadTriggerZone?
---@param logger Logger ---@param logger Logger
---@param briefing string? ---@param briefing string?
---@return BuildableMission
function BuildableMission.new(database, logger, targetZone, noLandingZone, requiredKilos, requiredCrateType, briefing) function BuildableMission.new(database, logger, targetZone, noLandingZone, requiredKilos, requiredCrateType, briefing)
setmetatable(BuildableMission, Mission) setmetatable(BuildableMission, Mission)
@@ -117,6 +120,7 @@ function BuildableMission:ShowBriefing(groupID)
local unitType = DcsUtil.getUnitTypeFromGroup(group) local unitType = DcsUtil.getUnitTypeFromGroup(group)
local coords = DcsUtil.convertVec2ToUnitUsableType(self.location, unitType) local coords = DcsUtil.convertVec2ToUnitUsableType(self.location, unitType)
if coords == nil then coords = "Could not make conversion" end
local siteType = "FARP" local siteType = "FARP"
if self._crateType == "SAM_CRATE" then if self._crateType == "SAM_CRATE" then
@@ -143,17 +147,20 @@ function BuildableMission:ShowBriefing(groupID)
trigger.action.outTextForGroup(groupID, briefing, GlobalConfig:getBriefingTime()) trigger.action.outTextForGroup(groupID, briefing, GlobalConfig:getBriefingTime())
end end
---@param groupID number
function BuildableMission:MarkMissionAreaToGroup(groupID) function BuildableMission:MarkMissionAreaToGroup(groupID)
if self._markIDsPerGroup[groupID] then local groupIdStr = tostring(groupID)
DcsUtil.RemoveMark(self._markIDsPerGroup[groupID])
end
if self._markIDsPerGroup[groupIdStr] then
DcsUtil.RemoveMark(self._markIDsPerGroup[groupIdStr])
end
---@type string
local text = "[" .. self.code .. "] " .. self.name .. " | " .. self._crateType local text = "[" .. self.code .. "] " .. self.name .. " | " .. self._crateType
local location = { x= self.location.x, y=land.getHeight(self.location), z=self.location.y } local location = { x= self.location.x, y=land.getHeight(self.location), z=self.location.y }
local markID = DcsUtil.AddMarkToGroup(groupID, text, location) local markID = DcsUtil.AddMarkToGroup(groupID, text, location)
self._markIDsPerGroup[groupID] = markID self._markIDsPerGroup[groupIdStr] = markID
end end
---@private ---@private
@@ -197,6 +204,7 @@ function BuildableMission:SpawnActive()
---@param selfA BuildableMission ---@param selfA BuildableMission
---@param time number ---@param time number
---@return number?
local checkForCrateTasks = function (selfA, time) local checkForCrateTasks = function (selfA, time)
selfA:CheckCratesInZone() selfA:CheckCratesInZone()
@@ -24,6 +24,7 @@ local RunwayStrikeMission = {}
---@param runway Runway ---@param runway Runway
---@param database Database ---@param database Database
---@param logger Logger ---@param logger Logger
---@param airbaseName string
---@param runwayBombingTracker RunwayBombingTracker ---@param runwayBombingTracker RunwayBombingTracker
---@return RunwayStrikeMission? ---@return RunwayStrikeMission?
function RunwayStrikeMission.new(runway, airbaseName, database, logger, runwayBombingTracker) function RunwayStrikeMission.new(runway, airbaseName, database, logger, runwayBombingTracker)
@@ -205,8 +206,9 @@ function RunwayStrikeMission:StartRepair()
self._repairInProgress = true self._repairInProgress = true
self._logger:debug("Starting repair of runway strike mission " .. self._airportName .. ":" .. self._runway.Name) self._logger:debug("Starting repair of runway strike mission " .. self._airportName .. ":" .. self._runway.Name)
---comment ---comment
---@param selfA any ---@param selfA RunwayStrikeMission
---@return unknown ---@param time number
---@return number?
local repairTask = function (selfA, time) local repairTask = function (selfA, time)
local interval = selfA:DoRepairCycle() local interval = selfA:DoRepairCycle()
if interval == nil then return nil end if interval == nil then return nil end
@@ -215,6 +217,7 @@ function RunwayStrikeMission:StartRepair()
timer.scheduleFunction(repairTask, self, timer.getTime() + 5) timer.scheduleFunction(repairTask, self, timer.getTime() + 5)
end end
---@return number?
function RunwayStrikeMission:DoRepairCycle() function RunwayStrikeMission:DoRepairCycle()
local interval = 5 local interval = 5
@@ -247,12 +250,14 @@ function RunwayStrikeMission:DoRepairCycle()
end end
---@class StaticSpawn ---@class StaticSpawn : table
---@field category string ---@field category string
---@field type string ---@field type string
---@field y number ---@field y number
---@field x number ---@field x number
---@field heading number ---@field heading number
---@field name string?
---@field hidden boolean?
local counter = 1 local counter = 1
@@ -441,6 +446,7 @@ end
---@private ---@private
---@param runway Runway ---@param runway Runway
---@param numSections number
---@return Array<RunwaySection> ---@return Array<RunwaySection>
function RunwayStrikeMission:ToSections(runway, numSections) function RunwayStrikeMission:ToSections(runway, numSections)
@@ -240,7 +240,7 @@ function ZoneMission:UpdateState(checkHealth, messageIfDone)
local staticObject = StaticObject.getByName(unitName) local staticObject = StaticObject.getByName(unitName)
if staticObject then if staticObject then
if staticObject:isExist() == true then if staticObject:isExist() == true then
local life0 = staticObject:getDesc().life local life0 = staticObject:getDesc().life --[[@as number]]
if staticObject:getLife() / life0 < 0.3 then if staticObject:getLife() / life0 < 0.3 then
self._logger:debug("exploding unit") self._logger:debug("exploding unit")
trigger.action.explosion(staticObject:getPoint(), 100) trigger.action.explosion(staticObject:getPoint(), 100)
@@ -286,7 +286,9 @@ function ZoneMission:UpdateState(checkHealth, messageIfDone)
end end
if self._missionGroups.hasTargets == true then if self._missionGroups.hasTargets == true then
---@type number
local total = 0 local total = 0
---@type number
local alive = 0 local alive = 0
for _, units in pairs(self._missionGroups.targetsAlive) do for _, units in pairs(self._missionGroups.targetsAlive) do
@@ -299,13 +301,13 @@ function ZoneMission:UpdateState(checkHealth, messageIfDone)
end end
for _, sceneryObject in pairs(self._missionGroups.sceneryTargets) do for _, sceneryObject in pairs(self._missionGroups.sceneryTargets) do
total = total + 1 total = total + 1 --[[@as number]]
if sceneryObject:IsAlive() == true then if sceneryObject:IsAlive() == true then
alive = alive + 1 alive = alive + 1
end end
end end
local deadRatio = (total - alive) / total local deadRatio = (total - alive) / total --[[@as number]]
if deadRatio >= self._completeAtIndex then if deadRatio >= self._completeAtIndex then
self._logger:debug("Dead ratio " .. self.zoneName .. deadRatio .. " >= " .. self._completeAtIndex) self._logger:debug("Dead ratio " .. self.zoneName .. deadRatio .. " >= " .. self._completeAtIndex)
self._state = "COMPLETED" self._state = "COMPLETED"
@@ -477,6 +479,7 @@ function ZoneMission:OnUnitLost(object)
local category = Object.getCategory(object) local category = Object.getCategory(object)
if category == Object.Category.UNIT then if category == Object.Category.UNIT then
object = object --[[@as Unit]]
local unitName = object:getName() local unitName = object:getName()
self._logger:debug("UnitName:" .. unitName) self._logger:debug("UnitName:" .. unitName)
@@ -487,6 +490,7 @@ function ZoneMission:OnUnitLost(object)
self._missionGroups.targetsAlive[groupName][unitName] = false self._missionGroups.targetsAlive[groupName][unitName] = false
end end
elseif category == Object.Category.STATIC then elseif category == Object.Category.STATIC then
object = object --[[@as StaticObject]]
local name = object:getName() local name = object:getName()
self._missionGroups.unitsAlive[name][name] = false self._missionGroups.unitsAlive[name][name] = false
@@ -86,6 +86,7 @@ function Mission:ShowBriefing(groupId)
local unitType = DcsUtil.getUnitTypeFromGroup(group) local unitType = DcsUtil.getUnitTypeFromGroup(group)
local coords = DcsUtil.convertVec2ToUnitUsableType(self.location, unitType) local coords = DcsUtil.convertVec2ToUnitUsableType(self.location, unitType)
if coords == nil then coords = "Could not make conversion" end
self._logger:debug("Coords converted: " .. coords) self._logger:debug("Coords converted: " .. coords)
local stateString = self:ToStateString() local stateString = self:ToStateString()
+50 -19
View File
@@ -40,7 +40,7 @@ do -- INIT DCS_UTIL
---@field zone_type SpearheadTriggerZoneType ---@field zone_type SpearheadTriggerZoneType
---@field properties Array<KeyValuePair>? ---@field properties Array<KeyValuePair>?
---@type Array<SpearheadTriggerZone> ---@type table<string, SpearheadTriggerZone>
DCS_UTIL.__trigger_zones = {} DCS_UTIL.__trigger_zones = {}
end end
@@ -66,12 +66,15 @@ do -- INIT DCS_UTIL
STATIC = 5 --CUSTOM CATEGORY STATIC = 5 --CUSTOM CATEGORY
} }
---@type table<string, string>
DCS_UTIL.__airbaseNamesById = {} DCS_UTIL.__airbaseNamesById = {}
---@type table<string, SpearheadTriggerZone> ---@type table<string, SpearheadTriggerZone>
DCS_UTIL.__airbaseZonesByName = {} DCS_UTIL.__airbaseZonesByName = {}
---@type table<string, CoalitionSide>
DCS_UTIL.__airportsStartingCoalition = {} DCS_UTIL.__airportsStartingCoalition = {}
---@type table<string, CoalitionSide>
DCS_UTIL.__warehouseStartingCoalition = {} DCS_UTIL.__warehouseStartingCoalition = {}
function DCS_UTIL.__INIT() function DCS_UTIL.__INIT()
do -- INITS ALL TABLES WITH DATA THAT's from the MIZ environment do -- INITS ALL TABLES WITH DATA THAT's from the MIZ environment
@@ -104,8 +107,8 @@ do -- INIT DCS_UTIL
if trigger_zone.properties then if trigger_zone.properties then
for _, kvPair in pairs(trigger_zone.properties) do for _, kvPair in pairs(trigger_zone.properties) do
local key = kvPair["key"] local key = kvPair.key
local value = kvPair["value"] local value = kvPair.value
zone.properties[#zone.properties + 1] = { key = key, value = value } zone.properties[#zone.properties + 1] = { key = key, value = value }
end end
end end
@@ -116,6 +119,7 @@ do -- INIT DCS_UTIL
do -- init airports and warehouses do -- init airports and warehouses
if env.warehouses.airports then if env.warehouses.airports then
env.warehouses.airports = env.warehouses.airports --[[@as table<string, any>]]
for warehouse_id, value in pairs(env.warehouses.airports) do for warehouse_id, value in pairs(env.warehouses.airports) do
if warehouse_id ~= nil then if warehouse_id ~= nil then
warehouse_id = tostring(warehouse_id) or "nil" warehouse_id = tostring(warehouse_id) or "nil"
@@ -126,12 +130,12 @@ do -- INIT DCS_UTIL
end end
if env.warehouses.warehouses then if env.warehouses.warehouses then
DCS_UTIL.__warehouseStartingCoalition[-1] = "placeholder" env.warehouses.warehouses = env.warehouses.warehouses --[[@as table<number, any>]]
for warehouse_id, value in pairs(env.warehouses.warehouses) do for warehouse_id, value in pairs(env.warehouses.warehouses) do
if warehouse_id ~= nil then if warehouse_id ~= nil then
warehouse_id = tostring(warehouse_id) or "nil" local warehouse_id_str = tostring(warehouse_id) or "nil"
local coalitionNumber = DCS_UTIL.stringToCoalition(value.coalition) local coalitionNumber = DCS_UTIL.stringToCoalition(value.coalition)
DCS_UTIL.__warehouseStartingCoalition[warehouse_id] = coalitionNumber DCS_UTIL.__warehouseStartingCoalition[warehouse_id_str] = coalitionNumber
end end
end end
end end
@@ -218,11 +222,13 @@ do -- INIT DCS_UTIL
end end
end end
--- takes a list of units and returns all the units that are in any of the zones --- takes a list of units and returns all the units that are in any of the zones
---@param unit_names table unit names ---@param unit_names Array<string> unit names
---@param zone_names table zone names ---@param zone_names Array<string> zone names
---@return table unit list of objects { unit = UNIT, zone_name = zoneName} ---@return table<number, { unit : Unit|StaticObject, zone_name: string }>
function DCS_UTIL.getUnitsInZones(unit_names, zone_names) function DCS_UTIL.getUnitsInZones(unit_names, zone_names)
---@type Array<Unit|StaticObject>
local units = {} local units = {}
---@type Array<SpearheadTriggerZone> ---@type Array<SpearheadTriggerZone>
@@ -241,14 +247,19 @@ do -- INIT DCS_UTIL
zones[#zones + 1] = zone zones[#zones + 1] = zone
end end
end end
---@type table<number, { unit : Unit|StaticObject, zone_name: string }>
local in_zone_units = {} local in_zone_units = {}
for units_ind = 1, #units do for units_ind = 1, #units do
local lUnit = units[units_ind] local lUnit = units[units_ind]
local unit_pos = lUnit:getPosition().p local isActive = true
local lCat = Object.getCategory(lUnit) local lCat = Object.getCategory(lUnit)
if lCat == Object.Category.UNIT then
local unit = lUnit --[[@as Unit]]
isActive = unit:isActive() == true
end
local unit_pos = lUnit:getPosition().p
for _, zone in pairs(zones) do for _, zone in pairs(zones) do
if unit_pos and ((lCat == 1 and lUnit:isActive() == true) or lCat ~= 1) then -- it is a unit and is active or it is not a unit if unit_pos and isActive == true then -- it is a unit and is active or it is not a unit
local isInZone = Util.is3dPointInZone(unit_pos, zone) local isInZone = Util.is3dPointInZone(unit_pos, zone)
if isInZone == true then if isInZone == true then
in_zone_units[#in_zone_units + 1] = { unit = lUnit, zone_name = zone.name } in_zone_units[#in_zone_units + 1] = { unit = lUnit, zone_name = zone.name }
@@ -262,9 +273,9 @@ do -- INIT DCS_UTIL
--- takes a list of groups and returns all the group leaders that are in any of the zones --- takes a list of groups and returns all the group leaders that are in any of the zones
---@param group_names table unit names ---@param group_names table unit names
---@param zone_name string zone names ---@param zone_name string zone names
---@return table groupnames list of group names ---@return Array<string> groupnames list of group names
function DCS_UTIL.getGroupsInZone(group_names, zone_name) function DCS_UTIL.getGroupsInZone(group_names, zone_name)
local zone = DCS_UTIL.__trigger_zones[zone_name] local zone = DCS_UTIL.__trigger_zones[zone_name] --[[@as SpearheadTriggerZone?]]
if zone == nil then if zone == nil then
return {} return {}
end end
@@ -277,6 +288,7 @@ do -- INIT DCS_UTIL
---@param zone SpearheadTriggerZone ---@param zone SpearheadTriggerZone
---@return Array<string> groupnames list of groups that are in the zone ---@return Array<string> groupnames list of groups that are in the zone
function DCS_UTIL.areGroupsInCustomZone(group_names, zone) function DCS_UTIL.areGroupsInCustomZone(group_names, zone)
---@type Array<{ unit : Unit|StaticObject, groupname: string }>
local units = {} local units = {}
if Util.tableLength(group_names) < 1 then return {} end if Util.tableLength(group_names) < 1 then return {} end
@@ -308,8 +320,8 @@ do -- INIT DCS_UTIL
--- takes a x, y poistion and checks if it is inside any of the zones --- takes a x, y poistion and checks if it is inside any of the zones
---@param x number North South position ---@param x number North South position
---@param z number West East position ---@param z number West East position
---@param zone_names table zone names ---@param zone_names Array<string> zone names
---@return table zones list of objects { zone_name = zoneName} ---@return Array<string> zones list of objects { zone_name = zoneName}
function DCS_UTIL.isPositionInZones(x, z, zone_names) function DCS_UTIL.isPositionInZones(x, z, zone_names)
---@type Array<SpearheadTriggerZone> ---@type Array<SpearheadTriggerZone>
local zones = {} local zones = {}
@@ -319,7 +331,7 @@ do -- INIT DCS_UTIL
zones[#zones + 1] = zone zones[#zones + 1] = zone
end end
end end
---@type Array<string>
local result_zones = {} local result_zones = {}
for _, zone in pairs(zones) do for _, zone in pairs(zones) do
if Util.is3dPointInZone({ x = x, z = z, y = 0 }, zone) == true then if Util.is3dPointInZone({ x = x, z = z, y = 0 }, zone) == true then
@@ -396,6 +408,18 @@ do -- INIT DCS_UTIL
return nil; return nil;
end end
---@return Array<string>
function DCS_UTIL.getAllGroupCategoryNames()
return {
"airplane",
"helicopter",
"ground",
"ship",
"train",
"static"
}
end
---@type table<string, CoordType> ---@type table<string, CoordType>
local config = local config =
{ {
@@ -408,7 +432,8 @@ do -- INIT DCS_UTIL
---@param location Vec2 ---@param location Vec2
---@param unitType string ---@param unitType string?
---@return string?
function DCS_UTIL.convertVec2ToUnitUsableType(location, unitType) function DCS_UTIL.convertVec2ToUnitUsableType(location, unitType)
local height = land.getHeight(location) local height = land.getHeight(location)
@@ -429,6 +454,7 @@ do -- INIT DCS_UTIL
---@private ---@private
---@param location Vec3 ---@param location Vec3
---@param coordType CoordType ---@param coordType CoordType
---@return string?
function DCS_UTIL.convertToDisplayCoord(location, coordType) function DCS_UTIL.convertToDisplayCoord(location, coordType)
local lattitude, longitude, altitude = coord.LOtoLL(location) local lattitude, longitude, altitude = coord.LOtoLL(location)
@@ -440,7 +466,7 @@ do -- INIT DCS_UTIL
-- Convert DD to DDM (Degrees Decimal Minutes) -- Convert DD to DDM (Degrees Decimal Minutes)
local function dd_to_ddm(dd) local function dd_to_ddm(dd)
local degrees = math.floor(math.abs(dd)) local degrees = math.floor(math.abs(dd))
local minutes = (math.abs(dd) - degrees) * 60 local minutes = (math.abs(dd) - degrees) * 60 --[[@as number]]
local sign = dd >= 0 and 1 or -1 local sign = dd >= 0 and 1 or -1
return degrees * sign, minutes return degrees * sign, minutes
end end
@@ -559,6 +585,7 @@ do -- INIT DCS_UTIL
end end
---@param group Group ---@param group Group
---@return string? unit type name
function DCS_UTIL.getUnitTypeFromGroup(group) function DCS_UTIL.getUnitTypeFromGroup(group)
for _, unit in pairs(group:getUnits()) do for _, unit in pairs(group:getUnits()) do
if unit and unit:isExist() then if unit and unit:isExist() then
@@ -571,6 +598,7 @@ do -- INIT DCS_UTIL
---comment Get all units that are players ---comment Get all units that are players
---@return Array<Unit> units ---@return Array<Unit> units
function DCS_UTIL.getAllPlayerUnits() function DCS_UTIL.getAllPlayerUnits()
---@type Array<Unit>
local units = {} local units = {}
for i = 0, 2 do for i = 0, 2 do
local players = coalition.getPlayers(i) local players = coalition.getPlayers(i)
@@ -616,6 +644,7 @@ do -- INIT DCS_UTIL
return result return result
end end
---@param unitName string
function DCS_UTIL.CleanCorpse(unitName) function DCS_UTIL.CleanCorpse(unitName)
unitName = "dead_" .. unitName unitName = "dead_" .. unitName
local object = StaticObject.getByName(unitName) local object = StaticObject.getByName(unitName)
@@ -734,6 +763,8 @@ do -- INIT DCS_UTIL
return false return false
end end
---@param groupName string
---@param offset number?
---@return boolean ---@return boolean
function DCS_UTIL.IsBingoFuel(groupName, offset) function DCS_UTIL.IsBingoFuel(groupName, offset)
if offset == nil then offset = 0 end if offset == nil then offset = 0 end
+7 -3
View File
@@ -1,8 +1,12 @@
---@class MissionEditingWarnings ---@class MissionEditingWarnings
local MissionEditingWarnings = {} local MissionEditingWarnings = {}
---@type table<number, string>
MissionEditingWarnings.warnings = {}
function MissionEditingWarnings.Add(warningMessage) function MissionEditingWarnings.Add(warningMessage)
table.insert(MissionEditingWarnings, warningMessage or "skip") table.insert(MissionEditingWarnings.warnings, warningMessage or "skip")
end end
---@param logger Logger ---@param logger Logger
@@ -12,12 +16,12 @@ function MissionEditingWarnings.WriteAll(logger)
return return
end end
if not MissionEditingWarnings or #MissionEditingWarnings == 0 then if not MissionEditingWarnings.warnings or #MissionEditingWarnings.warnings == 0 then
return return
end end
logger:warn("Mission Editor Warnings:") logger:warn("Mission Editor Warnings:")
for _, warning in ipairs(MissionEditingWarnings) do for _, warning in ipairs(MissionEditingWarnings.warnings) do
logger:warn("- " .. warning) logger:warn("- " .. warning)
end end
+36 -13
View File
@@ -22,7 +22,7 @@ do -- INIT UTIL
end end
---comment ---comment
---@param table any ---@param table table<any, any>
---@return number ---@return number
function UTIL.tableLength(table) function UTIL.tableLength(table)
if table == nil then return 0 end if table == nil then return 0 end
@@ -35,23 +35,34 @@ do -- INIT UTIL
---@param orig table ---@param orig table
---@return table copy ---@return table copy
function UTIL.deepCopyTable(orig) function UTIL.deepCopyTable(orig)
local orig_type = type(orig)
---@param original any
---@return any
local function deepCopy(original)
local orig_type = type(original)
---@type any
local copy local copy
if orig_type == 'table' then if orig_type == 'table' then
copy = {} original = original --[[@as table<any, any>]]
for orig_key, orig_value in next, orig, nil do copy = {} --[[@as table<any, any>]]
copy[UTIL.deepCopyTable(orig_key)] = UTIL.deepCopyTable(orig_value) for orig_key, orig_value in pairs(original) do
local copiedKey = deepCopy(orig_key) --[[@as any]]
copy[copiedKey] = deepCopy(orig_value)
end end
setmetatable(copy, UTIL.deepCopyTable(getmetatable(orig))) setmetatable(copy, deepCopy(getmetatable(original)))
else -- number, string, boolean, etc else -- number, string, boolean, etc
copy = orig copy = original --[[@as any]]
end end
return copy return copy
end end
return deepCopy(orig)
end
---Gets a random from the list ---Gets a random from the list
---@param list Array ---@generic T
---@return any @random element from the list ---@param list Array<T>
---@return T @random element from the list
function UTIL.randomFromList(list) function UTIL.randomFromList(list)
local max = #list local max = #list
@@ -65,11 +76,13 @@ do -- INIT UTIL
return list[random] return list[random]
end end
---@param list Array ---@generic T
---@param list Array<T>
---@param start number start ---@param start number start
---@param n number length ---@param n number length
---@return Array ---@return Array<T>
function UTIL.sublist(list, start, n) function UTIL.sublist(list, start, n)
---@type table<number, any>
local result = {} local result = {}
for i = start, n do for i = start, n do
result[#result + 1] = list[i] result[#result + 1] = list[i]
@@ -90,9 +103,10 @@ do -- INIT UTIL
end end
local function table_print(tt, indent, done) local function table_print(tt, indent, done)
done = done or {} done = done or {} --[[@as table<any, boolean>]]
indent = indent or 0 indent = indent or 0
if type(tt) == "table" then if type(tt) == "table" then
tt = tt --[[@as table<any, any>]]
local sb = {} local sb = {}
for key, value in pairs(tt) do for key, value in pairs(tt) do
table.insert(sb, string.rep(" ", indent)) -- indent it table.insert(sb, string.rep(" ", indent)) -- indent it
@@ -146,7 +160,7 @@ do -- INIT UTIL
---comment ---comment
---@param str string ---@param str string
---@param findableTable table ---@param findableTable table<any,any>
---@return boolean ---@return boolean
UTIL.startswithAny = function(str, findableTable) UTIL.startswithAny = function(str, findableTable)
for _, value in pairs(findableTable) do for _, value in pairs(findableTable) do
@@ -244,6 +258,7 @@ do -- INIT UTIL
---@return boolean ---@return boolean
local function isInComplexPolygon(polygon, x, y) local function isInComplexPolygon(polygon, x, y)
---@param poly Array<Vec2> of pairs { x, y } ---@param poly Array<Vec2> of pairs { x, y }
---@return Array<{ x1: number, z1: number, x2: number, z2: number }>
local function getEdges(poly) local function getEdges(poly)
local result = {} local result = {}
for i = 1, #poly do for i = 1, #poly do
@@ -280,6 +295,7 @@ do -- INIT UTIL
---@param point Vec3 ---@param point Vec3
---@param zone SpearheadTriggerZone ---@param zone SpearheadTriggerZone
---@return boolean
function UTIL.is3dPointInZone(point, zone) function UTIL.is3dPointInZone(point, zone)
if zone.zone_type == "Polygon" and zone.verts then if zone.zone_type == "Polygon" and zone.verts then
if UTIL.IsPointInPolygon(zone.verts, point.x, point.z) == true then if UTIL.IsPointInPolygon(zone.verts, point.x, point.z) == true then
@@ -296,6 +312,7 @@ do -- INIT UTIL
---@param point Vec2 ---@param point Vec2
---@param zone SpearheadTriggerZone ---@param zone SpearheadTriggerZone
---@return boolean
function UTIL.is2dPointInZone(point, zone) function UTIL.is2dPointInZone(point, zone)
if zone.zone_type == "Polygon" and zone.verts then if zone.zone_type == "Polygon" and zone.verts then
if UTIL.IsPointInPolygon(zone.verts, point.x, point.y) == true then if UTIL.IsPointInPolygon(zone.verts, point.x, point.y) == true then
@@ -447,6 +464,8 @@ do -- INIT UTIL
end end
---@param points Array<Vec2> ---@param points Array<Vec2>
---@param meters number
---@return Array<Vec2>
function UTIL.enlargeConvexHull(points, meters) function UTIL.enlargeConvexHull(points, meters)
if points == nil or #points == 0 then if points == nil or #points == 0 then
return {} return {}
@@ -524,6 +543,10 @@ function UTIL.GetTangentHullPointsFromOrigin(hull, origin)
return {} return {}
end end
---@param a Vec2
---@param b Vec2
---@param c Vec2
---@return number
local function orientation(a, b, c) local function orientation(a, b, c)
-- Returns >0 if c is to the left of ab, <0 if to the right, 0 if colinear -- Returns >0 if c is to the left of ab, <0 if to the right, 0 if colinear
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)