diff --git a/config.lua b/config.lua index 14af0b5..f463f95 100644 --- a/config.lua +++ b/config.lua @@ -15,7 +15,7 @@ SpearheadConfig = { --quickly enable of disable the entire CAP Logic --(you can also just rename all units to not be named "CAP_") enabled = true, -- default true - + --min ground speed for CAP aircraft during patrol -- unit: knots minSpeed = 400, -- default 400 @@ -62,7 +62,7 @@ SpearheadConfig = { deathDelay = 1800, -- default 1800 }, StageConfig = { - + -- management of stages and its missions. -- This is not related to CAP managers which will continue to work even if stage management is disabled enabled = true, -- default true @@ -98,7 +98,7 @@ SpearheadConfig = { }, Persistence = { --- io and lfs cannot be sanitized in the MissionScripting.lua - + --- enables or disables the persistence logic in spearhead enabled = false, diff --git a/dev/dev_classes.lua b/dev/dev_classes.lua deleted file mode 100644 index 8e2a55b..0000000 --- a/dev/dev_classes.lua +++ /dev/null @@ -1,73 +0,0 @@ - - - ---assert(loadfile("C:\\Repos\\DCS\\Spearhead\\dev\\dev_classes.lua"))() - -local basePath = "C:\\Repos\\DCS\\Spearhead\\" -local classPath = basePath .. "classes\\" - -assert(loadfile(classPath .. "_baseClasses\\Queue.lua"))() - -assert(loadfile(classPath .. "spearhead_base.lua"))() -assert(loadfile(classPath .. "spearhead_routeutil.lua"))() -assert(loadfile(classPath .. "spearhead_events.lua"))() -assert(loadfile(classPath .. "spearhead_db.lua"))() - -assert(loadfile(classPath .. "fleetClasses\\FleetGroup.lua"))() -assert(loadfile(classPath .. "fleetClasses\\GlobalFleetManager.lua"))() - -assert(loadfile(classPath .. "helpers\\MizGroupsManager.lua"))() -assert(loadfile(classPath .. "helpers\\SpawnManager.lua"))() - -assert(loadfile(classPath .. "configuration\\CapConfig.lua"))() -assert(loadfile(classPath .. "configuration\\StageConfig.lua"))() - -assert(loadfile(classPath .. "stageClasses\\GlobalStageManager.lua"))() -assert(loadfile(classPath .. "stageClasses\\missions\\baseMissions\\Mission.lua"))() -assert(loadfile(classPath .. "stageClasses\\missions\\ZoneMission.lua"))() -assert(loadfile(classPath .. "stageClasses\\missions\\RunwayStrikeMission.lua"))() -assert(loadfile(classPath .. "stageClasses\\missions\\BuildableMission.lua"))() - - -assert(loadfile(classPath .. "stageClasses\\Stages\\BaseStage\\Stage.lua"))() -assert(loadfile(classPath .. "stageClasses\\Stages\\PrimaryStage.lua"))() -assert(loadfile(classPath .. "stageClasses\\Stages\\ExtraStage.lua"))() -assert(loadfile(classPath .. "stageClasses\\Stages\\WaitingStage.lua"))() - - -assert(loadfile(classPath .. "stageClasses\\Groups\\SpearheadGroup.lua"))() -assert(loadfile(classPath .. "stageClasses\\Groups\\SpearheadSceneryObject.lua"))() - - -assert(loadfile(classPath .. "stageClasses\\helpers\\MissionCommandsHelper.lua"))() -assert(loadfile(classPath .. "stageClasses\\helpers\\SupplyConfig.lua"))() -assert(loadfile(classPath .. "stageClasses\\helpers\\SupplyUnitsTracker.lua"))() -assert(loadfile(classPath .. "stageClasses\\helpers\\BattleManager.lua"))() - -assert(loadfile(classPath .. "stageClasses\\SpecialZones\\abstract\\BuildableZone.lua"))() -assert(loadfile(classPath .. "stageClasses\\SpecialZones\\StageBase.lua"))() -assert(loadfile(classPath .. "stageClasses\\SpecialZones\\BlueSam.lua"))() -assert(loadfile(classPath .. "stageClasses\\SpecialZones\\FarpZone.lua"))() -assert(loadfile(classPath .. "stageClasses\\SpecialZones\\SupplyHub.lua"))() - -assert(loadfile(classPath .. "capClasses\\taskings\\RTB.lua"))() -assert(loadfile(classPath .. "capClasses\\taskings\\CAP.lua"))() -assert(loadfile(classPath .. "capClasses\\taskings\\SWEEP.lua"))() -assert(loadfile(classPath .. "capClasses\\taskings\\INTERCEPT.lua"))() -assert(loadfile(classPath .. "capClasses\\airGroups\\AirGroup.lua"))() -assert(loadfile(classPath .. "capClasses\\airGroups\\CapGroup.lua"))() -assert(loadfile(classPath .. "capClasses\\airGroups\\SweepGroup.lua"))() -assert(loadfile(classPath .. "capClasses\\airGroups\\InterceptGroup.lua"))() -assert(loadfile(classPath .. "capClasses\\detection\\DetectionManager.lua"))() -assert(loadfile(classPath .. "capClasses\\GlobalCapManager.lua"))() -assert(loadfile(classPath .. "capClasses\\CapAirbase.lua"))() -assert(loadfile(classPath .. "capClasses\\runwayBombing\\RunwayBombingTracker.lua"))() - -assert(loadfile(classPath .. "persistence\\Persistence.lua"))() - --- Startup: - - - -assert(loadfile(basePath .. "main.lua"))() - diff --git a/dev/dev_config.lua b/dev/dev_config.lua deleted file mode 100644 index cc1c608..0000000 --- a/dev/dev_config.lua +++ /dev/null @@ -1,79 +0,0 @@ - -SpearheadConfig = { - - debugEnabled = true, - CapConfig = { - --quickly enable of disable the entire CAP Logic - --(you can also just rename all units to not be named "CAP_") - enabled = true, -- default true - - --min ground speed for CAP aircraft during patrol - -- unit: knots - minSpeed = 400, -- default 400 - - --max speed for CAP aircraft during patrol - -- unit: knots - maxSpeed = 500, -- default 500 - - --minAlt for aircraft on patrol - -- unit: feet - minAlt = 18000, -- default 18000 - - --maxAlt for aircraft on patrol - -- unit: feet - maxAlt = 28000, -- default 28000 - - --Delay for aircraft from touchdown to off the chocks. - -- unit: seconds - rearmDelay = 180, -- default 600 - repairDelay = 600, -- default 600 - --Delay for aircraft from death to takeoff. - --When the seconds remaining is the same at the rearmDelay it will be spawned on the ramp and follow the rearm logic. - -- !! Can not be lower than rearmDelay - -- unit: seconds - deathDelay = 1800, -- default 1800 - }, - StageConfig = { - - -- management of stages and its missions. - -- This is not related to CAP managers which will continue to work even if stage management is disabled - enabled = true, -- default true - - --Will draw the active and the next stage - drawStages = true, -- default true - drawPreActivated = true, - markLastContact = true, - - --AutoStages will continue to the next stage automatically on completion of the missions within the stage. - -- If you want to make it so the next stage triggers only when you want to disable it here and manually implement the actions needed. - --[[ - TODO: Add manual stage transition documentation - ]] - autoStages = true, --default true - - --Maximum missions per stage (includes all types of missions) - maxMissionStage = 100, - - --Stage starting number - startingStage = 1, - - ---DEBUG logging. Consider keeping this disabled - debugEnabled = true - }, - Persistence = { - --- io and lfs cannot be sanitized in the MissionScripting.lua - - --- enables or disables the persistence logic in spearhead - enabled = true, - - --- sets the directory where the persistence file is stored - --- if nil then lfs.writedir() will be used. - --- which will - directory = nil , - - --- the filename of the persistence file. Should end with .json for convention, but any text extension should do. - fileName = "Spearhead_Persistence_Dev" - - } -} - diff --git a/src/classes/capClasses/CapAirbase.lua b/src/classes/capClasses/CapAirbase.lua index 6d73e30..1a5c2d4 100644 --- a/src/classes/capClasses/CapAirbase.lua +++ b/src/classes/capClasses/CapAirbase.lua @@ -95,7 +95,6 @@ function CapBase.new(airbaseName, database, logger, capConfig, runwayBombingTrac SpearheadEvents.AddStageNumberChangedListener(self) timer.scheduleFunction(CheckStateContinuous, self, timer.getTime() + 15) - return self end @@ -152,8 +151,9 @@ end function CapBase:CheckAndScheduleCAP() self.logger:debug("Check taskings for airbase " .. self.airbaseName) - + ---@type table local countPerStage = {} + ---@type table local requiredPerStage = {} local airbase = Airbase.getByName(self.airbaseName) @@ -168,7 +168,7 @@ function CapBase:CheckAndScheduleCAP() if group:IsBackup() == true then local state = group:GetState() if state == "InTransit" or state == "OnStation" or state == "RtbInTen" then - + local supposedTargetZoneID = group:GetZoneIDWhenStageID(activeStageID) local currentTargetZone = group:GetCurrentTargetZoneID() @@ -190,7 +190,7 @@ function CapBase:CheckAndScheduleCAP() end end end - + if countPerStage[supposedTargetZoneID] == nil then countPerStage[supposedTargetZoneID] = 0 end @@ -229,7 +229,7 @@ function CapBase:CheckAndScheduleCAP() countPerStage[supposedZone] = countPerStage[supposedZone] + 1 end elseif state == "InTransit" or state == "OnStation" then - + if supposedZone ~= group:GetCurrentTargetZoneID() then if countPerStage[supposedZone] < requiredPerStage[supposedZone] then local triggerZone = self.database:GetCapZoneForZoneID(supposedZone) @@ -271,7 +271,7 @@ function CapBase:CheckAndScheduleCAP() if triggerZone then group:SendToZone(triggerZone, supposedZone, airbase) end - + countPerStage[supposedZone] = countPerStage[supposedZone] + 1 end end @@ -310,6 +310,7 @@ function CapBase:CheckAndScheduleIntercept() self.logger:debug("Check intercept taskings for airbase " .. self.airbaseName) + ---@type table local interceptZoneIDs = {} local airbase = Airbase.getByName(self.airbaseName) @@ -353,7 +354,7 @@ function CapBase:CheckAndScheduleIntercept() end end end - + ---RATIO. Amount of enemy fighters required per zone before another group gets added. local ratio = 4 -- Ratio of units to intercept per zone, can be adjusted diff --git a/src/classes/capClasses/GlobalCapManager.lua b/src/classes/capClasses/GlobalCapManager.lua index 4e772d7..94c9014 100644 --- a/src/classes/capClasses/GlobalCapManager.lua +++ b/src/classes/capClasses/GlobalCapManager.lua @@ -35,9 +35,8 @@ do for _, airbaseName in pairs(airbaseNames) do if airbaseName then local airbaseSpecificLogger = Logger.new("CAP_" .. airbaseName, logLevel) - + local airbase = CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, runwayBombingTracker, detectionManager, spawnManager) - if airbase then table.insert(airbasesPerStage[stageName], airbase) allAirbasesByName[airbaseName] = airbase diff --git a/src/classes/capClasses/airGroups/CapGroup.lua b/src/classes/capClasses/airGroups/CapGroup.lua index a7ee26c..decd1d8 100644 --- a/src/classes/capClasses/airGroups/CapGroup.lua +++ b/src/classes/capClasses/airGroups/CapGroup.lua @@ -103,7 +103,7 @@ function CapGroup:InitWithName(groupName) return end - + local subsplit = Util.split_string(configPart, "|") if subsplit then @@ -112,8 +112,8 @@ function CapGroup:InitWithName(groupName) local targetZone = keySplit[2] local allActives = string.sub(keySplit[1], 2, #keySplit[1]) local commaSeperated = Util.split_string(allActives, ",") - for _, value in pairs(commaSeperated) do - local dashSeperated = Util.split_string(value, "-") + for _, childValue in pairs(commaSeperated) do + local dashSeperated = Util.split_string(childValue, "-") if Util.tableLength(dashSeperated) > 1 then local from = tonumber(dashSeperated[1]) local till = tonumber(dashSeperated[2]) diff --git a/src/classes/capClasses/airGroups/InterceptGroup.lua b/src/classes/capClasses/airGroups/InterceptGroup.lua index c9afde3..8bdac36 100644 --- a/src/classes/capClasses/airGroups/InterceptGroup.lua +++ b/src/classes/capClasses/airGroups/InterceptGroup.lua @@ -190,7 +190,7 @@ function InterceptGroup:UpdateTask() self:SendRTB(self._airbase) return nil -- Return to base if bingo fuel end - + if selfDetected and self:IsInAir() == true then if self._currentTargetName and self._currentTargetName == closestUnit:getName() then local distance = Util.VectorDistance3d(closestUnit:getPoint(), groupPoint) @@ -213,8 +213,6 @@ function InterceptGroup:UpdateTask() self._currentTargetName = nil end - - local speed = self._config:getMaxSpeed() local interceptPoint = self:GetInterceptPoint(groupPoint, speed, closestUnit) @@ -328,8 +326,8 @@ function InterceptGroup:InitWithName(groupName) local targetZone = keySplit[2] local allActives = string.sub(keySplit[1], 2, #keySplit[1]) local commaSeperated = Util.split_string(allActives, ",") - for _, value in pairs(commaSeperated) do - local dashSeperated = Util.split_string(value, "-") + for _, childValue in pairs(commaSeperated) do + local dashSeperated = Util.split_string(childValue, "-") if Util.tableLength(dashSeperated) > 1 then local from = tonumber(dashSeperated[1]) local till = tonumber(dashSeperated[2]) diff --git a/src/classes/capClasses/airGroups/SweepGroup.lua b/src/classes/capClasses/airGroups/SweepGroup.lua index 05d25af..ee5988a 100644 --- a/src/classes/capClasses/airGroups/SweepGroup.lua +++ b/src/classes/capClasses/airGroups/SweepGroup.lua @@ -77,7 +77,7 @@ function SweepGroup:InitWithName(groupName) local configPart = split_string[2] configPart = string.sub(configPart, 2, #configPart) - + local subsplit = Util.split_string(configPart, "|") if subsplit then for _, value in pairs(subsplit) do @@ -85,8 +85,8 @@ function SweepGroup:InitWithName(groupName) local targetZone = keySplit[2] local allActives = string.sub(keySplit[1], 2, #keySplit[1]) local commaSeperated = Util.split_string(allActives, ",") - for _, value in pairs(commaSeperated) do - local dashSeperated = Util.split_string(value, "-") + for _, childValue in pairs(commaSeperated) do + local dashSeperated = Util.split_string(childValue, "-") if Util.tableLength(dashSeperated) > 1 then local from = tonumber(dashSeperated[1]) local till = tonumber(dashSeperated[2]) diff --git a/src/classes/capClasses/detection/DetectionManager.lua b/src/classes/capClasses/detection/DetectionManager.lua index 50b16b4..5cef8bd 100644 --- a/src/classes/capClasses/detection/DetectionManager.lua +++ b/src/classes/capClasses/detection/DetectionManager.lua @@ -37,7 +37,6 @@ function DetectionManager.New(logger) return time + 10 end timer.scheduleFunction(updateDetected, self, timer.getTime() + 130) - return self end diff --git a/src/classes/capClasses/runwayBombing/RunwayBombingTracker.lua b/src/classes/capClasses/runwayBombing/RunwayBombingTracker.lua index 725d556..f77b958 100644 --- a/src/classes/capClasses/runwayBombing/RunwayBombingTracker.lua +++ b/src/classes/capClasses/runwayBombing/RunwayBombingTracker.lua @@ -30,7 +30,7 @@ function RunwayBombingTracker:OnWeaponFired(_, weapon, _) local desc = weapon:getDesc() local isTrackable = desc.category == Weapon.Category.BOMB or (desc.category == Weapon.Category.MISSILE and desc.missileCategory == Weapon.MissileCategory.CRUISE) if isTrackable == true then - + ---@type WeaponTrackingArgs local weaponTrackingArgs = { weapon = weapon, @@ -61,7 +61,7 @@ function RunwayBombingTracker.trackWeaponTask(weaponTrackingArgs, time) local weapon = weaponTrackingArgs.weapon local self = weaponTrackingArgs.self - + if not weapon or weapon:isExist() == false then return nil end local pos = weapon:getPoint() @@ -83,11 +83,7 @@ function RunwayBombingTracker.trackWeaponTask(weaponTrackingArgs, time) x = pos.x + velocity.x * nextInterval, y = pos.z + velocity.z * nextInterval } - - self:OnWeaponImpact(weapon:getDesc(), impactPoint) - - return nil end diff --git a/src/classes/capClasses/taskings/INTERCEPT.lua b/src/classes/capClasses/taskings/INTERCEPT.lua index e6cdc8d..6c90ec4 100644 --- a/src/classes/capClasses/taskings/INTERCEPT.lua +++ b/src/classes/capClasses/taskings/INTERCEPT.lua @@ -38,7 +38,7 @@ function INTERCEPT.getMissionFromAirbase(groupName, interceptPoint, airbase, con id = 'Mission', params = { airborne = true, - route = { + route = { points = points } } @@ -159,10 +159,10 @@ function INTERCEPT.getInterceptTaskPoint(groupName, currentPoint, targetPoint, a params = { tasks = { id = 'EngageTargetsInZone', - params = { + params = { point = targetPoint, zoneRadius = 10 * 1852, -- 10 NM, point will be updated, so target should be in this zone. - targetTypes = { + targetTypes = { [1] = "Planes", }, priority = 0 @@ -188,10 +188,10 @@ function INTERCEPT.getInterceptTaskPoint(groupName, currentPoint, targetPoint, a params = { tasks = { id = 'EngageTargetsInZone', - params = { + params = { point = targetPoint, zoneRadius = 10 * 1852, -- 10 NM, point will be updated, so target should be in this zone. - targetTypes = { + targetTypes = { [1] = "Planes", }, priority = 0 diff --git a/src/classes/capClasses/taskings/RTB.lua b/src/classes/capClasses/taskings/RTB.lua index 7ebfa5a..6484a91 100644 --- a/src/classes/capClasses/taskings/RTB.lua +++ b/src/classes/capClasses/taskings/RTB.lua @@ -47,7 +47,7 @@ local getRunwayIntoWindCourseRad = function(airbase) else rad = 0 - rad end - + local runwayVec = {x = math.cos(rad), z = math.sin(rad), y = 0} local alignment = Util.vectorAlignment(windVec, runwayVec) @@ -60,14 +60,14 @@ local getRunwayIntoWindCourseRad = function(airbase) do --inverse local degree = math.deg(runway.course) degree = (degree + 180) % 360 - + local rad = math.rad(degree) if rad < 0 then rad = math.abs(rad) else rad = 0 - rad end - + local runwayVec = {x = math.cos(rad), z = math.sin(rad), y = 0} local alignment = Util.vectorAlignment(windVec, runwayVec) diff --git a/src/classes/configuration/StageConfig.lua b/src/classes/configuration/StageConfig.lua index 94590db..54eb580 100644 --- a/src/classes/configuration/StageConfig.lua +++ b/src/classes/configuration/StageConfig.lua @@ -18,7 +18,7 @@ local _logger = Logger.new("StageConfig", Logger.LogLevel) ---@return StageConfig local function new() - if SpearheadConfig == nil then + if SpearheadConfig == nil then _logger:warn("SpearheadConfig is nil, creating default SpearheadConfig") SpearheadConfig = {} end diff --git a/src/classes/fleetClasses/FleetGroup.lua b/src/classes/fleetClasses/FleetGroup.lua index 97eab9d..12b63b3 100644 --- a/src/classes/fleetClasses/FleetGroup.lua +++ b/src/classes/fleetClasses/FleetGroup.lua @@ -4,37 +4,43 @@ local MissionEditorWarning = require("classes.util.MissionEditorWarnings") local RouteUtil = require("classes.spearhead_routeutil") local SpearheadEvents = require("classes.spearhead_events") ----@class FleetGroup +---@class FleetGroup : OnStageChangedListener +---@field private fleetGroupName string +---@field private logger Logger +---@field private fleetNameIdentifier string +---@field private targetZonePerStage table +---@field private currentTargetZone string +---@field private pointsPerZone table local FleetGroup = {} +FleetGroup.__index = FleetGroup ---comment ---@param fleetGroupName string ---@param database Database ---@param logger Logger ----@return nil -function FleetGroup:new(fleetGroupName, database, logger) - local o = {} +---@return FleetGroup? +function FleetGroup.new(fleetGroupName, database, logger) - setmetatable(o, { __index = self }) + local self = setmetatable({}, FleetGroup) - o.fleetGroupName = fleetGroupName - o.logger = logger + self.fleetGroupName = fleetGroupName + self.logger = logger local split_name = Util.split_string(fleetGroupName, "_") if Util.tableLength(split_name) < 2 then MissionEditorWarning.Add("CARRIERGROUP should have at least 2 parts. CARRIERGROUP_") return nil end - o.fleetNameIdentifier = split_name[2] + self.fleetNameIdentifier = split_name[2] - o.targetZonePerStage = {} - o.currentTargetZone = nil - o.pointsPerZone = {} + self.targetZonePerStage = {} + self.currentTargetZone = nil + self.pointsPerZone = {} do --INIT local carrierRouteZones = database:getCarrierRouteZones() for _, zoneName in pairs(carrierRouteZones) do - if Util.strContains(string.lower(zoneName), "_".. string.lower(o.fleetNameIdentifier) .. "_" ) == true then + if Util.strContains(string.lower(zoneName), "_".. string.lower(self.fleetNameIdentifier) .. "_" ) == true then local zone = DcsUtil.getZoneByName(zoneName) if zone and zone.zone_type == DcsUtil.ZoneType.Polygon then local split_string = Util.split_string(zoneName, "_") @@ -43,18 +49,18 @@ function FleetGroup:new(fleetGroupName, database, logger) "CARRIERROUTE should at least have 3 parts. Check the documentation for: " .. zoneName) else - ---@param zone SpearheadTriggerZone + ---@param zoneA SpearheadTriggerZone ---@return Vec2, Vec2 - local function GetTwoFurthestPoints(zone) + local function GetTwoFurthestPoints(zoneA) local biggest = nil - local biggestA = zone.verts[1] - local biggestB = zone.verts[2] + local biggestA = zoneA.verts[1] + local biggestB = zoneA.verts[2] for i = 1, 3 do for ii = i + 1, 4 do - local a = zone.verts[i] - local b = zone.verts[ii] + local a = zoneA.verts[i] + local b = zoneA.verts[ii] local dist = Util.VectorDistance2d(a, b) if biggest == nil or dist > biggest then @@ -100,9 +106,9 @@ function FleetGroup:new(fleetGroupName, database, logger) local first, second = getMinMaxStage(split_string[3]) if first ~= nil and second ~= nil then for i = first, second do - o.targetZonePerStage[tostring(i)] = zoneName + self.targetZonePerStage[tostring(i)] = zoneName end - o.pointsPerZone[zoneName] = { pointA = { x = pointA.x, z = pointA.y, y = 0 }, pointB = { x = pointB.x, z = pointB.y, y = 0} } + self.pointsPerZone[zoneName] = { pointA = { x = pointA.x, z = pointA.y, y = 0 }, pointB = { x = pointB.x, z = pointB.y, y = 0} } else MissionEditorWarning.Add("CARRIERROUTE zone stage numbers not in the format _[-]: " .. zoneName) end @@ -114,32 +120,32 @@ function FleetGroup:new(fleetGroupName, database, logger) end end - local SetTaskAsync = function(input, _) - local targetZone = input.targetZone - local task = input.task - local groupName = input.groupName - local logger = input.logger + SpearheadEvents.AddStageNumberChangedListener(self) + return self +end - local group = Group.getByName(groupName) - if group then - logger:info("Sending " .. groupName .. " to " .. targetZone) - group:getController():setTask(task) - end +local SetTaskAsync = function(input, _) + local targetZone = input.targetZone + local task = input.task + local groupName = input.groupName + local l_logger = input.logger + + local group = Group.getByName(groupName) + if group then + l_logger:info("Sending " .. groupName .. " to " .. targetZone) + group:getController():setTask(task) end +end - o.OnStageNumberChanged = function(self, number, laneIdentifier) - -- only react on "main" lane changes, ignore other lanes for now - if laneIdentifier ~= nil then return end - local targetZone = self.targetZonePerStage[tostring(number)] - if targetZone and targetZone ~= self.currentTargetZone then - local points = self.pointsPerZone[targetZone] - local task = RouteUtil.CreateCarrierRacetrack(points.pointA, points.pointB) - timer.scheduleFunction(SetTaskAsync, { task = task, targetZone = targetZone, groupName = self.fleetGroupName, logger = self.logger }, timer.getTime() + 5) - end +function FleetGroup:OnStageNumberChanged(number, laneIdentifier) + -- only react on "main" lane changes, ignore other lanes for now + if laneIdentifier ~= nil then return end + local targetZone = self.targetZonePerStage[tostring(number)] + if targetZone and targetZone ~= self.currentTargetZone then + local points = self.pointsPerZone[targetZone] + local task = RouteUtil.CreateCarrierRacetrack(points.pointA, points.pointB) + timer.scheduleFunction(SetTaskAsync, { task = task, targetZone = targetZone, groupName = self.fleetGroupName, logger = self.logger }, timer.getTime() + 5) end - - SpearheadEvents.AddStageNumberChangedListener(o) - return o end return FleetGroup diff --git a/src/classes/fleetClasses/GlobalFleetManager.lua b/src/classes/fleetClasses/GlobalFleetManager.lua index 11aa78c..b987dc8 100644 --- a/src/classes/fleetClasses/GlobalFleetManager.lua +++ b/src/classes/fleetClasses/GlobalFleetManager.lua @@ -17,7 +17,7 @@ GlobalFleetManager.start = function(database) for _, groupName in pairs(all_groups) do if Util.startswith(string.lower(groupName), "carriergroup" ) == true then logger:info("Registering " .. groupName .. " as a managed fleet") - local carrierGroup = FleetGroup:new(groupName, database, logger) + local carrierGroup = FleetGroup.new(groupName, database, logger) table.insert(fleetGroups, carrierGroup) end end diff --git a/src/classes/helpers/SpawnManager.lua b/src/classes/helpers/SpawnManager.lua index a3ae9f3..812faf4 100644 --- a/src/classes/helpers/SpawnManager.lua +++ b/src/classes/helpers/SpawnManager.lua @@ -33,7 +33,7 @@ end ---@return StaticObject|Group|nil spawned ---@return boolean isStatic function SpawnManager:SpawnGroup(groupName, overrides, isGroupPersistant) - + local spawnData = MizGroupsManager.getSpawnTemplateData(groupName) if spawnData == nil then @@ -50,7 +50,7 @@ end function SpawnManager:DestroyGroup(groupName) if groupName == nil then return end - + if self:IsGroupStatic(groupName) == true then local object = StaticObject.getByName(groupName) if object ~= nil then @@ -181,7 +181,6 @@ do --- privates return group end - return nil end diff --git a/src/classes/persistence/Persistence.lua b/src/classes/persistence/Persistence.lua index 681151f..9cb886c 100644 --- a/src/classes/persistence/Persistence.lua +++ b/src/classes/persistence/Persistence.lua @@ -89,7 +89,7 @@ do else logger:error("Could not load persistence file, using default tables") end - + if tables.version == nil then tables.version = version end end @@ -114,7 +114,7 @@ do local UpdateContinuous = function(_, time) env.info("[Spearhead][Persistence] Checking up on persistence state...") - if Persistence._updateRequired == true then + if Persistence._updateRequired == true then local status, result = pcall(writeToFile) if status == false then env.error("[Spearhead][Persistence] Could not write state to file: " .. result) @@ -194,7 +194,7 @@ do split[#split+1] = "0" split[#split+1] = "spearhead" end - + fileName = table.concat(split, ".") end @@ -218,12 +218,12 @@ do logger:info("No previous persistence file found, using default: " .. fileName) end - + logger:info("New Persistence file name: " .. tostring(fileName)) local lastPath = dir .. "\\" .. lastFile local path = dir .. "\\" .. fileName Persistence._path = path - + createFileIfNotExists(path) loadTablesFromFile(lastPath) timer.scheduleFunction(UpdateContinuous, nil, timer.getTime() + 120) diff --git a/src/classes/spearhead_db.lua b/src/classes/spearhead_db.lua index 5462572..2c1b1e9 100644 --- a/src/classes/spearhead_db.lua +++ b/src/classes/spearhead_db.lua @@ -258,7 +258,7 @@ function Database.New(Logger) if env.mission.drawings and env.mission.drawings.layers then for _, layer in pairs(env.mission.drawings.layers) do if string.lower(layer.name) == "author" then - for key, layer_object in pairs(layer.objects) do + for _, layer_object in pairs(layer.objects) do if Util.startswith(string.lower(layer_object.name), "stagebriefing_", true) == true then local zone = DcsUtil.getZoneByName(stageZoneName) local vec2 = { x = layer_object.mapX, y = layer_object.mapY } @@ -339,14 +339,14 @@ function Database.New(Logger) end -- fill missions - for key, missionZone in pairs(self._tables.MissionZones) do + for _, missionZone in pairs(self._tables.MissionZones) do if DcsUtil.isZoneInZone(missionZone, stageZoneName) == true then table.insert(stageData.MissionZones, missionZone) end end -- fill random missions - for key, missionZone in pairs(self._tables.RandomMissionZones) do + for _, missionZone in pairs(self._tables.RandomMissionZones) do if DcsUtil.isZoneInZone(missionZone, stageZoneName) == true then table.insert(stageData.RandomMissionZones, missionZone) end @@ -620,9 +620,9 @@ function Database:loadBlueSamUnits() samData.buildingKilos = number if env.mission.drawings and env.mission.drawings.layers then - for i, layer in pairs(env.mission.drawings.layers) do + for _, layer in pairs(env.mission.drawings.layers) do if string.lower(layer.name) == "author" then - for key, 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 } if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then @@ -637,7 +637,7 @@ function Database:loadBlueSamUnits() end end end - else + else MissionEditorWarnings.Add("Buildable number for " .. blueSamZone .. " is invalid") end end @@ -670,13 +670,13 @@ function Database:LoadZoneData(missionZoneName) for _, groupName in pairs(groups) do if MizGroupsManager.IsGroupStatic(groupName) == true then local object = StaticObject.getByName(groupName) - + if object and object:getCoalition() == coalition.side.RED then table.insert(self._tables.MissionZoneData[missionZoneName].RedGroups, groupName) elseif object then table.insert(self._tables.MissionZoneData[missionZoneName].BlueGroups, groupName) end - + else local group = Group.getByName(groupName) if group and group:getCoalition() == coalition.side.RED then @@ -720,9 +720,9 @@ function Database:LoadZoneData(missionZoneName) ---Adds Briefings if env.mission.drawings and env.mission.drawings.layers then - for i, layer in pairs(env.mission.drawings.layers) do + for _, layer in pairs(env.mission.drawings.layers) do if string.lower(layer.name) == "author" then - for key, 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 } if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then @@ -776,9 +776,9 @@ function Database:loadFarpData() -- check briefings if env.mission.drawings and env.mission.drawings.layers then - for i, layer in pairs(env.mission.drawings.layers) do + for _, layer in pairs(env.mission.drawings.layers) do if string.lower(layer.name) == "author" then - for key, 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 } if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then @@ -796,8 +796,6 @@ function Database:loadFarpData() else MissionEditorWarnings.Add("Buildable number for " .. farpZone .. " is invalid.") end - - end end end diff --git a/src/classes/spearhead_events.lua b/src/classes/spearhead_events.lua index 92ec417..ab7f495 100644 --- a/src/classes/spearhead_events.lua +++ b/src/classes/spearhead_events.lua @@ -46,7 +46,7 @@ do ---@class OnStageNumberChangeCompleteListener ---@field OnStageNumberChangeComplete fun(self:OnStageNumberChangeCompleteListener, number:integer, laneIdentifier:string?) - + local OnStageNumberChangeCompleteListeners = {} ---@param listener OnStageNumberChangeCompleteListener SpearheadEvents.AddStageNumberChangeCompleteListener = function(listener) @@ -65,7 +65,7 @@ do end) for _, callable in pairs(OnStageNumberChangedListeners) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnStageNumberChanged(newStageNumber, laneIdentifier) end) if err then @@ -74,14 +74,14 @@ do end for _, callable in pairs(OnStageNumberChangedHandlers) do - local succ, err = pcall(callable, newStageNumber, laneIdentifier) + local _, err = pcall(callable, newStageNumber, laneIdentifier) if err then logError(err) end end for _, callable in pairs(OnStageNumberChangeCompleteListeners) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnStageNumberChangeComplete(newStageNumber, laneIdentifier) end) if err then @@ -112,7 +112,7 @@ do local triggerWeaponFired = function(unit, weapon, target) for _, callable in pairs(onWeaponFiredListeners) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnWeaponFired(unit, weapon, target) end) @@ -121,7 +121,7 @@ do end end end - + local onLandEventListeners = {} ---Add an event listener to a specific unit @@ -186,7 +186,7 @@ do if groupName ~= nil then if OnGroupRTBListeners[groupName] then for _, callable in pairs(OnGroupRTBListeners[groupName]) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnGroupRTB(groupName) end) if err then @@ -221,7 +221,7 @@ do if groupName ~= nil then if OnGroupRTBInTenListeners[groupName] then for _, callable in pairs(OnGroupRTBInTenListeners[groupName]) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnGroupRTBInTen(groupName) end) if err then @@ -257,7 +257,7 @@ do if groupName ~= nil then if OnGroupOnStationListeners[groupName] then for _, callable in pairs(OnGroupOnStationListeners[groupName]) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnGroupOnStation(groupName) end) if err then @@ -286,7 +286,7 @@ do if unit ~= nil then if playerEnterUnitListeners then for _, callable in pairs(playerEnterUnitListeners) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnPlayerEntersUnit(unit) end) if err then @@ -299,7 +299,7 @@ do end do -- Ejection events - + local unitEjectListeners = {} SpearheadEvents.AddOnUnitEjectedListener = function(listener) if type(listener) ~= "table" then @@ -321,7 +321,7 @@ do local name = unit:getName() if onLandEventListeners[name] then for _, callable in pairs(onLandEventListeners[name]) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnUnitLanded(unit, airbase) end) if err then @@ -341,10 +341,10 @@ do if object and object.getName then logDebug("Receiving death event from: " .. object:getName()) end - + if object and object.getName and OnUnitLostListeners[object:getName()] then for _, callable in pairs(OnUnitLostListeners[object:getName()]) do - local succ, err = pcall(function() + local _, err = pcall(function() callable:OnUnitLost(object) end) @@ -356,11 +356,11 @@ do end if event.id == world.event.S_EVENT_EJECTION then - + end if event.id == world.event.S_EVENT_SHOT then - + local shooter = event.initiator local weapon = event.weapon local target = event.target @@ -374,26 +374,26 @@ do local AI_GROUPS = {} - local function CheckAndTriggerSpawnAsync(unit, time) - - local function isPlayer(unit) - if unit == nil then return false, "unit is nil" end - if unit.getGroup == nil then return false, 'no get group function in unit object, most likely static' end - if Object.getCategory(unit) ~= Object.Category.UNIT then + local function CheckAndTriggerSpawnAsync(unit, _) + + local function isPlayer(checkUnit) + 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 Object.getCategory(checkUnit) ~= Object.Category.UNIT then return false, "object is not a unit" end - if unit:isExist() ~= true then return false, "unit does not exist" end - local group = unit:getGroup() + if checkUnit:isExist() ~= true then return false, "unit does not exist" end + local group = checkUnit:getGroup() if group ~= nil then if AI_GROUPS[group:getName()] == true then return false end local players = DcsUtil.getAllPlayerUnits() - local unitName = unit:getName() - for i, unit in pairs(players) do - if unit:getName() == unitName then + local unitName = checkUnit:getName() + for _, playerUnit in pairs(players) do + if playerUnit:getName() == unitName then return true end end @@ -403,7 +403,6 @@ do end if isPlayer(unit) == true then - local groupId = unit:getGroup():getID() SpearheadEvents.TriggerPlayerEntersUnit(unit) end diff --git a/src/classes/stageClasses/GlobalStageManager.lua b/src/classes/stageClasses/GlobalStageManager.lua index 658c9f3..7b08a85 100644 --- a/src/classes/stageClasses/GlobalStageManager.lua +++ b/src/classes/stageClasses/GlobalStageManager.lua @@ -2,7 +2,6 @@ local Events = require("classes.spearhead_events") local Util = require("classes.util.Util") local DcsUtil = require("classes.util.DcsUtil") local Logger = require("classes.util.Logger") -local MissionEditorWarnings = require("classes.util.MissionEditorWarnings") local PersistenceConfig = require("classes.configuration.PersistenceConfig") local ExtraStage = require("classes.stageClasses.Stages.ExtraStage") local PrimaryStage = require("classes.stageClasses.Stages.PrimaryStage") @@ -35,7 +34,6 @@ local singletonInstance = nil ---@param spawnManager SpawnManager ---@return GlobalStageManager function GlobalStageManager.new(database, stageConfig, logLevel, spawnManager) - if singletonInstance ~= nil then return singletonInstance end @@ -44,7 +42,7 @@ function GlobalStageManager.new(database, stageConfig, logLevel, spawnManager) logger:info("Using Stage Log Level: " .. logLevel) local self = setmetatable({}, GlobalStageManager) singletonInstance = self - + self.database = database self.stageConfig = stageConfig self._missionCommandsHelper = MissionCommandsHelper.getOrCreate() @@ -52,14 +50,15 @@ function GlobalStageManager.new(database, stageConfig, logLevel, spawnManager) self.logger = logger if stageConfig.isAutoStages ~= true then - logger:warn("Spearhead will not automatically progress stages due to the given settings. If you manually have implemented this, please ignore this message") + logger:warn( + "Spearhead will not automatically progress stages due to the given settings. If you manually have implemented this, please ignore this message") end Events.AddStageNumberChangedListener(self) for _, stageName in pairs(database:getStagezoneNames()) do logger:debug("Found stage zone with name: " .. stageName) - + local parseResult = self:ParseStageName(stageName) if parseResult.isValid == false then logger:warn("Stage zone with name " .. stageName .. " is not valid: " .. parseResult.invalidReason) @@ -81,12 +80,12 @@ function GlobalStageManager.new(database, stageConfig, logLevel, spawnManager) stage:AddStageCompleteListener(self) self._stageRepository:AddStage(stage) elseif parseResult.stageType == "WaitingStage" then - local waitingStage = WaitingStage.New(database, stageConfig, logger, initData, parseResult.waitingStageSeconds, spawnManager) + local waitingStage = WaitingStage.New(database, stageConfig, logger, initData, + parseResult.waitingStageSeconds, spawnManager) waitingStage:AddStageCompleteListener(self) self._stageRepository:AddStage(waitingStage) end end - end singletonInstance = self @@ -103,11 +102,11 @@ function GlobalStageManager:Start() local stageLanes = self._stageRepository:getAllStageLanes() for _, stageLane in pairs(stageLanes) do - local stageLaneIdentifier = stageLane:GetStageLaneIdentifier() local persistedStage = Persistence.GetActiveStage(stageLaneIdentifier) if persistedStage then - self.logger:info("Loaded persisted stage " .. persistedStage .. " for lane " .. (stageLaneIdentifier or "default")) + self.logger:info("Loaded persisted stage " .. + persistedStage .. " for lane " .. (stageLaneIdentifier or "default")) stageLane:SetActiveStageIndex(persistedStage) Events.PublishStageNumberChanged(persistedStage, stageLaneIdentifier) else @@ -139,17 +138,16 @@ end ---@param stageName string ---@return StageNameParseResult function GlobalStageManager:ParseStageName(stageName) - local split = Util.split_string(stageName, "_") if Util.tableLength(split) < 3 then - return { isValid = false, invalidReason = "Stage zone with name " .. stageName .. " does not have a order number or valid format" } + return { isValid = false, invalidReason = "Stage zone with name " .. + stageName .. " does not have a order number or valid format" } end local typePart = string.lower(split[1]) if typePart == "missionstage" then - local orderNumberString = string.lower(split[2]) ---@type StageType local stageType = "PrimaryStage" @@ -161,15 +159,16 @@ function GlobalStageManager:ParseStageName(stageName) local first = orderNumberString:sub(1, 1) if tonumber(first) == nil then -- first character is the lane identifier only if it's not a number stageLaneIdentifier = string.lower(first) - + orderNumberString = orderNumberString:sub(2) end local orderNumber = tonumber(orderNumberString) if orderNumber == nil then - return { isValid = false, invalidReason = "Stage zone with name " .. stageName .. " does not have a valid order number : " .. orderNumberString } + return { isValid = false, invalidReason = "Stage zone with name " .. + stageName .. " does not have a valid order number : " .. orderNumberString } end - + local stageDisplayName = split[3] ---@type StageNameParseResult local result = { @@ -182,18 +181,19 @@ function GlobalStageManager:ParseStageName(stageName) } return result elseif typePart == "waitingstage" then - local stageType = "WaitingStage" local orderNumberString = split[2] local orderNumber = tonumber(orderNumberString) if orderNumber == nil then - return { isValid = false, invalidReason = "Waiting Stage zone with name " .. stageName .. " does not have a valid order number : " .. orderNumberString } + return { isValid = false, invalidReason = "Waiting Stage zone with name " .. + stageName .. " does not have a valid order number : " .. orderNumberString } end local waitingSecondsString = split[3] local waitingSeconds = tonumber(waitingSecondsString) if waitingSeconds == nil then - return { isValid = false, invalidReason = "Waiting Stage zone with name " .. stageName .. " does not have a valid amount of seconds parameter : " .. waitingSecondsString } + return { isValid = false, invalidReason = "Waiting Stage zone with name " .. + stageName .. " does not have a valid amount of seconds parameter : " .. waitingSecondsString } end local stageDisplayName = "Waiting Stage " .. orderNumber @@ -209,9 +209,9 @@ function GlobalStageManager:ParseStageName(stageName) waitingStageSeconds = waitingSeconds } return result - end - return { isValid = false, invalidReason = "Stage zone with name " .. stageName .. " has an unrecognized type: " .. typePart } + return { isValid = false, invalidReason = "Stage zone with name " .. + stageName .. " has an unrecognized type: " .. typePart } end ---@param stage Stage @@ -223,7 +223,8 @@ function GlobalStageManager:OnStageComplete(stage) local stageLane = self._stageRepository:getStageLane(laneIdentifier) if not stageLane or not stageLane:IsCurrentStageIndexComplete() then - self.logger:debug("Stage lane " .. (laneIdentifier or "default") .. " is not complete for stage index " .. stageIndex) + self.logger:debug("Stage lane " .. + (laneIdentifier or "default") .. " is not complete for stage index " .. stageIndex) return end @@ -234,7 +235,7 @@ function GlobalStageManager:OnStageComplete(stage) stageLane:SetActiveStageIndex(nextStageIndex) if stageLane:IsDefaultStageLane() then - -- COMPLETION IN THE DEFAULT LANE + -- COMPLETION IN THE DEFAULT LANE -- 1. Check if any lane is at status "BetweenChapters" and the next chapter start is "next stage index" local allLanes = self._stageRepository:getAllStageLanes() @@ -242,7 +243,9 @@ function GlobalStageManager:OnStageComplete(stage) if lane:GetStageLaneIdentifier() ~= StageLane.DefaultLaneKey and lane:GetStageLaneState() == "BetweenChapters" then local nextChapterStart = lane:GetNextChapterStart() if nextChapterStart == nextStageIndex then - self.logger:debug("Lane " .. (lane:GetStageLaneIdentifier() or "default") .. " is at chapter start for next stage index " .. nextStageIndex) + self.logger:debug("Lane " .. + (lane:GetStageLaneIdentifier() or "default") .. + " is at chapter start for next stage index " .. nextStageIndex) Events.PublishStageNumberChanged(nextStageIndex, lane:GetStageLaneIdentifier()) lane:SetActiveStageIndex(nextStageIndex) end @@ -256,7 +259,6 @@ function GlobalStageManager:OnStageComplete(stage) if defaultStageLane and defaultStageLane:GetStageLaneState() == "BetweenChapters" then local nextChapterStart = defaultStageLane:GetNextChapterStart() if nextChapterStart == nextStageIndex then - -- 2. Check if all side lanes are at or beyond the next chapter starts local allLanes = self._stageRepository:getAllStageLanes() local allSideLanesReady = true @@ -265,15 +267,19 @@ function GlobalStageManager:OnStageComplete(stage) -- Check if the lane is at or beyond the next chapter starts when "InChapter" eq "Active" if lane:GetStageLaneState() == "InChapter" and lane:GetActiveStageIndex() < nextStageIndex then allSideLanesReady = false - self.logger:debug("Lane " .. (lane:GetStageLaneIdentifier() or "default") .. " is not ready for next stage index " .. nextStageIndex) + self.logger:debug("Lane " .. + (lane:GetStageLaneIdentifier() or "default") .. + " is not ready for next stage index " .. nextStageIndex) break - -- When in between chapters, check if the next chapter start is less than the next stage index, meaning there is still stages to be completed before the main lane can be activated again + -- When in between chapters, check if the next chapter start is less than the next stage index, meaning there is still stages to be completed before the main lane can be activated again elseif lane:GetStageLaneState() == "BetweenChapters" then local nextChapter = lane:GetNextChapterStart() if nextChapter and nextChapter < nextStageIndex then allSideLanesReady = false - self.logger:debug("Lane " .. (lane:GetStageLaneIdentifier() or "default") .. " is not ready for next stage index " .. nextStageIndex) + self.logger:debug("Lane " .. + (lane:GetStageLaneIdentifier() or "default") .. + " is not ready for next stage index " .. nextStageIndex) break end end @@ -281,13 +287,14 @@ function GlobalStageManager:OnStageComplete(stage) end if allSideLanesReady then - self.logger:debug("All side lanes are ready for next stage index " .. nextStageIndex .. ", activating default lane") + self.logger:debug("All side lanes are ready for next stage index " .. + nextStageIndex .. ", activating default lane") Events.PublishStageNumberChanged(nextStageIndex, nil) defaultStageLane:SetActiveStageIndex(nextStageIndex) else - self.logger:debug("Not all side lanes are ready for next stage index " .. nextStageIndex .. ", default lane will not be activated") + self.logger:debug("Not all side lanes are ready for next stage index " .. + nextStageIndex .. ", default lane will not be activated") end - end end end @@ -308,7 +315,6 @@ end ---@public function GlobalStageManager:OnStageNumberChanged(stageNumber, stageLaneIdentifier) - -- only react on "main" lane changes, ignore other lanes for now if stageLaneIdentifier ~= nil then return end @@ -321,7 +327,6 @@ function GlobalStageManager:OnStageNumberChangeComplete(stageNumber, stageLaneId if stageLaneIdentifier ~= nil then return end self.logger:debug("Stage number change complete to: " .. tostring(stageNumber)) - local groups = {} for _, player in pairs(DcsUtil.getAllPlayerUnits()) do @@ -349,80 +354,81 @@ function GlobalStageManager:UpdateDrawings(stageNumber, stageLaneIdentifier) if laneIdentifier == stageLaneIdentifier then if stageNumber >= startStage and stageNumber < stopStage then - self.logger:debug("Drawing " .. drawing:GetName() .. " is active for stage number: " .. tostring(stageNumber)) + self.logger:debug("Drawing " .. + drawing:GetName() .. " is active for stage number: " .. tostring(stageNumber)) drawing:Draw() else - self.logger:debug("Drawing " .. drawing:GetName() .. " is not active for stage number: " .. tostring(stageNumber)) + self.logger:debug("Drawing " .. + drawing:GetName() .. " is not active for stage number: " .. tostring(stageNumber)) drawing:Remove() end end end end - function GlobalStageManager:PrintMermaidStage() local lanes = self._stageRepository:getAllStageLanes() - + local nodes = {} local edges = {} local stageIndicesByLane = {} -- Track all stage indices per lane local mainLaneId = "default" - + -- Color palette for lanes (26 vibrant colors optimized for dark mode) local laneColors = { - "#FF6B6B", -- 1: Red - "#4ECDC4", -- 2: Teal - "#45B7D1", -- 3: Blue - "#FFA502", -- 4: Orange - "#95E1D3", -- 5: Mint - "#F38181", -- 6: Coral - "#AA96DA", -- 7: Purple - "#FCBAD3", -- 8: Pink - "#A8E6CF", -- 9: Light green - "#FFD3B6", -- 10: Peach - "#FFAAA5", -- 11: Light red - "#FF8B94", -- 12: Rose - "#FFEAA7", -- 13: Butter - "#DFE6E9", -- 14: Gray - "#00B894", -- 15: Emerald - "#0984E3", -- 16: Cobalt - "#6C5CE7", -- 17: Indigo - "#A29BFE", -- 18: Lavender - "#FD79A8", -- 19: Magenta - "#FDCB6E", -- 20: Gold - "#6C757D", -- 21: Slate - "#20C997", -- 22: Seafoam - "#E74C3C", -- 23: Scarlet - "#3498DB", -- 24: Dodger blue - "#9B59B6", -- 25: Amethyst - "#1ABC9C", -- 26: Turquoise + "#FF6B6B", -- 1: Red + "#4ECDC4", -- 2: Teal + "#45B7D1", -- 3: Blue + "#FFA502", -- 4: Orange + "#95E1D3", -- 5: Mint + "#F38181", -- 6: Coral + "#AA96DA", -- 7: Purple + "#FCBAD3", -- 8: Pink + "#A8E6CF", -- 9: Light green + "#FFD3B6", -- 10: Peach + "#FFAAA5", -- 11: Light red + "#FF8B94", -- 12: Rose + "#FFEAA7", -- 13: Butter + "#DFE6E9", -- 14: Gray + "#00B894", -- 15: Emerald + "#0984E3", -- 16: Cobalt + "#6C5CE7", -- 17: Indigo + "#A29BFE", -- 18: Lavender + "#FD79A8", -- 19: Magenta + "#FDCB6E", -- 20: Gold + "#6C757D", -- 21: Slate + "#20C997", -- 22: Seafoam + "#E74C3C", -- 23: Scarlet + "#3498DB", -- 24: Dodger blue + "#9B59B6", -- 25: Amethyst + "#1ABC9C", -- 26: Turquoise } local laneColorMap = {} -- Map lane ID to color local colorIndex = 1 - + -- Build nodes and collect all stage indices per lane for _, lane in ipairs(lanes) do local laneId = lane:GetStageLaneIdentifier() or "default" local stageIndices = lane:GetAllStageIndices() stageIndicesByLane[laneId] = stageIndices - + -- Assign color to this lane laneColorMap[laneId] = laneColors[colorIndex] colorIndex = colorIndex + 1 if colorIndex > #laneColors then colorIndex = 1 end - + -- Create nodes for each stage index in this lane for _, stageIndex in ipairs(stageIndices) do local stages = lane:GetStagesAtIndex(stageIndex) - + if stages then for _, stage in ipairs(stages) do local nodeId = laneId .. "_" .. stageIndex local stageType = stage:GetStageType() local stageName = stage.stageName or stage.zoneName - + -- Generate bracket label: [1], [2] for default, [w1], [e2] for other lanes local bracketLabel if laneId == "default" then @@ -430,10 +436,10 @@ function GlobalStageManager:PrintMermaidStage() else bracketLabel = "[" .. laneId .. stageIndex .. "]" end - + -- Combined label: [bracket] Name local label = bracketLabel .. " " .. stageName - + -- Different node shapes for different stage types local nodeShape = "[" local nodeEnd = "]" @@ -444,14 +450,14 @@ function GlobalStageManager:PrintMermaidStage() nodeShape = "[[" nodeEnd = "]]" end - - nodes[nodeId] = string.format(' %s%s"%s"%s', + + nodes[nodeId] = string.format(' %s%s"%s"%s', nodeId, nodeShape, label, nodeEnd) end end end end - + -- Add edges for sequential stages within the same lane for laneId, stageIndices in pairs(stageIndicesByLane) do for i = 1, #stageIndices - 1 do @@ -459,7 +465,7 @@ function GlobalStageManager:PrintMermaidStage() local toIdx = stageIndices[i + 1] local fromNodeId = laneId .. "_" .. fromIdx local toNodeId = laneId .. "_" .. toIdx - + -- Check if this is a chapter boundary (gap) local isChapter = false for _, lane in ipairs(lanes) do @@ -469,12 +475,12 @@ function GlobalStageManager:PrintMermaidStage() break end end - + local label = isChapter and "|chapter|" or "" table.insert(edges, string.format(' %s -->%s %s', fromNodeId, label, toNodeId)) end end - + -- Get main lane reference local mainStageLane = nil for _, lane in ipairs(lanes) do @@ -483,7 +489,7 @@ function GlobalStageManager:PrintMermaidStage() break end end - + -- Add dependencies from DEFAULT lane to SIDE lanes at chapter starts -- Side lanes activate when main completes the stage BEFORE the chapter start if mainStageLane then @@ -491,7 +497,7 @@ function GlobalStageManager:PrintMermaidStage() if lane:IsDefaultStageLane() == false then local sideId = lane:GetStageLaneIdentifier() local sideIndices = stageIndicesByLane[sideId] - + -- For each stage in the side lane for _, stageIdx in ipairs(sideIndices) do -- Check if this is a chapter start in the side lane @@ -506,16 +512,16 @@ function GlobalStageManager:PrintMermaidStage() end end end - + -- Add dependencies from SIDE lanes gating the MAIN lane at chapter boundaries -- Main cannot advance to the next chapter until ALL side lanes are at or above that chapter index if mainStageLane then local mainIndices = stageIndicesByLane[mainLaneId] - + -- For each chapter start in main lane (skip first one) for i = 2, #mainIndices do local nextIdx = mainIndices[i] - + -- Check if nextIdx is a chapter start (there's a gap before it) if mainStageLane:IsChapterStart(nextIdx) then -- Before main can progress to nextIdx, all side lanes must be at >= nextIdx @@ -523,23 +529,23 @@ function GlobalStageManager:PrintMermaidStage() if lane:IsDefaultStageLane() == false then local sideId = lane:GetStageLaneIdentifier() local sideIndices = stageIndicesByLane[sideId] - + -- Find the appropriate gate node for this side lane -- Use first stage >= nextIdx if it exists, otherwise use the highest stage local gateStageIdx = nil - + for _, idx in ipairs(sideIndices) do if idx >= nextIdx then gateStageIdx = idx break end end - + -- If no stage >= nextIdx, use the highest stage in this lane if gateStageIdx == nil and #sideIndices > 0 then gateStageIdx = sideIndices[#sideIndices] end - + if gateStageIdx then local fromNodeId = sideId .. "_" .. gateStageIdx local toNodeId = mainLaneId .. "_" .. nextIdx @@ -550,25 +556,26 @@ function GlobalStageManager:PrintMermaidStage() end end end - + -- Build complete Mermaid diagram - local diagramLines = {"graph TD"} - + local diagramLines = { "graph TD" } + -- Add class definitions for each lane with colors and contrasting text for laneId, color in pairs(laneColorMap) do - table.insert(diagramLines, string.format(' classDef lane_%s fill:%s,stroke:#333,stroke-width:2px,color:#000', laneId, color)) + table.insert(diagramLines, + string.format(' classDef lane_%s fill:%s,stroke:#333,stroke-width:2px,color:#000', laneId, color)) end - + -- Add nodes for _, nodeStr in pairs(nodes) do table.insert(diagramLines, nodeStr) end - + -- Add edges for _, edgeStr in pairs(edges) do table.insert(diagramLines, edgeStr) end - + -- Apply classes to nodes for nodeId in pairs(nodes) do local laneId = nodeId:match("(.+)_[0-9]+$") @@ -576,9 +583,10 @@ function GlobalStageManager:PrintMermaidStage() table.insert(diagramLines, string.format(' class %s lane_%s', nodeId, laneId)) end end - + -- Print as single multi-line message - local diagram = "========== STAGE FLOW DIAGRAM ==========\n" .. table.concat(diagramLines, "\n") .. "\n========== END DIAGRAM ==========" + local diagram = "========== STAGE FLOW DIAGRAM ==========\n" .. + table.concat(diagramLines, "\n") .. "\n========== END DIAGRAM ==========" self.logger:info(diagram) end @@ -586,10 +594,10 @@ end ---@param stageNumber number ---@param stageLaneIdentifier string? nil for default lan ---@return boolean | nil -GlobalStageManager.isStageComplete = function (stageNumber, stageLaneIdentifier) - +GlobalStageManager.isStageComplete = function(stageNumber, stageLaneIdentifier) if singletonInstance == nil then - Logger.new("StageManager", "INFO"):warn("GlobalStageManager.isStageComplete called before GlobalStageManager was initialized. Returning nil") + Logger.new("StageManager", "INFO"):warn( + "GlobalStageManager.isStageComplete called before GlobalStageManager was initialized. Returning nil") return nil end diff --git a/src/classes/stageClasses/Groups/SpearheadGroup.lua b/src/classes/stageClasses/Groups/SpearheadGroup.lua index 0a22e04..c5f8d41 100644 --- a/src/classes/stageClasses/Groups/SpearheadGroup.lua +++ b/src/classes/stageClasses/Groups/SpearheadGroup.lua @@ -41,7 +41,7 @@ end function SpearheadGroup:SpawnCorpsesOnly() if self._isSpawned == true then return end - + self._spawnManager:SpawnCorpsesOnly(self._groupName) self._isSpawned = true @@ -97,7 +97,7 @@ function SpearheadGroup:GetObjects() local result = {} if self._isStatic == true then local staticObject = StaticObject.getByName(self._groupName) - if staticObject then + if staticObject then table.insert(result, staticObject) end else @@ -105,7 +105,7 @@ function SpearheadGroup:GetObjects() if not group then return {} end for _, unit in pairs(group:getUnits()) do table.insert(result, unit) - end + end end return result end @@ -123,7 +123,7 @@ function SpearheadGroup:GetAsUnits() if not group then return {} end for _, unit in pairs(group:getUnits()) do table.insert(result, unit) - end + end return result end @@ -133,7 +133,7 @@ function SpearheadGroup:GetAllUnitPositions() local result = {} if self._isStatic == true then local staticObject = StaticObject.getByName(self._groupName) - if staticObject then + if staticObject then table.insert(result, staticObject:getPoint()) end else @@ -141,7 +141,7 @@ function SpearheadGroup:GetAllUnitPositions() if not group then return {} end for _, unit in pairs(group:getUnits()) do table.insert(result, unit:getPoint()) - end + end end return result end diff --git a/src/classes/stageClasses/SpecialZones/BlueSam.lua b/src/classes/stageClasses/SpecialZones/BlueSam.lua index 1723fec..5e19b78 100644 --- a/src/classes/stageClasses/SpecialZones/BlueSam.lua +++ b/src/classes/stageClasses/SpecialZones/BlueSam.lua @@ -50,16 +50,10 @@ function BlueSam.New(database, logger, zoneName, spawnManager) ---@type table local redUnitsPos = {} - - local buildable = false - if self._buildableCrateKilos and self._buildableCrateKilos > 0 then - buildable = true - end - for _, groupName in pairs(blueSamData.groups) do local spearheadGroup = SpearheadGroup.New(groupName, spawnManager, true) if spearheadGroup then - + if spearheadGroup:GetCoalition() == 2 or spearheadGroup:GetCoalition() == 0 then table.insert(self._blueGroups, spearheadGroup) end @@ -78,7 +72,7 @@ function BlueSam.New(database, logger, zoneName, spawnManager) --Cleanup units local cleanup_distance = 5 - for blueUnitName, blueUnitPos in pairs(blueUnitsPos) do + for _, blueUnitPos in pairs(blueUnitsPos) do for redUnitName, redUnitPos in pairs(redUnitsPos) do local distance = Util.VectorDistance3d(blueUnitPos, redUnitPos) if distance <= cleanup_distance then @@ -140,7 +134,9 @@ end function BlueSam:SpawnGroups() for unitName, needsCleanup in pairs(self._cleanupUnits) do - DcsUtil.DestroyUnit(unitName) + if needsCleanup then + DcsUtil.DestroyUnit(unitName) + end end for _, group in pairs(self._blueGroups) do diff --git a/src/classes/stageClasses/SpecialZones/FarpZone.lua b/src/classes/stageClasses/SpecialZones/FarpZone.lua index 74b329d..b888fd5 100644 --- a/src/classes/stageClasses/SpecialZones/FarpZone.lua +++ b/src/classes/stageClasses/SpecialZones/FarpZone.lua @@ -42,11 +42,11 @@ function FarpZone.New(database, logger, zoneName, spawnManager) self._groups = {} self._padNames = {} self._supplyHubs = {} - + if farpData then self._padNames = farpData.padNames - + for _, supplyHubName in pairs(farpData.supplyHubNames) do local supplyHub = SupplyHub.new(database, logger, supplyHubName) if supplyHub then @@ -55,7 +55,7 @@ function FarpZone.New(database, logger, zoneName, spawnManager) end - for _, groupName in pairs(farpData.groups) do + for _, groupName in pairs(farpData.groups) do local group = SpearheadGroup.New(groupName, spawnManager, true) table.insert(self._groups, group) group:Destroy() diff --git a/src/classes/stageClasses/SpecialZones/StageBase.lua b/src/classes/stageClasses/SpecialZones/StageBase.lua index 552b98f..c738f43 100644 --- a/src/classes/stageClasses/SpecialZones/StageBase.lua +++ b/src/classes/stageClasses/SpecialZones/StageBase.lua @@ -90,7 +90,7 @@ function StageBase.New(databaseManager, logger, airbaseName, spawnManager) local cleanup_distance = 5 - for blueUnitName, blueUnitPos in pairs(blueUnitsPos) do + for _, blueUnitPos in pairs(blueUnitsPos) do for redUnitName, redUnitPos in pairs(redUnitsPos) do local distance = Util.VectorDistance3d(blueUnitPos, redUnitPos) if distance <= cleanup_distance then @@ -172,7 +172,7 @@ function StageBase:ActivateBlueStage() else self:FinaliseBlueStage() end - + end function StageBase:FinaliseBlueStage() diff --git a/src/classes/stageClasses/SpecialZones/SupplyHub.lua b/src/classes/stageClasses/SpecialZones/SupplyHub.lua index c05aba5..b9d49dd 100644 --- a/src/classes/stageClasses/SpecialZones/SupplyHub.lua +++ b/src/classes/stageClasses/SpecialZones/SupplyHub.lua @@ -42,7 +42,7 @@ function SupplyHub.new(database, logger, zoneName) end self._zone = DcsUtil.getZoneByName(zoneName) - + self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate() self._inZone = {} self._missionCommandsHelper = MissionCommandsHelper.getOrCreate() diff --git a/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua b/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua index 38fcada..fe1296f 100644 --- a/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua +++ b/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua @@ -50,7 +50,7 @@ function BuildableZone:New(targetZone, kilosRequired, crateType, buildableGroup if params.unpackedKilos >= params.kilos or spawned == false then return end - + return time + 0.5 end @@ -76,8 +76,6 @@ function BuildableZone:New(targetZone, kilosRequired, crateType, buildableGroup self._buildableMission = nil end - - if self._buildableMission == nil then self._buildableLogger:debug("No buildable mission for zone: " .. targetZone.name) end @@ -99,23 +97,11 @@ function BuildableZone:OnBuildingComplete() end ---@field unpackedItems number ---@field unpackedKilos number ----@param mission BuildableMission? +---@param _ BuildableMission? ---@param kilos number -function BuildableZone:OnCrateDroppedOff(mission, kilos) +function BuildableZone:OnCrateDroppedOff(_, kilos) self._buildableLogger:debug("Crate dropped off in zone: " .. self._targetZone.name) - local timeToUnpack = (kilos / 500) * 15 - - ---@type UnpackCrateParam - local params = { - self = self, - groupsPerKilo = self._groupsPerKilo, - unpackedItems = 0, - kilosPerSecond = kilos/timeToUnpack, - unpackedKilos = 0, - kilos = kilos - } - ---@param params UnpackCrateParam ---@param time number local startUnpackingCrate = function(params, time) @@ -132,10 +118,21 @@ function BuildableZone:OnCrateDroppedOff(mission, kilos) params.self:FinaliseCrate(params.kilos) return end - + return time + 2 end + local timeToUnpack = (kilos / 500) * 15 + ---@type UnpackCrateParam + local params = { + self = self, + groupsPerKilo = self._groupsPerKilo, + unpackedItems = 0, + kilosPerSecond = kilos/timeToUnpack, + unpackedKilos = 0, + kilos = kilos + } + timer.scheduleFunction(startUnpackingCrate, params, timer.getTime() + 2) end @@ -190,7 +187,7 @@ function BuildableZone:SpawnAmount(amount) return nil end - for i = 1, amount do + for _ = 1, amount do local spawned = spawnOne() if spawned ~= true then self._buildableLogger:debug("No more groups to spawn in zone: " .. self._targetZone.name) diff --git a/src/classes/stageClasses/StageRepository.lua b/src/classes/stageClasses/StageRepository.lua index 31f8840..a66ab5e 100644 --- a/src/classes/stageClasses/StageRepository.lua +++ b/src/classes/stageClasses/StageRepository.lua @@ -49,7 +49,6 @@ end function StageRepository:AddStage(stage) local stageLaneIdentifier = stage:GetStageLaneIdentifier() or StageLane.DefaultLaneKey - if self.StageLanes[tostring(stageLaneIdentifier)] == nil then self.StageLanes[tostring(stageLaneIdentifier)] = StageLane.New(stageLaneIdentifier) end diff --git a/src/classes/stageClasses/Stages/BaseStage/Stage.lua b/src/classes/stageClasses/Stages/BaseStage/Stage.lua index 69d2f4f..21bd59c 100644 --- a/src/classes/stageClasses/Stages/BaseStage/Stage.lua +++ b/src/classes/stageClasses/Stages/BaseStage/Stage.lua @@ -105,7 +105,7 @@ function Stage:superNew(database, stageConfig, logger, initData, stageType, miss end self.stageName = initData.stageDisplayName self._stageType = stageType - + self.OnPostStageComplete = nil self.OnPostBlueActivated = nil @@ -160,25 +160,25 @@ function Stage:superNew(database, stageConfig, logger, initData, stageType, miss self._logger:info("Initiating new Stage with name: " .. self.zoneName) ---comment - ---@param self Stage + ---@param selfA Stage ---@param time number? - self.CheckContinuousAsync = function (self, time) - - self:CheckAndUpdateSelf() - if self:IsComplete() == true then - self:NotifyComplete() + self.CheckContinuousAsync = function (selfA, time) + + selfA:CheckAndUpdateSelf() + if selfA:IsComplete() == true then + selfA:NotifyComplete() return nil end return time + 20 end - + do -- load tables local missionZones = database:getMissionsForStage(self.zoneName) self._logger:debug("Found " .. Util.tableLength(missionZones) .. " mission zones for stage: " .. self.zoneName) for _, missionZone in pairs(missionZones) do - + local mission = ZoneMission.new(missionZone, self._missionPriority, database, logger, self, spawnManager) if mission then self._db.missionsByCode[mission.code] = mission @@ -233,7 +233,7 @@ function Stage:superNew(database, stageConfig, logger, initData, stageType, miss table.insert(self._db.missions, mission) end end - else + else self._logger:info("Using persisted random mission with name: " .. missionName .. " and zone: " .. missionZonePicked) for _, mission in pairs(missions) do if string.lower(mission.zoneName) == string.lower(missionZonePicked) then @@ -284,14 +284,14 @@ end function Stage:IsComplete() if self._currentStageState >= StageState.Blue then return true end - for i, mission in pairs(self._db.sams) do + for _, mission in pairs(self._db.sams) do local state = mission:getState() if state == "ACTIVE" or state == "NEW" or state =="WAITING" then return false end end - for i, mission in pairs(self._db.missions) do + for _, mission in pairs(self._db.missions) do local state = mission:getState() if state == "ACTIVE" or state == "NEW" then return false @@ -370,9 +370,9 @@ function Stage:CheckAndUpdateSelf() local availableMissionsCount = Util.tableLength(getAvailableMissions()) local activeCount = getActiveMissionsCount() if activeCount < max and availableMissionsCount > 0 then - for i = activeCount+1, max do + for _ = activeCount+1, max do if availableMissionsCount == 0 then - i = max+1 --exits this loop + break else local mission = Util.randomFromList(getAvailableMissions()) --[[@as Mission]] if mission then @@ -426,7 +426,7 @@ function Stage:PreActivate() end self._currentStageState = StageState.PreActivated - for key, mission in pairs(self._db.sams) do + for _, mission in pairs(self._db.sams) do if mission then mission:SpawnInactive() end @@ -473,7 +473,7 @@ function Stage:MarkStage() drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.INVISIBLE) drawing.style = "no line" end - + return drawing end) self._customDrawing:Draw() @@ -585,12 +585,12 @@ function Stage:OnStageNumberChanged(number, stageLaneIdentifier) if needsBlueActivation() == true then self:ActivateBlueStage() end - + end ---@param self Stage ----@param mission Mission -Stage.OnMissionComplete = function(self, mission) +---@param _ Mission +Stage.OnMissionComplete = function(self, _) self:CheckAndUpdateSelf() end @@ -645,7 +645,7 @@ function Stage:GetStageStats() end end - for _, mission in pairs(self._db.sams) do + for _, _ in pairs(self._db.sams) do dead = dead + 1 end @@ -673,13 +673,13 @@ function Stage:ActivateBlueStage() miscGroup:Spawn() end - ---@param self Stage - local ActivateBlueAsync = function(self) + ---@param selfA Stage + local ActivateBlueAsync = function(selfA) pcall(function() - self:MarkStage() + selfA:MarkStage() end) - self:ActivateBlueGroups() + selfA:ActivateBlueGroups() return nil end diff --git a/src/classes/stageClasses/Stages/ExtraStage.lua b/src/classes/stageClasses/Stages/ExtraStage.lua index 48b56c8..d8dc033 100644 --- a/src/classes/stageClasses/Stages/ExtraStage.lua +++ b/src/classes/stageClasses/Stages/ExtraStage.lua @@ -23,10 +23,9 @@ function ExtraStage.New(database, stageConfig, logger, initData, spawnManager) self:superNew(database, stageConfig, logger, initData, "ExtraStage", "secondary", spawnManager) self.OnPostBlueActivated = function (selfStage) - selfStage:MarkStage() end - + self.OnPostStageComplete = function (selfStage) selfStage:ActivateBlueStage() end @@ -48,7 +47,6 @@ function ExtraStage:OnStageNumberChanged(number, stageLaneIdentifier) return end - local previousActive = self._activeStage self._activeStage = number if self.stageNumber - self._activeStage == self._stageConfig.AmountPreactivateStage then diff --git a/src/classes/stageClasses/Stages/WaitingStage.lua b/src/classes/stageClasses/Stages/WaitingStage.lua index a803a8a..4b722b6 100644 --- a/src/classes/stageClasses/Stages/WaitingStage.lua +++ b/src/classes/stageClasses/Stages/WaitingStage.lua @@ -25,7 +25,7 @@ function WaitingStage.New(database, stageConfig, logger, initData, waitingSecond self._startTime = nil self.CheckContinuousAsync = function (selfA, time) - + if selfA:IsComplete() == true then selfA:NotifyComplete() return nil @@ -47,7 +47,7 @@ function WaitingStage:ActivateStage() timer.scheduleFunction(self.CheckContinuousAsync, self, self._startTime + self._waitTimeSeconds) end -function WaitingStage:IsComplete() +function WaitingStage:IsComplete() if timer.getTime() > (self._startTime + self._waitTimeSeconds) then return true end return false end @@ -56,12 +56,12 @@ function WaitingStage:OnStageNumberChanged() self._logger:debug("Waiting Stage OnStageNumberChanged override") end -function WaitingStage:MarkStage(stageColor) +function WaitingStage:MarkStage(_) self._logger:debug("Waiting Stage MarkStage override") end function WaitingStage:GetExpectedTime() - return self._startTime + self._waitTimeSeconds + return self._startTime + self._waitTimeSeconds end return WaitingStage diff --git a/src/classes/stageClasses/drawings/helper/DrawingHelper.lua b/src/classes/stageClasses/drawings/helper/DrawingHelper.lua index 3911546..aa90234 100644 --- a/src/classes/stageClasses/drawings/helper/DrawingHelper.lua +++ b/src/classes/stageClasses/drawings/helper/DrawingHelper.lua @@ -77,7 +77,7 @@ local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineS end trigger.action.setMarkupColor(drawID, lineColor) trigger.action.setMarkupTypeLine(drawID, lineStyle) - + end ---@private @@ -200,7 +200,7 @@ function DrawingHelper.DrawLine(object) ---@type Array local points = {} - local ids = {} + local ids = {} for _, point in ipairs(object.points) do table.insert(points, { x = object.mapX + point.x, y = 0, z = object.mapY + point.y } ) @@ -264,7 +264,7 @@ function DrawingHelper.ColorTableToColorString(rgba) logger:warn("ColorTableToColorString called with invalid rgba table, returning default color string '0x00000000'") return "0x00000000" end - + local r = string.format("%02X", math.floor(rgba[1] * 255)) local g = string.format("%02X", math.floor(rgba[2] * 255)) local b = string.format("%02X", math.floor(rgba[3] * 255)) diff --git a/src/classes/stageClasses/helpers/BattleManager.lua b/src/classes/stageClasses/helpers/BattleManager.lua index 03d22de..951767a 100644 --- a/src/classes/stageClasses/helpers/BattleManager.lua +++ b/src/classes/stageClasses/helpers/BattleManager.lua @@ -27,8 +27,8 @@ function BattleManager.New(redGroups, blueGroups, name, logLevel) self._redGroups = redGroups self._blueGroups = blueGroups - self._logger:debug("BattleManager created with name: " .. self._name - .. ", red groups: " .. #self._redGroups + self._logger:debug("BattleManager created with name: " .. self._name + .. ", red groups: " .. #self._redGroups .. ", blue groups: " .. #self._blueGroups) return self @@ -131,7 +131,7 @@ function BattleManager:LetUnitsShoot(groups, targetGroups) expendQtyEnabled = true } } - + local controller = unit:getController() if controller then controller:setTask(shootTask) @@ -141,7 +141,7 @@ function BattleManager:LetUnitsShoot(groups, targetGroups) end end end -end +end ---@param unit Unit ---@return number @@ -191,7 +191,7 @@ function BattleManager:IsUnitApplicable(unit) end return true - + end ---@private @@ -231,7 +231,7 @@ end ---@param groupHulls Array> ---@return Vec2? function BattleManager:GetRandomPoint(origin, groupHulls) - + local hull = Util.randomFromList(groupHulls) --[[@as Array]] if not hull then return nil end local shootPoints = Util.GetTangentHullPointsFromOrigin(hull, origin) diff --git a/src/classes/stageClasses/helpers/SupplyLoadConfig.lua b/src/classes/stageClasses/helpers/SupplyLoadConfig.lua index 90b42db..dd0d528 100644 --- a/src/classes/stageClasses/helpers/SupplyLoadConfig.lua +++ b/src/classes/stageClasses/helpers/SupplyLoadConfig.lua @@ -29,7 +29,7 @@ local SupplyLoadConfig = { { centerAngle = 270, angleWidth = 60, minRadius = 15, maxRadius = 50, spacing = 5 }, { centerAngle = 90, angleWidth = 60, minRadius = 15, maxRadius = 50, spacing = 5 }, } - }, + }, ["UH-1H"] = { maxInternalLoad = 2000, dropZones = { diff --git a/src/classes/stageClasses/helpers/SupplyUnitsTracker.lua b/src/classes/stageClasses/helpers/SupplyUnitsTracker.lua index eee35c8..3256f8d 100644 --- a/src/classes/stageClasses/helpers/SupplyUnitsTracker.lua +++ b/src/classes/stageClasses/helpers/SupplyUnitsTracker.lua @@ -236,7 +236,7 @@ function SupplyUnitsTracker:CheckUnitsInZones() end) end end - + else if self._unitInSupplyHub[tostring(unit:getID())] == true then self._unitInSupplyHub[tostring(unit:getID())] = false @@ -290,11 +290,11 @@ local cargoCount = 0 ---@param crateType CrateType ---@param missionCommandsHelper MissionCommandsHelper function SupplyUnitsTracker:UnloadRequested(unitID, crateType, missionCommandsHelper) - + self._logger:debug("Unload requested for unit: " .. unitID .. " crateType: " .. crateType) local unit = DcsUtil.GetPlayerUnitByID(unitID) - if unit == nil or unit:isExist() == false then + if unit == nil or unit:isExist() == false then self._logger:warn("Unload requested for non-existent unit: " .. unitID) return end @@ -303,7 +303,7 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType, missionCommandsHe self._logger:warn("Unload requested for unit with no group: " .. unit:getName()) return end - + local cargoConfig = SupplyConfigHelper.getSupplyConfig(crateType) if cargoConfig == nil then @@ -360,11 +360,11 @@ function SupplyUnitsTracker:UnitRequestCrateLoading(groupID, crateType, missionC end local unit = group:getUnit(1) - + if unit == nil then return end if unit:isExist() == false then return end - + if unit:inAir() == true then trigger.action.outTextForUnit(unit:getID(), "Land first before crates can be loaded", 10) return @@ -381,7 +381,7 @@ function SupplyUnitsTracker:UnitRequestCrateLoading(groupID, crateType, missionC ---@param params LoadCargoParams local LoadCrateTask = function(params) - + local loaded = params.self:TryLoadCrateInUnit(params.unit, params.crateType, params.commandHelper) if loaded ~= false then trigger.action.outTextForUnit(unit:getID(), "Loaded crate :" .. params.crateType, 10) @@ -408,7 +408,7 @@ end ---@param commandHelper MissionCommandsHelper ---@return boolean function SupplyUnitsTracker:TryLoadCrateInUnit(unit, crateType, commandHelper) - + local crateConfigA = SupplyConfigHelper.getSupplyConfig(crateType) if crateConfigA == nil then trigger.action.outTextForUnit(unit:getID(), "Invalid crate type: " .. crateType, 5) @@ -442,7 +442,7 @@ function SupplyUnitsTracker:TryLoadCrateInUnit(unit, crateType, commandHelper) if group == nil then return false end local groupID = group:getID() commandHelper:updateCommandsForGroup(groupID) - + return true end @@ -460,7 +460,7 @@ function SupplyUnitsTracker:UnitRequestCrateSpawn(groupID, crateType) return end - + end end @@ -482,11 +482,11 @@ function SupplyUnitsTracker:GetBoundingBoxes(foundObject) if desc == nil or desc.box == nil then return nil end - + local objPos = foundObject:getPoint() local box = desc.box local heading = 0 - + -- Try to get object heading from position vector's forward direction -- This works for units and other objects that support getPosition pcall(function() @@ -495,13 +495,13 @@ function SupplyUnitsTracker:GetBoundingBoxes(foundObject) heading = math.atan2(objPosition.x.z, objPosition.x.x) end end) - + -- For rotated objects, we need to rotate the bounding box local minX = box.min.x local maxX = box.max.x local minZ = box.min.z local maxZ = box.max.z - + -- If object has significant rotation, apply rotation to bbox corners if math.abs(heading) > 0.1 then -- Get all 4 corners of bbox in local space @@ -511,11 +511,11 @@ function SupplyUnitsTracker:GetBoundingBoxes(foundObject) {maxX, minZ}, {maxX, maxZ} } - + -- Rotate corners and find new min/max minX, maxX = math.huge, -math.huge minZ, maxZ = math.huge, -math.huge - + for _, corner in ipairs(corners) do local rotX = corner[1] * math.cos(heading) - corner[2] * math.sin(heading) local rotZ = corner[1] * math.sin(heading) + corner[2] * math.cos(heading) @@ -525,7 +525,7 @@ function SupplyUnitsTracker:GetBoundingBoxes(foundObject) maxZ = math.max(maxZ, rotZ) end end - + -- Convert relative bbox to world space by adding object position ---@type SupplyUnitsBoundingBox return { @@ -549,7 +549,7 @@ end ---@param safetyMargin number Safety margin around objects ---@return boolean True if collision detected function SupplyUnitsTracker:CheckBBoxCollision(crateBBox, objBBox, safetyMargin) - + -- Apply safety margin to object bbox local objMin = { x = objBBox.min.x - safetyMargin, @@ -561,7 +561,7 @@ function SupplyUnitsTracker:CheckBBoxCollision(crateBBox, objBBox, safetyMargin) y = objBBox.max.y + safetyMargin, z = objBBox.max.z + safetyMargin } - + -- AABB collision detection return crateBBox.min.x <= objMax.x and crateBBox.max.x >= objMin.x and crateBBox.min.y <= objMax.y and crateBBox.max.y >= objMin.y and @@ -575,7 +575,7 @@ end function SupplyUnitsTracker:GetCargoPlacePosition(unit, crateTypeName) local unitPos = unit:getPosition() - + -- Get unit's heading from the forward vector (x component) -- Heading is calculated as: atan2(forward.z, forward.x) local unitHeading = math.atan2(unitPos.x.z, unitPos.x.x) @@ -586,14 +586,14 @@ function SupplyUnitsTracker:GetCargoPlacePosition(unit, crateTypeName) self._logger:error("Could not get bbox for crate type: " .. crateTypeName) return nil end - + local crateRelativeBBox = crateDesc.box -- Get drop zone config for this unit local dropZones = { { centerAngle = 180, angleWidth = 60, minRadius = 15, maxRadius = 50, spacing = 5 } } - + if SupplyLoadConfig[unit:getTypeName()] ~= nil then dropZones = SupplyLoadConfig[unit:getTypeName()].dropZones end @@ -646,15 +646,15 @@ function SupplyUnitsTracker:GetCargoPlacePosition(unit, crateTypeName) for distance = zone.minRadius, zone.maxRadius, zone.spacing do -- Check multiple positions within the angular slice local angleStep = math.min(15, zone.angleWidth / 3) -- Divide slice into sections - + for angle = minAngle, maxAngle, angleStep do local radians = math.rad(angle) - + -- Calculate position at this angle and distance, relative to unit's heading -- Angle 0 = forward, 90 = right, 180 = rear, 270 = left -- Apply unit heading to make angles relative to unit orientation local worldAngle = radians + unitHeading - + local candidateX = unitPos.p.x + distance * math.sin(worldAngle) local candidateZ = unitPos.p.z + distance * math.cos(worldAngle) local candidateY = land.getHeight({ x = candidateX, y = candidateZ }) diff --git a/src/classes/stageClasses/missions/BuildableMission.lua b/src/classes/stageClasses/missions/BuildableMission.lua index cc0b5b7..e90202c 100644 --- a/src/classes/stageClasses/missions/BuildableMission.lua +++ b/src/classes/stageClasses/missions/BuildableMission.lua @@ -25,7 +25,7 @@ local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelpe local BuildableMission = {} BuildableMission.__index = BuildableMission - +---@return string local function getDefaultBriefing(siteType, coords) return "We've dispatched forward units to find a proper spot for a new " .. siteType .. "." .. "\nYou will need to drop off supplies so they can start building." .. @@ -48,7 +48,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi setmetatable(BuildableMission, Mission) local self = setmetatable({}, { __index = BuildableMission }) - + self._targetZone = targetZone self._database = database self._requiredKilos = requiredKilos @@ -75,7 +75,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi end self.code = tostring(database:GetNewMissionCode()) - + local splitTargetZoneName = Util.split_string(targetZone.name, "_") if splitTargetZoneName and splitTargetZoneName[3] and splitTargetZoneName[3] ~= "" then self.name = splitTargetZoneName[3] @@ -83,13 +83,6 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi self.name = "Resupply" end - local type = "site" - if requiredCrateType == "SAM_CRATE" then - type = "SAM site" - elseif requiredCrateType == "FARP_CRATE" then - type = "FARP" - end - self.zoneName = targetZone.name .. "_supply" self._logger = logger self._onCrateDroppedOfListeners = {} @@ -139,7 +132,7 @@ function BuildableMission:ShowBriefing(groupID) briefingPart = getDefaultBriefing(siteType, coords) end - local briefing = "Mission [" .. self.code .. "] " .. self.name .. + local briefing = "Mission [" .. self.code .. "] " .. self.name .. "\n \n" .. briefingPart .. "\n\n" .. @@ -201,7 +194,7 @@ function BuildableMission:SpawnActive() local fillColor2 = DrawingHelper.ColorTableToColorString({ 0, 0, 1, 0}) self._dropOffZoneDrawing = CustomDrawing.FromZone(self._dropOffZone, lineColor2, fillColor2, 2, 6) self._dropOffZoneDrawing:Draw() - + ---@param selfA BuildableMission ---@param time number local checkForCrateTasks = function (selfA, time) @@ -266,8 +259,8 @@ function BuildableMission:CheckCratesInZone() end end end - - for _, foundCrate in pairs(foundCrates) do + + for _, foundCrate in pairs(foundCrates) do local crateConfig = SupplyConfigHelper.fromObjectName(foundCrate:getName()) if crateConfig then self._droppedKilos = self._droppedKilos + crateConfig.weight @@ -282,7 +275,7 @@ function BuildableMission:CheckCratesInZone() self:NotifyMissionComplete() self._state = "COMPLETED" end - + if self._state == "COMPLETED" then for groupID, markID in pairs(self._markIDsPerGroup) do if markID then diff --git a/src/classes/stageClasses/missions/RunwayStrikeMission.lua b/src/classes/stageClasses/missions/RunwayStrikeMission.lua index e3119de..0d6e658 100644 --- a/src/classes/stageClasses/missions/RunwayStrikeMission.lua +++ b/src/classes/stageClasses/missions/RunwayStrikeMission.lua @@ -42,7 +42,7 @@ function RunwayStrikeMission.new(runway, airbaseName, database, logger, runwayBo self._runwayZone = self:RunwayToSpearheadZone(runway) self._repairInProgress = false self._minKilosForDamage = 100 - + local sections = self:ToSections(runway, 5) --[[ +-----------+-----------+-----------+-----------+-----------+ @@ -84,7 +84,6 @@ function RunwayStrikeMission:RunwayHit(impactPoint, explosiveMass) self._logger:debug("Runway hit: " .. self._airportName .. ":" .. self._runway.Name) for _, section in pairs(self._runwaySections) do - local zone = self:SectionToSpearheadZone(section) if Util.is3dPointInZone({ x = impactPoint.x, z = impactPoint.y, y = 0 }, zone) then if section.kilosHit == nil then @@ -96,7 +95,7 @@ function RunwayStrikeMission:RunwayHit(impactPoint, explosiveMass) end ---@param selfA RunwayStrikeMission - local updateState = function(selfA, time) + local updateState = function(selfA, _) selfA:UpdateState() end @@ -154,7 +153,7 @@ function RunwayStrikeMission:Draw() if runwaySection.drawID == nil then local zone = self:SectionToSpearheadZone(runwaySection) - + ---@type Free local drawObject = { primitiveType = "Polygon", @@ -213,7 +212,6 @@ function RunwayStrikeMission:StartRepair() if interval == nil then return nil end return time + interval end - timer.scheduleFunction(repairTask, self, timer.getTime() + 5) end diff --git a/src/classes/stageClasses/missions/ZoneMission.lua b/src/classes/stageClasses/missions/ZoneMission.lua index 8be5f72..c87ce14 100644 --- a/src/classes/stageClasses/missions/ZoneMission.lua +++ b/src/classes/stageClasses/missions/ZoneMission.lua @@ -211,7 +211,7 @@ end ---@return boolean function ZoneMission:AllDependenciesMet() local allDependenciesMet = true - for missionName, value in pairs(self._dependencies) do + for missionName, _ in pairs(self._dependencies) do if self._parentStage:IsMissionComplete(missionName) == false then allDependenciesMet = false self._dependencies[missionName] = false @@ -503,12 +503,12 @@ end ---@param unit Object function ZoneMission:MarkLastContact(unit) - if not unit then + if not unit then self._logger:error("MarkLastContact called with nil unit") return end - local point = unit:getPoint() + local point = unit:getPoint() if not point then self._logger:error("MarkLastContact called with unit without point") return diff --git a/src/classes/stageClasses/missions/baseMissions/Mission.lua b/src/classes/stageClasses/missions/baseMissions/Mission.lua index 2cb4c09..9fdabfb 100644 --- a/src/classes/stageClasses/missions/baseMissions/Mission.lua +++ b/src/classes/stageClasses/missions/baseMissions/Mission.lua @@ -51,7 +51,7 @@ function Mission.newSuper(self, zoneName, missionName, missionType, missionBrief self.location = database:GetLocationForMissionZone(zoneName) self.missionTypeDisplay = self.missionType - + self._missionCommandsHelper = MissionCommandsHelper.getOrCreate() return true, "success" diff --git a/src/classes/util/DcsUtil.lua b/src/classes/util/DcsUtil.lua index c314c0b..a59ffd9 100644 --- a/src/classes/util/DcsUtil.lua +++ b/src/classes/util/DcsUtil.lua @@ -77,7 +77,7 @@ do -- INIT DCS_UTIL do -- INITS ALL TABLES WITH DATA THAT's from the MIZ environment do --init trigger zones - for i, trigger_zone in pairs(env.mission.triggers.zones) do + for _, trigger_zone in pairs(env.mission.triggers.zones) do -- reorder verts as they are not ordered correctly in the ME local verts = {} if Util.tableLength(trigger_zone.verticies) >= 4 then @@ -192,7 +192,7 @@ do -- INIT DCS_UTIL BLUE = 2 } ]] -- - local input = string.lower(input) + input = string.lower(input) if input == 'neutrals' or input == "neutral" or input == "0" then return DCS_UTIL.Coalition.NEUTRAL end @@ -235,7 +235,7 @@ do -- INIT DCS_UTIL end end - for index, zone_name in pairs(zone_names) do + for _, zone_name in pairs(zone_names) do local zone = DCS_UTIL.__trigger_zones[zone_name] if zone then zones[#zones + 1] = zone @@ -247,7 +247,7 @@ do -- INIT DCS_UTIL local lUnit = units[units_ind] local unit_pos = lUnit:getPosition().p local lCat = Object.getCategory(lUnit) - for zone_name, 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 local isInZone = Util.is3dPointInZone(unit_pos, zone) if isInZone == true then @@ -313,7 +313,7 @@ do -- INIT DCS_UTIL function DCS_UTIL.isPositionInZones(x, z, zone_names) ---@type Array local zones = {} - for index, zone_name in pairs(zone_names) do + for _, zone_name in pairs(zone_names) do local zone = DCS_UTIL.__trigger_zones[zone_name] if zone then zones[#zones + 1] = zone @@ -321,7 +321,7 @@ do -- INIT DCS_UTIL end local result_zones = {} - for zone_name, zone in pairs(zones) do + for _, zone in pairs(zones) do if Util.is3dPointInZone({ x = x, z = z, y = 0 }, zone) == true then result_zones[#result_zones + 1] = zone.name end @@ -414,7 +414,7 @@ do -- INIT DCS_UTIL local height = land.getHeight(location) local vec3 = { x = location.x, y = height, z = location.y } - local unitType = string.lower(unitType or "") + unitType = string.lower(unitType or "") local conversionType = config[unitType] if not conversionType then conversionType = "DDM" end @@ -471,7 +471,7 @@ do -- INIT DCS_UTIL lon_hemisphere, math.abs(lon_deg), lon_min_display, lon_sec_display, altitude * 3,28084) end - + end ---@param zone SpearheadTriggerZone @@ -574,7 +574,7 @@ do -- INIT DCS_UTIL local units = {} for i = 0, 2 do local players = coalition.getPlayers(i) - for key, unit in pairs(players) do + for _, unit in pairs(players) do units[#units + 1] = unit end end @@ -617,8 +617,7 @@ do -- INIT DCS_UTIL end function DCS_UTIL.CleanCorpse(unitName) - local unitName = "dead_" .. unitName - + unitName = "dead_" .. unitName local object = StaticObject.getByName(unitName) if object then @@ -632,11 +631,11 @@ do -- INIT DCS_UTIL ---@field b number ---@field a number - local drawID = 4210 + local __drawID = 4210 function DCS_UTIL.GetNextDrawID() - drawID = drawID + 1 - return drawID + __drawID = __drawID + 1 + return __drawID end ---@param groupID number @@ -644,9 +643,9 @@ do -- INIT DCS_UTIL ---@param location Vec3 ---@return number markID function DCS_UTIL.AddMarkToGroup(groupID, text, location) - local drawID = DCS_UTIL.GetNextDrawID() - trigger.action.markToGroup(drawID, text, location, groupID, true, nil) - return drawID + local nextId = DCS_UTIL.GetNextDrawID() + trigger.action.markToGroup(nextId, text, location, groupID, true, nil) + return nextId end ---comment @@ -654,9 +653,9 @@ do -- INIT DCS_UTIL ---@param location Vec3 ---@return integer function DCS_UTIL.AddMarkToAll(text, location) - local drawID = DCS_UTIL.GetNextDrawID() - trigger.action.markToAll(drawID, text, location, true, nil) - return drawID + local nextId = DCS_UTIL.GetNextDrawID() + trigger.action.markToAll(nextId, text, location, true, nil) + return nextId end ---@param markId number @@ -705,7 +704,7 @@ do -- INIT DCS_UTIL ---@return number? id function DCS_UTIL.GetNeutralCountry() - for name, id in pairs(country.id) do + for _, id in pairs(country.id) do if coalition.getCountryCoalition(id) == DCS_UTIL.Coalition.NEUTRAL then return id end @@ -759,7 +758,7 @@ do -- INIT DCS_UTIL function DCS_UTIL.GetPlayerGroupByGroupID(groupId) for i = 0, 2 do local players = coalition.getPlayers(i) - for key, unit in pairs(players) do + for _, unit in pairs(players) do if unit and unit:isExist() == true then local group = unit:getGroup() if group and group:getID() == groupId then @@ -775,7 +774,7 @@ do -- INIT DCS_UTIL function DCS_UTIL.GetPlayerUnitByID(unitID) for i = 0, 2 do local players = coalition.getPlayers(i) - for key, unit in pairs(players) do + for _, unit in pairs(players) do if unit and unit:getID() == unitID then return unit end diff --git a/src/classes/util/Util.lua b/src/classes/util/Util.lua index f8366c4..09c8465 100644 --- a/src/classes/util/Util.lua +++ b/src/classes/util/Util.lua @@ -149,7 +149,7 @@ do -- INIT UTIL ---@param findableTable table ---@return boolean UTIL.startswithAny = function(str, findableTable) - for key, value in pairs(findableTable) do + for _, value in pairs(findableTable) do if type(value) == "string" and UTIL.startswith(str, value) then return true end end return false