Work in progress refactor for toolkit

This commit is contained in:
2026-03-06 19:07:54 +01:00
parent 97f68389d4
commit d77279328e
61 changed files with 1987 additions and 3375 deletions
Vendored
BIN
View File
Binary file not shown.
+3 -1
View File
@@ -1,2 +1,4 @@
**/.DS_Store
.DS_Store
.DS_Store
/dist
+4 -1
View File
@@ -16,5 +16,8 @@
"disableFolding": false
}
},
"livePreview.serverRoot": "/_docs"
"livePreview.serverRoot": "/_docs",
"Lua.workspace.library": [
"/Users/ex61wi/Developer/personal/DcsMissionScriptingTools/dutchies-dcs-scripting-tools/lua-addons"
]
}
-1349
View File
File diff suppressed because it is too large Load Diff
@@ -1,22 +0,0 @@
local GlobalFleetManager = {}
local fleetGroups = {}
GlobalFleetManager.start = function(database)
local logger = Spearhead.LoggerTemplate.new("CARRIERFLEET", "INFO")
local all_groups = Spearhead.classes.helpers.MizGroupsManager.getAllGroupNames()
for _, groupName in pairs(all_groups) do
if Spearhead.Util.startswith(string.lower(groupName), "carriergroup" ) == true then
logger:info("Registering " .. groupName .. " as a managed fleet")
local carrierGroup = Spearhead.internal.FleetGroup:new(groupName, database, logger)
table.insert(fleetGroups, carrierGroup)
end
end
end
if not Spearhead.internal then Spearhead.internal = {} end
Spearhead.internal.GlobalFleetManager = GlobalFleetManager
-82
View File
@@ -1,82 +0,0 @@
--Single player purpose
local defaultLogLevel = "INFO"
if SpearheadConfig and SpearheadConfig.debugEnabled == true then
defaultLogLevel = "DEBUG"
end
local startTime = timer.getTime() * 1000
Spearhead.Events.Init(defaultLogLevel)
local dbLogger = Spearhead.LoggerTemplate.new("database", defaultLogLevel)
local standardLogger = Spearhead.LoggerTemplate.new("", defaultLogLevel)
local databaseManager = Spearhead.DB.New(dbLogger)
Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(defaultLogLevel) -- initiate
local capConfig = Spearhead.internal.configuration.CapConfig:new();
local stageConfig = Spearhead.internal.configuration.StageConfig:new();
local startingStage = stageConfig.startingStage or 1
if SpearheadConfig and SpearheadConfig.Persistence and SpearheadConfig.Persistence.enabled == true then
standardLogger:info("Persistence enabled")
local persistenceLogger = Spearhead.LoggerTemplate.new("Persistence", defaultLogLevel)
Spearhead.classes.persistence.Persistence.Init(persistenceLogger)
local persistanceStage = Spearhead.classes.persistence.Persistence.GetActiveStage()
if persistanceStage then
standardLogger:info("Persistance activated and using persistant active stage: " .. persistanceStage)
startingStage = persistanceStage
end
else
standardLogger:info("Persistence disabled")
end
local spawnLogger = Spearhead.LoggerTemplate.new("SpawnManager", defaultLogLevel)
local spawnManager = Spearhead.classes.helpers.SpawnManager.new(spawnLogger)
local detectionLogger = Spearhead.LoggerTemplate.new("DetectionManager", defaultLogLevel)
local detectionManager = Spearhead.classes.capClasses.detection.DetectionManager.New(detectionLogger)
Spearhead.classes.capClasses.GlobalCapManager.start(databaseManager, capConfig, detectionManager, stageConfig, defaultLogLevel, spawnManager)
Spearhead.internal.GlobalStageManager.NewAndStart(databaseManager, stageConfig, defaultLogLevel, spawnManager)
Spearhead.internal.GlobalFleetManager.start(databaseManager)
local SetStageDelayed = function(number, time)
Spearhead.Events.PublishStageNumberChanged(number)
return nil
end
timer.scheduleFunction(SetStageDelayed, startingStage, timer.getTime() + 3)
env.info(startTime .. "ms / " .. timer.getTime() * 1000 .. "ms")
local duration = (timer.getTime() * 1000) - startTime
standardLogger:info("Spearhead Initialisation duration: " .. tostring(duration) .. "ms")
Spearhead.LoadingDone()
Spearhead.internal.GlobalStageManager:printFullOverview()
--Check lines of code in directory per file:
-- Get-ChildItem . -Include *.lua -Recurse | foreach {""+(Get-Content $_).Count + " => " + $_.name }; GCI . -Include *.lua* -Recurse | foreach{(GC $_).Count} | measure-object -sum | % Sum
-- find . -name '*.lua' | xargs wc -l
--- ==================== DEBUG ORDER OR ZONE VEC ===========================
-- local zone = Spearhead.DcsUtil.getZoneByName("MISSIONSTAGE_99")
-- local count = Spearhead.Util.tableLength(zone.verts)
-- for i = 1, count - 1 do
-- local a = zone.verts[i]
-- local b = zone.verts[i+1]
-- local color = {0,0,0,1}
-- color[i] = 1
-- trigger.action.textToAll(-1, 46+i , { x= a.x, y = 0, z = a.z } , color, {0,0,0}, 24 , true , "" .. i )
-- trigger.action.lineToAll(-1 , 56+i , { x= a.x, y = 0, z = a.z } , { x = b.x, y = 0, z = b.z } , color , 1, true)
-- end
@@ -44,7 +44,4 @@ function Queue:toList()
return items
end
if Spearhead == nil then Spearhead = {} end
if Spearhead._baseClasses == nil then Spearhead._baseClasses = {} end
Spearhead._baseClasses.Queue = Queue
return Queue
@@ -1,3 +1,6 @@
local SpearheadEvents = require("classes.spearhead_events")
local GlobalStageManager = require("classes.stageClasses.GlobalStageManager")
---@type Array<OnMissionCompleteListener>
local MissionCompleteListeners = {}
@@ -16,18 +19,18 @@ SpearheadAPI = {
return false, "stageNumber " .. stageNumber .. " is not a valid number"
end
Spearhead.Events.PublishStageNumberChanged(stageNumber)
SpearheadEvents.PublishStageNumberChanged(stageNumber)
return true, ""
end,
getCurrentStage = function()
return Spearhead.StageNumber or nil
return GlobalStageManager.getCurrentStage() or nil
end,
isStageComplete = function(stageNumber)
if type(stageNumber) ~= "number" then
return false, "stageNumber " .. stageNumber .. " is not a valid number"
end
local isComplete = Spearhead.internal.GlobalStageManager.isStageComplete(stageNumber)
local isComplete = GlobalStageManager.isStageComplete(stageNumber)
if isComplete == nil then
return nil, "no stage found with number " .. stageNumber
end
@@ -1,3 +1,11 @@
local Util = require("classes.util.Util")
local CapGroup = require("classes.capClasses.airGroups.CapGroup")
local SweepGroup = require("classes.capClasses.airGroups.SweepGroup")
local InterceptGroup = require("classes.capClasses.airGroups.InterceptGroup")
local RunwayBombingTracker = require("classes.capClasses.runwayBombing.RunwayBombingTracker")
local SpearheadEvents = require("classes.util.SpearheadEvents")
local RunwayStrikeMission = require("classes.stageClasses.missions.RunwayStrikeMission")
---@class CapBase : OnStageChangedListener
---@field private airbaseName string
---@field private logger table
@@ -54,7 +62,7 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw
local baseData = database:getAirbaseDataForZone(airbaseName)
if baseData and baseData.CapGroups then
for key, name in pairs(baseData.CapGroups) do
local capGroup = Spearhead.classes.capClasses.airGroups.CapGroup.New(name, capConfig, logger, spawnManager)
local capGroup = CapGroup.New(name, capConfig, logger, spawnManager)
if capGroup then
self.capGroupsByName[name] = capGroup
end
@@ -63,7 +71,7 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw
if baseData and baseData.SweepGroups then
for key, name in pairs(baseData.SweepGroups) do
local sweepGroup = Spearhead.classes.capClasses.airGroups.SweepGroup.New(name, capConfig, logger, spawnManager)
local sweepGroup = SweepGroup.New(name, capConfig, logger, spawnManager)
if sweepGroup then
self.sweepGroupsByName[name] = sweepGroup
end
@@ -72,22 +80,21 @@ function CapBase.new(airbaseName, database, logger, capConfig, stageConfig, runw
if baseData and baseData.InterceptGroups then
for key, name in pairs(baseData.InterceptGroups) do
local interceptGroup = Spearhead.classes.capClasses.airGroups.InterceptGroup.New(name, capConfig, logger, detectionManager, spawnManager)
local interceptGroup = InterceptGroup.New(name, capConfig, logger, detectionManager, spawnManager)
if interceptGroup then
self.interceptGroupsByName[name] = interceptGroup
end
end
end
local capFlights = Spearhead.Util.tableLength(self.capGroupsByName)
local sweepFlights = Spearhead.Util.tableLength(self.sweepGroupsByName)
local interceptFlights = Spearhead.Util.tableLength(self.interceptGroupsByName)
local capFlights = Util.tableLength(self.capGroupsByName)
local sweepFlights = Util.tableLength(self.sweepGroupsByName)
local interceptFlights = Util.tableLength(self.interceptGroupsByName)
logger:info(airbaseName .. " : " .. capFlights .." CAP | " .. sweepFlights .. " SWEEP | " .. interceptFlights .. " INTERCEPT")
self:CreateRunwayStrikeMission(database)
Spearhead.Events.AddStageNumberChangedListener(self)
SpearheadEvents.AddStageNumberChangedListener(self)
timer.scheduleFunction(CheckStateContinuous, self, timer.getTime() + 15)
@@ -111,7 +118,7 @@ function CapBase:CreateRunwayStrikeMission(database)
" at airbase " ..
self.airbaseName ..
" with heading " .. runway.course .. " and length " .. runway.length .. " and width " .. runway.width)
local mission = Spearhead.classes.stageClasses.missions.RunwayStrikeMission.new(runway, self.airbaseName,
local mission = RunwayStrikeMission.new(runway, self.airbaseName,
database, self.logger, self.runwayBombingTracker)
self.runwayStrikeMissions[runway.Name] = mission
end
@@ -338,7 +345,7 @@ function CapBase:CheckAndScheduleIntercept()
local unit = Unit.getByName(unitName)
if unit and unit:isExist() then
local unitPos = unit:getPoint()
if Spearhead.Util.is3dPointInZone(unitPos, zone) == true then
if Util.is3dPointInZone(unitPos, zone) == true then
if not unitsToInterceptPerZone[zone.name] then
unitsToInterceptPerZone[zone.name] = {}
end
@@ -356,7 +363,7 @@ function CapBase:CheckAndScheduleIntercept()
for name, targets in pairs(unitsToInterceptPerZone) do
local required = 0
local nrTargets = Spearhead.Util.tableLength(targets)
local nrTargets = Util.tableLength(targets)
if targets and nrTargets > 0 then
required = math.ceil(nrTargets / ratio)
end
@@ -424,7 +431,4 @@ function CapBase:IsBaseActiveWhenStageIsActive(stageNumber)
return false
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
Spearhead.classes.capClasses.CapAirbase = CapBase
return CapBase
@@ -1,3 +1,9 @@
local Logger = require("classes.util.Logger")
local Util = require("classes.util.Util")
local RunwayBombingTracker = require("classes.capClasses.runwayBombing.RunwayBombingTracker")
local CapAirbase = require("classes.capClasses.CapAirbase")
---@class GlobalCapManager
local GlobalCapManager = {}
do
local airbasesPerStage = {}
@@ -17,9 +23,9 @@ do
function GlobalCapManager.start(database, capConfig, detectionManager, stageConfig, logLevel, spawnManager)
if initiated == true then return end
local logger = Spearhead.LoggerTemplate.new("AirbaseManager", logLevel)
local bombTrackLogger = Spearhead.LoggerTemplate.new("RunwayBombingTracker", logLevel)
local runwayBombingTracker = Spearhead.classes.capClasses.runwayBombing.RunwayBombingTracker.new(bombTrackLogger)
local logger = Logger.new("AirbaseManager", logLevel)
local bombTrackLogger = Logger.new("RunwayBombingTracker", logLevel)
local runwayBombingTracker = RunwayBombingTracker.new(bombTrackLogger)
local zones = database:getStagezoneNames()
if zones then
@@ -32,9 +38,9 @@ do
if airbaseNames then
for _, airbaseName in pairs(airbaseNames) do
if airbaseName then
local airbaseSpecificLogger = Spearhead.LoggerTemplate.new("CAP_" .. airbaseName, logLevel)
local airbaseSpecificLogger = Logger.new("CAP_" .. airbaseName, logLevel)
local airbase = Spearhead.classes.capClasses.CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig, runwayBombingTracker, detectionManager, spawnManager)
local airbase = CapAirbase.new(airbaseName, database, airbaseSpecificLogger, capConfig, stageConfig, runwayBombingTracker, detectionManager, spawnManager)
if airbase then
table.insert(airbasesPerStage[stageName], airbase)
@@ -46,16 +52,14 @@ do
end
end
logger:info("Initiated " .. Spearhead.Util.tableLength(allAirbasesByName) .. " airbases for cap")
logger:info("Initiated " .. Util.tableLength(allAirbasesByName) .. " airbases for cap")
initiated = true
local InfoFunctions = {}
---returns if there is CAP active
---@param zoneName any
---@param activeZoneNumber number
---@return boolean
InfoFunctions.IsCapActiveWhenZoneIsActive = function(zoneName, activeZoneNumber)
GlobalCapManager.IsCapActiveWhenZoneIsActive = function(zoneName, activeZoneNumber)
for _, airbase in pairs(airbasesPerStage[zoneName]) do
if airbase:IsBaseActiveWhenStageIsActive(activeZoneNumber) == true then
return true
@@ -63,14 +67,7 @@ do
end
return false
end
Spearhead.capInfo = InfoFunctions
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
Spearhead.classes.capClasses.GlobalCapManager = GlobalCapManager
return GlobalCapManager
@@ -1,3 +1,8 @@
local SpearheadEvents = require("classes.spearhead_events")
local RTBMission = require("classes.capClasses.taskings.RTB")
local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
---@class AirGroup : OnUnitLostListener
---@field protected _logger Logger
---@field protected _groupName string
@@ -26,13 +31,13 @@ function AirGroup:New(groupName, groupType, config, logger, spawnManager)
local group = Group.getByName(self._groupName)
if group then
Spearhead.Events.addOnGroupRTBListener(self._groupName, self)
Spearhead.Events.addOnGroupRTBInTenListener(self._groupName, self)
Spearhead.Events.addOnGroupOnStationListener(self._groupName, self)
SpearheadEvents.addOnGroupRTBListener(self._groupName, self)
SpearheadEvents.addOnGroupRTBInTenListener(self._groupName, self)
SpearheadEvents.addOnGroupOnStationListener(self._groupName, self)
for _, unit in pairs(group:getUnits()) do
Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self)
Spearhead.Events.addOnUnitLandEventListener(unit:getName(), self)
SpearheadEvents.addOnUnitLostEventListener(unit:getName(), self)
SpearheadEvents.addOnUnitLandEventListener(unit:getName(), self)
end
spawnManager:DestroyGroup(groupName)
@@ -105,7 +110,7 @@ function AirGroup:SendRTB(airbase)
end
end
if location then
local mission = Spearhead.classes.capClasses.taskings.RTB.getAsMission(airbase, { x= location.x, y= location.z }, self._config)
local mission = RTBMission.getAsMission(airbase, { x= location.x, y= location.z }, self._config)
group:getController():setTask(mission)
self._logger:debug("AirGroup:SendRTB - Task set for group: " .. self._groupName)
end
@@ -248,7 +253,7 @@ function AirGroup:OnLastUnitLanded()
return time + 5
end
if pos and Spearhead.Util.VectorDistance3d(pos, data.lastLocations[unit:getName()]) > 10 then
if pos and Util.VectorDistance3d(pos, data.lastLocations[unit:getName()]) > 10 then
data.lastChangeTime = time
end
data.lastLocations[unit:getName()] = pos
@@ -426,14 +431,10 @@ do --EVENT LISTENERS
end
function AirGroup:Destroy()
Spearhead.DcsUtil.DestroyGroup(self._groupName)
self._spawnManager:DestroyGroup(self._groupName)
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.airGroups then Spearhead.classes.capClasses.airGroups = {} end
Spearhead.classes.capClasses.airGroups.AirGroup = AirGroup
return AirGroup
---@alias AirGroupState
---| "UnSpawned"
@@ -1,3 +1,7 @@
local AirGroup = require("classes.capClasses.airGroups.AirGroup")
local CAP = require("classes.capClasses.taskings.CAP")
local Util = require("classes.util.Util")
local MissionEditorWarner = require("classes.util.MissionEditorWarnings")
---@class CapGroup : AirGroup
---@field private _targetZoneIdPerStage table<string, string>
@@ -14,9 +18,9 @@ CapGroup.__index = CapGroup
---@return CapGroup
function CapGroup.New(groupName, config, logger, spawnManager)
setmetatable(CapGroup, Spearhead.classes.capClasses.airGroups.AirGroup)
setmetatable(CapGroup, AirGroup)
local self = setmetatable({}, CapGroup) --[[@as CapGroup]]
Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "CAP", config, logger, spawnManager)
AirGroup.New(self, groupName, "CAP", config, logger, spawnManager)
self._targetZoneIdPerStage = {}
@@ -65,10 +69,10 @@ function CapGroup:SendToZone(zone, targetZoneID, airbase)
end
if isInAir == true then
local mission = Spearhead.classes.capClasses.taskings.CAP.getAsMission(self._groupName, airbase, zone, self._config)
local mission = CAP.getAsMission(self._groupName, airbase, zone, self._config)
self:SetMission(mission)
else
local mission = Spearhead.classes.capClasses.taskings.CAP.getAsMissionFromAirbase(self._groupName, airbase, zone, self._config)
local mission = CAP.getAsMissionFromAirbase(self._groupName, airbase, zone, self._config)
if mission then
self:SetMission(mission)
else
@@ -80,8 +84,8 @@ end
---@private
function CapGroup:InitWithName(groupName)
local split_string = Spearhead.Util.split_string(groupName, "_")
local partCount = Spearhead.Util.tableLength(split_string)
local split_string = Util.split_string(groupName, "_")
local partCount = Util.tableLength(split_string)
if partCount >= 3 then
local configPart = split_string[2]
@@ -95,34 +99,34 @@ function CapGroup:InitWithName(groupName)
elseif first == "[" then
self._isBackup = false
else
Spearhead.AddMissionEditorWarning("Could not parse the CAP config for group: " .. groupName)
MissionEditorWarner.Add("Could not parse the CAP config for group: " .. groupName)
return
end
local subsplit = Spearhead.Util.split_string(configPart, "|")
local subsplit = Util.split_string(configPart, "|")
if subsplit then
for key, value in pairs(subsplit) do
local keySplit = Spearhead.Util.split_string(value, "]")
local keySplit = Util.split_string(value, "]")
local targetZone = keySplit[2]
local allActives = string.sub(keySplit[1], 2, #keySplit[1])
local commaSeperated = Spearhead.Util.split_string(allActives, ",")
local commaSeperated = Util.split_string(allActives, ",")
for _, value in pairs(commaSeperated) do
local dashSeperated = Spearhead.Util.split_string(value, "-")
if Spearhead.Util.tableLength(dashSeperated) > 1 then
local dashSeperated = Util.split_string(value, "-")
if Util.tableLength(dashSeperated) > 1 then
local from = tonumber(dashSeperated[1])
local till = tonumber(dashSeperated[2])
for i = from, till do
if Spearhead.Util.strContains(targetZone, "A") == true then
if Util.strContains(targetZone, "A") == true then
self._targetZoneIdPerStage[tostring(i)] = string.gsub(targetZone, "A", tostring(i))
else
self._targetZoneIdPerStage[tostring(i)] = targetZone
end
end
else
if Spearhead.Util.strContains(targetZone, "A") == true then
if Util.strContains(targetZone, "A") == true then
self._targetZoneIdPerStage[tostring(dashSeperated[1])] = string.gsub(targetZone, "A", tostring(dashSeperated[1]))
else
self._targetZoneIdPerStage[tostring(dashSeperated[1])] = targetZone
@@ -132,15 +136,11 @@ function CapGroup:InitWithName(groupName)
end
end
env.info("Capgroup parsed with table: " .. Spearhead.Util.toString(self._targetZoneIdPerStage))
env.info("Capgroup parsed with table: " .. Util.toString(self._targetZoneIdPerStage))
else
Spearhead.AddMissionEditorWarning("CAP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount)
MissionEditorWarner.Add("CAP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount)
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.airGroups then Spearhead.classes.capClasses.airGroups = {} end
Spearhead.classes.capClasses.airGroups.CapGroup = CapGroup
return CapGroup
@@ -1,3 +1,9 @@
local AirGroup = require("classes.capClasses.airGroups.AirGroup")
local INTERCEPT = require("classes.capClasses.taskings.INTERCEPT")
local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
local MissionEditorWarner = require("classes.util.MissionEditorWarnings")
---@class InterceptGroup : AirGroup
---@field private _targetNames Array<string>
---@field private _targetZoneName string
@@ -22,9 +28,9 @@ InterceptGroup.__index = InterceptGroup
---@return InterceptGroup?
function InterceptGroup.New(groupName, config, logger, detectionManager, spawnManager)
setmetatable(InterceptGroup, Spearhead.classes.capClasses.airGroups.AirGroup)
setmetatable(InterceptGroup, AirGroup)
local self = setmetatable({}, InterceptGroup)
Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "INTERCEPT", config, logger, spawnManager)
AirGroup.New(self, groupName, "INTERCEPT", config, logger, spawnManager)
local group = Group.getByName(groupName)
if not group then
@@ -135,7 +141,7 @@ function InterceptGroup:GetClosestTarget()
local targetUnit = Unit.getByName(targetName)
if targetUnit and targetUnit:isExist() then
local pos = targetUnit:getPoint()
local distance = Spearhead.Util.VectorDistance3d(groupPoint, pos)
local distance = Util.VectorDistance3d(groupPoint, pos)
if distance < closestDistance then
closestDistance = distance
closestUnit = targetUnit
@@ -179,7 +185,7 @@ function InterceptGroup:UpdateTask()
end
end
if Spearhead.DcsUtil.IsBingoFuel(self._groupName) then
if DcsUtil.IsBingoFuel(self._groupName) then
self._logger:debug("InterceptGroup: " .. self._groupName .. " is at bingo fuel, returning to base")
self:SendRTB(self._airbase)
return nil -- Return to base if bingo fuel
@@ -187,7 +193,7 @@ function InterceptGroup:UpdateTask()
if selfDetected and self:IsInAir() == true then
if self._currentTargetName and self._currentTargetName == closestUnit:getName() then
local distance = Spearhead.Util.VectorDistance3d(closestUnit:getPoint(), groupPoint)
local distance = Util.VectorDistance3d(closestUnit:getPoint(), groupPoint)
if distance < 30 * 1852 then
-- If the target is within 10 nautical miles, continue attacking
self._logger:debug("InterceptGroup: " .. self._groupName .. " continues attacking target " .. closestUnit:getName())
@@ -199,7 +205,7 @@ function InterceptGroup:UpdateTask()
local vec3 = closestUnit:getPoint()
local vec2 = { x = vec3.x, y = vec3.z }
local groupPointVec2 = { x = groupPoint.x, y = groupPoint.z }
local mission = Spearhead.classes.capClasses.taskings.INTERCEPT.getUnitInterceptMissionFromAir(self._groupName, groupPointVec2, vec2, closestUnit, self._airbase, self._config, self._maxSpeed, alt)
local mission = INTERCEPT.getUnitInterceptMissionFromAir(self._groupName, groupPointVec2, vec2, closestUnit, self._airbase, self._config, self._maxSpeed, alt)
self:SetMission(mission)
self._currentTargetName = closestUnit:getName()
return 15 -- Just continue attacking the detected target
@@ -219,7 +225,7 @@ function InterceptGroup:UpdateTask()
local mission = nil
if self:IsInAir() == true then
-- If the group is in the air, create an intercept mission
mission = Spearhead.classes.capClasses.taskings.INTERCEPT.getMissionFromInAir(
mission = INTERCEPT.getMissionFromInAir(
self._groupName,
{ x = groupPoint.x, y = groupPoint.z },
interceptPoint,
@@ -229,7 +235,7 @@ function InterceptGroup:UpdateTask()
alt
)
else
mission = Spearhead.classes.capClasses.taskings.INTERCEPT.getMissionFromAirbase(
mission = INTERCEPT.getMissionFromAirbase(
self._groupName,
interceptPoint,
self._airbase,
@@ -310,33 +316,33 @@ end
---@private
function InterceptGroup:InitWithName(groupName)
local split_string = Spearhead.Util.split_string(groupName, "_")
local partCount = Spearhead.Util.tableLength(split_string)
local split_string = Util.split_string(groupName, "_")
local partCount = Util.tableLength(split_string)
if partCount >= 3 then
local configPart = split_string[2]
configPart = string.sub(configPart, 2, #configPart)
local subsplit = Spearhead.Util.split_string(configPart, "|")
local subsplit = Util.split_string(configPart, "|")
if subsplit then
for key, value in pairs(subsplit) do
local keySplit = Spearhead.Util.split_string(value, "]")
local keySplit = Util.split_string(value, "]")
local targetZone = keySplit[2]
local allActives = string.sub(keySplit[1], 2, #keySplit[1])
local commaSeperated = Spearhead.Util.split_string(allActives, ",")
local commaSeperated = Util.split_string(allActives, ",")
for _, value in pairs(commaSeperated) do
local dashSeperated = Spearhead.Util.split_string(value, "-")
if Spearhead.Util.tableLength(dashSeperated) > 1 then
local dashSeperated = Util.split_string(value, "-")
if Util.tableLength(dashSeperated) > 1 then
local from = tonumber(dashSeperated[1])
local till = tonumber(dashSeperated[2])
for i = from, till do
if Spearhead.Util.strContains(targetZone, "A") == true then
if Util.strContains(targetZone, "A") == true then
self._targetZoneIdPerStage[tostring(i)] = string.gsub(targetZone, "A", tostring(i))
else
self._targetZoneIdPerStage[tostring(i)] = targetZone
end
end
else
if Spearhead.Util.strContains(targetZone, "A") == true then
if Util.strContains(targetZone, "A") == true then
self._targetZoneIdPerStage[tostring(dashSeperated[1])] = string.gsub(targetZone, "A", tostring(dashSeperated[1]))
else
self._targetZoneIdPerStage[tostring(dashSeperated[1])] = targetZone
@@ -346,16 +352,12 @@ function InterceptGroup:InitWithName(groupName)
end
end
env.info("interceptGroup parsed with table: " .. Spearhead.Util.toString(self._targetZoneIdPerStage))
env.info("interceptGroup parsed with table: " .. Util.toString(self._targetZoneIdPerStage))
else
Spearhead.AddMissionEditorWarning("CAP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount)
MissionEditorWarner.Add("CAP Group with name: " .. groupName .. "should have at least 3 parts, but has " .. partCount)
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.airGroups then Spearhead.classes.capClasses.airGroups = {} end
Spearhead.classes.capClasses.airGroups.InterceptGroup = InterceptGroup
return InterceptGroup
@@ -1,3 +1,8 @@
local AirGroup = require("classes.capClasses.airGroups.AirGroup")
local SWEEP = require("classes.capClasses.taskings.SWEEP")
local Util = require("classes.util.Util")
local MissionEditorWarner = require("classes.util.MissionEditorWarnings")
---@class SweepGroup : AirGroup
---@field _targetZoneIdPerStage table<number, string>
---@field _currentTargetZoneID string?
@@ -11,9 +16,9 @@ SweepGroup.__index = SweepGroup
---@param spawnManager SpawnManager
---@return SweepGroup
function SweepGroup.New(groupName, config, logger, spawnManager)
setmetatable(SweepGroup, Spearhead.classes.capClasses.airGroups.AirGroup)
setmetatable(SweepGroup, AirGroup)
local self = setmetatable({}, SweepGroup) --[[@as SweepGroup]]
Spearhead.classes.capClasses.airGroups.AirGroup.New(self, groupName, "SWEEP", config, logger, spawnManager)
AirGroup.New(self, groupName, "SWEEP", config, logger, spawnManager)
self._targetZoneIdPerStage = {}
self:InitWithName(groupName)
@@ -47,7 +52,7 @@ function SweepGroup:SendToZone(zone, targetZoneID, airbase)
local group = Group.getByName(self._groupName)
local mission = Spearhead.classes.capClasses.taskings.SWEEP.getAsMissionFromAirbase(self._groupName, airbase, zone, self._config)
local mission = SWEEP.getAsMissionFromAirbase(self._groupName, airbase, zone, self._config)
if mission then
---@type SetTaskParams
local params = {
@@ -68,35 +73,35 @@ end
---@private
function SweepGroup:InitWithName(groupName)
local split_string = Spearhead.Util.split_string(groupName, "_")
local partCount = Spearhead.Util.tableLength(split_string)
local split_string = Util.split_string(groupName, "_")
local partCount = Util.tableLength(split_string)
if partCount >= 3 then
local configPart = split_string[2]
configPart = string.sub(configPart, 2, #configPart)
local subsplit = Spearhead.Util.split_string(configPart, "|")
local subsplit = Util.split_string(configPart, "|")
if subsplit then
for key, value in pairs(subsplit) do
local keySplit = Spearhead.Util.split_string(value, "]")
local keySplit = Util.split_string(value, "]")
local targetZone = keySplit[2]
local allActives = string.sub(keySplit[1], 2, #keySplit[1])
local commaSeperated = Spearhead.Util.split_string(allActives, ",")
local commaSeperated = Util.split_string(allActives, ",")
for _, value in pairs(commaSeperated) do
local dashSeperated = Spearhead.Util.split_string(value, "-")
if Spearhead.Util.tableLength(dashSeperated) > 1 then
local dashSeperated = Util.split_string(value, "-")
if Util.tableLength(dashSeperated) > 1 then
local from = tonumber(dashSeperated[1])
local till = tonumber(dashSeperated[2])
for i = from, till do
if Spearhead.Util.strContains(targetZone, "A") == true then
if Util.strContains(targetZone, "A") == true then
self._targetZoneIdPerStage[tostring(i)] = string.gsub(targetZone, "A", tostring(i))
else
self._targetZoneIdPerStage[tostring(i)] = targetZone
end
end
else
if Spearhead.Util.strContains(targetZone, "A") == true then
if Util.strContains(targetZone, "A") == true then
self._targetZoneIdPerStage[tostring(dashSeperated[1])] = string.gsub(targetZone, "A",
tostring(dashSeperated[1]))
else
@@ -107,15 +112,11 @@ function SweepGroup:InitWithName(groupName)
end
end
env.info("SweepGroup parsed with table: " .. Spearhead.Util.toString(self._targetZoneIdPerStage))
env.info("SweepGroup parsed with table: " .. Util.toString(self._targetZoneIdPerStage))
else
Spearhead.AddMissionEditorWarning("SWEEP Group with name: " ..
MissionEditorWarner.Add("SWEEP Group with name: " ..
groupName .. "should have at least 3 parts, but has " .. partCount)
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.airGroups then Spearhead.classes.capClasses.airGroups = {} end
Spearhead.classes.capClasses.airGroups.SweepGroup = SweepGroup
return SweepGroup
@@ -161,8 +161,4 @@ function DetectionManager:UpdateDetectedUnitsByCoalition(coalitionSide)
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.detection then Spearhead.classes.capClasses.detection = {} end
Spearhead.classes.capClasses.detection.DetectionManager = DetectionManager
return DetectionManager
@@ -1,3 +1,6 @@
local SpearheadEvents = require("classes.spearhead_events")
local Util = require("classes.util.Util")
---@class RunwayBombingTracker : OnWeaponFiredListener
---@field trackedRunways table<Runway, RunwayStrikeMission>
---@field private _logger Logger
@@ -11,8 +14,7 @@ function RunwayBombingTracker.new(logger)
local self = setmetatable({}, RunwayBombingTracker)
self._logger = logger
Spearhead.Events.AddWeaponFiredListener(self)
SpearheadEvents.AddWeaponFiredListener(self)
return self
end
@@ -111,15 +113,10 @@ function RunwayBombingTracker:OnWeaponImpact(weaponDesc, impactPoint)
local zone= strikeMission:GetRunwayZone()
if Spearhead.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
strikeMission:RunwayHit(impactPoint, explosiveMass)
end
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.runwayBombing then Spearhead.classes.capClasses.runwayBombing = {} end
Spearhead.classes.capClasses.runwayBombing.RunwayBombingTracker = RunwayBombingTracker
return RunwayBombingTracker
@@ -1,3 +1,6 @@
local Util = require("classes.util.Util")
local RTB = require("classes.capClasses.taskings.RTB")
---@class CAPTasking
local CAP = {}
@@ -38,7 +41,7 @@ local function GetCAPPointFromTriggerZone(airBase, capZone)
for indexA, pointA in ipairs(capZone.verts) do
for indexB, pointB in ipairs(capZone.verts) do
if pointA ~= pointB then
local distance = Spearhead.Util.VectorDistance2d(pointA, pointB)
local distance = Util.VectorDistance2d(pointA, pointB)
if distance > furthestDistance then
furthestDistance = distance
furthestA = indexA
@@ -58,12 +61,12 @@ local function GetCAPPointFromTriggerZone(airBase, capZone)
local furthest = pointA
local closest = pointB
local heading = Spearhead.Util.vectorHeadingFromTo(pointA, pointB)
local heading = Util.vectorHeadingFromTo(pointA, pointB)
if Spearhead.Util.VectorDistance2d(baseVec2, pointB) > Spearhead.Util.VectorDistance2d(baseVec2, pointA) then
if Util.VectorDistance2d(baseVec2, pointB) > Util.VectorDistance2d(baseVec2, pointA) then
furthest = pointB
closest = pointA
heading = Spearhead.Util.vectorHeadingFromTo(pointB, pointA)
heading = Util.vectorHeadingFromTo(pointB, pointA)
end
local distance = furthestDistance
@@ -87,8 +90,8 @@ end
local GetOutboundTask = function(airbase, capZone, capConfig)
local airbaseVec3 = airbase:getPoint()
local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z }
local heading = Spearhead.Util.vectorHeadingFromTo(airbaseVec2, capZone.location)
local point = Spearhead.Util.vectorMove(airbaseVec2, heading, 18520)
local heading = Util.vectorHeadingFromTo(airbaseVec2, capZone.location)
local point = Util.vectorMove(airbaseVec2, heading, 18520)
return {
alt = 2000,
@@ -130,9 +133,9 @@ function CAP.getAsMissionFromAirbase(groupName, airbase, capZone, capConfig)
[1] = GetOutboundTask(airbase, capZone, capConfig),
[2] = GetOutboundTask(airbase, capZone, capConfig),
[3] = CAP.getAsTasking(groupName, airbase, capZone, capConfig),
[4] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, capZone.location, capConfig),
[5] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase),
[6] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase)
[4] = RTB.getApproachPoint(airbase, capZone.location, capConfig),
[5] = RTB.getInitialPoint(airbase),
[6] = RTB.getLandingPoint(airbase)
}
local mission = {
@@ -155,9 +158,9 @@ end
function CAP.getAsMission(groupName, airbase, capZone, capConfig)
local points = {
[1] = CAP.getAsTasking(groupName, airbase, capZone, capConfig),
[2] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, capZone.location, capConfig),
[3] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase),
[4] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase)
[2] = RTB.getApproachPoint(airbase, capZone.location, capConfig),
[3] = RTB.getInitialPoint(airbase),
[4] = RTB.getLandingPoint(airbase)
}
local mission = {
@@ -320,8 +323,4 @@ function CAP.getAsTasking(groupName, airbase, capZone, capConfig)
}
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.taskings then Spearhead.classes.capClasses.taskings = {} end
Spearhead.classes.capClasses.taskings.CAP = CAP
return CAP
@@ -1,4 +1,5 @@
local Util = require("classes.util.Util")
local RTB = require("classes.capClasses.taskings.RTB")
---@class InterceptTasking
local INTERCEPT = {}
@@ -14,11 +15,11 @@ function INTERCEPT.getMissionFromAirbase(groupName, interceptPoint, airbase, con
local airbaseVec3 = airbase:getPoint()
local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z }
local heading = Spearhead.Util.vectorHeadingFromTo(airbaseVec2, interceptPoint)
local heading = Util.vectorHeadingFromTo(airbaseVec2, interceptPoint)
env.info("BLAAT: heading from runway to first point: " .. heading)
local point = Spearhead.Util.vectorMove(airbaseVec2, heading, 3*1852)
local point = Util.vectorMove(airbaseVec2, heading, 3*1852)
local pointA, pointB, pointC, pointD = INTERCEPT.getInterceptTaskPoint(groupName, point, interceptPoint, airbaseVec2, config, speed, alt)
@@ -28,9 +29,9 @@ function INTERCEPT.getMissionFromAirbase(groupName, interceptPoint, airbase, con
[3] = pointB,
[4] = pointC,
[5] = pointD,
[6] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, interceptPoint, config),
[7] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase),
[8] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase)
[6] = RTB.getApproachPoint(airbase, interceptPoint, config),
[7] = RTB.getInitialPoint(airbase),
[8] = RTB.getLandingPoint(airbase)
}
local mission = {
@@ -67,9 +68,9 @@ function INTERCEPT.getMissionFromInAir(groupName, currentPosition, interceptPoin
[3] = pointB,
[4] = pointC,
[5] = pointD,
[6] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, interceptPoint, config),
[7] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase),
[8] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase)
[6] = RTB.getApproachPoint(airbase, interceptPoint, config),
[7] = RTB.getInitialPoint(airbase),
[8] = RTB.getLandingPoint(airbase)
}
local mission = {
@@ -109,9 +110,9 @@ function INTERCEPT.getUnitInterceptMissionFromAir(groupName, currentPoint, targe
[3] = pointB,
[4] = pointC,
[5] = pointD,
[6] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, currentPoint, config),
[7] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase),
[8] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase)
[6] = RTB.getApproachPoint(airbase, currentPoint, config),
[7] = RTB.getInitialPoint(airbase),
[8] = RTB.getLandingPoint(airbase)
}
local mission = {
@@ -392,8 +393,4 @@ function INTERCEPT.getUnitInterceptTaskPoint(groupName, currentPoint, targetPosi
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.taskings then Spearhead.classes.capClasses.taskings = {} end
Spearhead.classes.capClasses.taskings.INTERCEPT = INTERCEPT
return INTERCEPT
@@ -1,3 +1,4 @@
local Util = require("classes.util.Util")
---@class RTBTasking
local RTB = {}
@@ -33,7 +34,7 @@ local getRunwayIntoWindCourseRad = function(airbase)
local runways = airbase:getRunways()
local windVec = atmosphere.getWind(airbase:getPoint())
local mPerS = Spearhead.Util.vectorMagnitude(windVec)
local mPerS = Util.vectorMagnitude(windVec)
if mPerS > 0 then
for i = 1, #runways do
@@ -48,7 +49,7 @@ local getRunwayIntoWindCourseRad = function(airbase)
end
local runwayVec = {x = math.cos(rad), z = math.sin(rad), y = 0}
local alignment = Spearhead.Util.vectorAlignment(windVec, runwayVec)
local alignment = Util.vectorAlignment(windVec, runwayVec)
if minAlignment == nil or alignment < minAlignment then
activeCourse = i
@@ -68,7 +69,7 @@ local getRunwayIntoWindCourseRad = function(airbase)
end
local runwayVec = {x = math.cos(rad), z = math.sin(rad), y = 0}
local alignment = Spearhead.Util.vectorAlignment(windVec, runwayVec)
local alignment = Util.vectorAlignment(windVec, runwayVec)
if minAlignment == nil or alignment < minAlignment then
activeCourse = i
@@ -102,7 +103,7 @@ local function calcInitialPoint(airbase)
local flipped = (heading + 180) % 360
local basePoint = airbase:getPoint()
local basePointVec2 = {x = basePoint.x, y = basePoint.z}
local point = Spearhead.Util.vectorMove(basePointVec2, flipped, 22000)
local point = Util.vectorMove(basePointVec2, flipped, 22000)
return point, flipped
@@ -116,10 +117,10 @@ end
function RTB.getApproachPoint(airbase, missionPoint, capConfig)
local initialPoint, headingFromRunway = calcInitialPoint(airbase)
local pointA = Spearhead.Util.vectorMove(initialPoint, headingFromRunway - 45, 9000)
local pointB = Spearhead.Util.vectorMove(initialPoint, headingFromRunway + 45, 9000)
local pointA = Util.vectorMove(initialPoint, headingFromRunway - 45, 9000)
local pointB = Util.vectorMove(initialPoint, headingFromRunway + 45, 9000)
if Spearhead.Util.VectorDistance2d(missionPoint, pointA) > Spearhead.Util.VectorDistance2d(missionPoint, pointB) then
if Util.VectorDistance2d(missionPoint, pointA) > Util.VectorDistance2d(missionPoint, pointB) then
pointA = pointB
end
@@ -194,8 +195,4 @@ function RTB.getLandingPoint(airbase)
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.taskings then Spearhead.classes.capClasses.taskings = {} end
Spearhead.classes.capClasses.taskings.RTB = RTB
return RTB
@@ -1,3 +1,6 @@
local Util = require("classes.util.Util")
local RTB = require("classes.capClasses.taskings.RTB")
---@class SWEEPTasking
local SWEEP = {}
@@ -31,7 +34,7 @@ local function GetCAPPointFromTriggerZone(airBase, capZone)
for indexA, pointA in ipairs(capZone.verts) do
for indexB, pointB in ipairs(capZone.verts) do
if pointA ~= pointB then
local distance = Spearhead.Util.VectorDistance2d(pointA, pointB)
local distance = Util.VectorDistance2d(pointA, pointB)
if distance > furthestDistance then
furthestDistance = distance
furthestA = indexA
@@ -51,12 +54,12 @@ local function GetCAPPointFromTriggerZone(airBase, capZone)
local furthest = pointA
local closest = pointB
local heading = Spearhead.Util.vectorHeadingFromTo(pointA, pointB)
local heading = Util.vectorHeadingFromTo(pointA, pointB)
if Spearhead.Util.VectorDistance2d(baseVec2, pointB) > Spearhead.Util.VectorDistance2d(baseVec2, pointA) then
if Util.VectorDistance2d(baseVec2, pointB) > Util.VectorDistance2d(baseVec2, pointA) then
furthest = pointB
closest = pointA
heading = Spearhead.Util.vectorHeadingFromTo(pointB, pointA)
heading = Util.vectorHeadingFromTo(pointB, pointA)
end
local distance = furthestDistance
@@ -80,8 +83,8 @@ end
local GetOutboundTask = function(airbase, capZone, capConfig)
local airbaseVec3 = airbase:getPoint()
local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z }
local heading = Spearhead.Util.vectorHeadingFromTo(airbaseVec2, capZone.location)
local point = Spearhead.Util.vectorMove(airbaseVec2, heading, 18520)
local heading = Util.vectorHeadingFromTo(airbaseVec2, capZone.location)
local point = Util.vectorMove(airbaseVec2, heading, 18520)
return {
alt = 2000,
@@ -128,9 +131,9 @@ function SWEEP.getAsMissionFromAirbase(groupName, airbase, capZone, capConfig)
[3] = pointA,
[4] = pointB,
[5] = pointC,
[6] = Spearhead.classes.capClasses.taskings.RTB.getApproachPoint(airbase, capZone.location, capConfig),
[7] = Spearhead.classes.capClasses.taskings.RTB.getInitialPoint(airbase),
[8] = Spearhead.classes.capClasses.taskings.RTB.getLandingPoint(airbase)
[6] = RTB.getApproachPoint(airbase, capZone.location, capConfig),
[7] = RTB.getInitialPoint(airbase),
[8] = RTB.getLandingPoint(airbase)
}
local mission = {
@@ -280,8 +283,4 @@ function SWEEP.getAsTasking(groupName, airbase, capZone, capConfig)
return pointA, pointB, pointC
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.capClasses then Spearhead.classes.capClasses = {} end
if not Spearhead.classes.capClasses.taskings then Spearhead.classes.capClasses.taskings = {} end
Spearhead.classes.capClasses.taskings.SWEEP = SWEEP
return SWEEP
@@ -95,6 +95,4 @@ function CapConfig:getDeathDelay()
return self._deathDelay
end
if not Spearhead.internal then Spearhead.internal = {} end
if not Spearhead.internal.configuration then Spearhead.internal.configuration = {} end
Spearhead.internal.configuration.CapConfig = CapConfig;
return CapConfig
@@ -29,6 +29,5 @@ function GlobalConfig:getBriefingTime()
end
if Spearhead == nil then Spearhead = {} end
Spearhead.GlobalConfig = GlobalConfig.New()
return GlobalConfig
@@ -7,8 +7,6 @@
--- @field startingStage integer
--- @field maxMissionsPerStage integer
--- @field AmountPreactivateStage integer
local StageConfig = {};
---comment
@@ -34,6 +32,4 @@ function StageConfig:new()
return o;
end
if not Spearhead.internal then Spearhead.internal = {} end
if not Spearhead.internal.configuration then Spearhead.internal.configuration = {} end
Spearhead.internal.configuration.StageConfig = StageConfig;
return StageConfig
@@ -1,3 +1,10 @@
local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
local MissionEditorWarning = require("classes.util.MissionEditorWarnings")
local RouteUtil = require("classes.spearhead_routeutil")
local SpearheadEvents = require("classes.spearhead_events")
---@class FleetGroup
local FleetGroup = {}
---comment
@@ -13,9 +20,9 @@ function FleetGroup:new(fleetGroupName, database, logger)
o.fleetGroupName = fleetGroupName
o.logger = logger
local split_name = Spearhead.Util.split_string(fleetGroupName, "_")
if Spearhead.Util.tableLength(split_name) < 2 then
Spearhead.AddMissionEditorWarning("CARRIERGROUP should have at least 2 parts. CARRIERGROUP_<fleetname>")
local split_name = Util.split_string(fleetGroupName, "_")
if Util.tableLength(split_name) < 2 then
MissionEditorWarning.Add("CARRIERGROUP should have at least 2 parts. CARRIERGROUP_<fleetname>")
return nil
end
o.fleetNameIdentifier = split_name[2]
@@ -27,12 +34,12 @@ function FleetGroup:new(fleetGroupName, database, logger)
do --INIT
local carrierRouteZones = database:getCarrierRouteZones()
for _, zoneName in pairs(carrierRouteZones) do
if Spearhead.Util.strContains(string.lower(zoneName), "_".. string.lower(o.fleetNameIdentifier) .. "_" ) == true then
local zone = Spearhead.DcsUtil.getZoneByName(zoneName)
if zone and zone.zone_type == Spearhead.DcsUtil.ZoneType.Polygon then
local split_string = Spearhead.Util.split_string(zoneName, "_")
if Spearhead.Util.tableLength(split_string) < 3 then
Spearhead.AddMissionEditorWarning(
if Util.strContains(string.lower(zoneName), "_".. string.lower(o.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, "_")
if Util.tableLength(split_string) < 3 then
MissionEditorWarning.Add(
"CARRIERROUTE should at least have 3 parts. Check the documentation for: " .. zoneName)
else
@@ -48,7 +55,7 @@ function FleetGroup:new(fleetGroupName, database, logger)
for ii = i + 1, 4 do
local a = zone.verts[i]
local b = zone.verts[ii]
local dist = Spearhead.Util.VectorDistance2d(a, b)
local dist = Util.VectorDistance2d(a, b)
if biggest == nil or dist > biggest then
biggestA = a
@@ -65,17 +72,17 @@ function FleetGroup:new(fleetGroupName, database, logger)
return nil, nil
end
if Spearhead.Util.startswith(namePart, "%[") == true then
namePart = Spearhead.Util.split_string(namePart, "[")[1]
if Util.startswith(namePart, "%[") == true then
namePart = Util.split_string(namePart, "[")[1]
end
if Spearhead.Util.strContains(namePart, "%]") == true then
namePart = Spearhead.Util.split_string(namePart, "]")[1]
if Util.strContains(namePart, "%]") == true then
namePart = Util.split_string(namePart, "]")[1]
end
local split_numbers = Spearhead.Util.split_string(namePart, "-")
if Spearhead.Util.tableLength(split_numbers) < 2 then
Spearhead.AddMissionEditorWarning("CARRIERROUTE zone stage numbers not in the format _[<number>-<number>]: " .. zoneName)
local split_numbers = Util.split_string(namePart, "-")
if Util.tableLength(split_numbers) < 2 then
MissionEditorWarning.Add("CARRIERROUTE zone stage numbers not in the format _[<number>-<number>]: " .. zoneName)
return nil, nil
end
@@ -83,7 +90,7 @@ function FleetGroup:new(fleetGroupName, database, logger)
local second = tonumber(split_numbers[2])
if first == nil or second == nil then
Spearhead.AddMissionEditorWarning("CARRIERROUTE zone stage numbers not in the format _[<number>-<number>]: " .. zoneName)
MissionEditorWarning.Add("CARRIERROUTE zone stage numbers not in the format _[<number>-<number>]: " .. zoneName)
return nil, nil
end
return first, second
@@ -97,11 +104,11 @@ function FleetGroup:new(fleetGroupName, database, logger)
end
o.pointsPerZone[zoneName] = { pointA = { x = pointA.x, z = pointA.y, y = 0 }, pointB = { x = pointB.x, z = pointB.y, y = 0} }
else
Spearhead.AddMissionEditorWarning("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
else
Spearhead.AddMissionEditorWarning("CARRIERROUTE cannot be a cilinder: " .. zoneName)
MissionEditorWarning.Add("CARRIERROUTE cannot be a cilinder: " .. zoneName)
end
end
end
@@ -115,7 +122,7 @@ function FleetGroup:new(fleetGroupName, database, logger)
local group = Group.getByName(groupName)
if group then
logger:info("Sending " .. fleetGroupName .. " to " .. targetZone)
logger:info("Sending " .. groupName .. " to " .. targetZone)
group:getController():setTask(task)
end
end
@@ -124,14 +131,13 @@ function FleetGroup:new(fleetGroupName, database, logger)
local targetZone = self.targetZonePerStage[tostring(number)]
if targetZone and targetZone ~= self.currentTargetZone then
local points = self.pointsPerZone[targetZone]
local task = Spearhead.RouteUtil.CreateCarrierRacetrack(points.pointA, points.pointB)
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
end
Spearhead.Events.AddStageNumberChangedListener(o)
SpearheadEvents.AddStageNumberChangedListener(o)
return o
end
if not Spearhead.internal then Spearhead.internal = {} end
Spearhead.internal.FleetGroup = FleetGroup
return FleetGroup
@@ -0,0 +1,26 @@
local Logger = require("classes.util.Logger")
local Util = require("classes.util.Util")
local FleetGroup = require("classes.fleetClasses.FleetGroup")
local MizGroupsManager = require("classes.helpers.MizGroupsManager")
---@class GlobalFleetManager
local GlobalFleetManager = {}
local fleetGroups = {}
GlobalFleetManager.start = function(database)
local logger = Logger.new("CARRIERFLEET", "INFO")
local all_groups = MizGroupsManager.getAllGroupNames()
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)
table.insert(fleetGroups, carrierGroup)
end
end
end
return GlobalFleetManager
@@ -1,3 +1,5 @@
local DcsUtil = require("classes.util.DcsUtil")
---@class SpawnData
---@field groupTemplate table
---@field isStatic boolean
@@ -14,17 +16,17 @@ MizGroupsManager._spawnTemplateData = {}
do --init
for coalition_name, coalition_data in pairs(env.mission.coalition) do
local coalition_nr = Spearhead.DcsUtil.stringToCoalition(coalition_name)
local coalition_nr = DcsUtil.stringToCoalition(coalition_name)
if coalition_data.country then
for country_index, country_data in pairs(coalition_data.country) do
for category_name, categorydata in pairs(country_data) do
local category_id = Spearhead.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
for group_index, group in pairs(categorydata.group) do
local name = group.name
local skippable = false
local isStatic = false
if category_id == Spearhead.DcsUtil.GroupCategory.STATIC then
if category_id == DcsUtil.GroupCategory.STATIC then
isStatic = true
local unit = group.units[1]
if unit and unit.category == "Heliports" then
@@ -75,7 +77,4 @@ function MizGroupsManager.getSpawnTemplateData(groupName)
return MizGroupsManager._spawnTemplateData[groupName]
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.helpers then Spearhead.classes.helpers = {} end
Spearhead.classes.helpers.MizGroupsManager = MizGroupsManager
return MizGroupsManager
@@ -1,3 +1,8 @@
local MizGroupsManager = require("classes.helpers.MizGroupsManager")
local Persistence = require("classes.persistence.Persistence")
local SpearheadEvents = require("classes.spearhead_events")
local Util = require("classes.util.Util")
---@class SpawnManager : OnUnitLostListener
---@field private _persistedUnits table<string,boolean>
---@field private _logger Logger
@@ -29,7 +34,7 @@ end
---@return boolean isStatic
function SpawnManager:SpawnGroup(groupName, overrides, isGroupPersistant)
local spawnData = Spearhead.classes.helpers.MizGroupsManager.getSpawnTemplateData(groupName)
local spawnData = MizGroupsManager.getSpawnTemplateData(groupName)
if spawnData == nil then
env.error("SpawnManager:SpawnGroup - No spawn template found for group: " .. groupName)
@@ -67,7 +72,7 @@ end
---@param groupName string
---@return boolean
function SpawnManager:IsGroupStatic(groupName)
local isStatic = Spearhead.classes.helpers.MizGroupsManager.IsGroupStatic(groupName)
local isStatic = MizGroupsManager.IsGroupStatic(groupName)
if isStatic ~= nil then return isStatic end
return StaticObject.getByName(groupName) ~= nil
@@ -89,7 +94,7 @@ function SpawnManager:OnUnitLost(object)
heading = heading
end
Spearhead.classes.persistence.Persistence.UnitKilled(
Persistence.UnitKilled(
name,
object:getPoint(),
heading,
@@ -119,7 +124,7 @@ do --- privates
country = override.countryID or spawnData.country
end
local spawnTemplate = Spearhead.Util.deepCopyTable(spawnData.groupTemplate)
local spawnTemplate = Util.deepCopyTable(spawnData.groupTemplate)
---@type Array<string>
local removeableUnitNames = {}
--[[
@@ -131,8 +136,8 @@ do --- privates
for _, unit in pairs(spawnTemplate["units"]) do
local name = unit["name"]
Spearhead.Events.addOnUnitLostEventListener(name, self)
local state = Spearhead.classes.persistence.Persistence.UnitState(name)
SpearheadEvents.addOnUnitLostEventListener(name, self)
local state = Persistence.UnitState(name)
if state then
if state.isDead == true then
removeableUnitNames[#removeableUnitNames+1] = name
@@ -170,7 +175,7 @@ do --- privates
if isPersistent == true then
self._persistedUnits[unit:getName()] = true
end
Spearhead.Events.addOnUnitLostEventListener(unit:getName(), self)
SpearheadEvents.addOnUnitLostEventListener(unit:getName(), self)
end
return group
@@ -195,10 +200,10 @@ do --- privates
country = overrides.countryID or spawnData.country
end
local spawnTemplate = Spearhead.Util.deepCopyTable(spawnData.groupTemplate)
local spawnTemplate = Util.deepCopyTable(spawnData.groupTemplate)
--for static Objecst groupNames and unit names are the same and is always 1:1
local persistentState = Spearhead.classes.persistence.Persistence.UnitState(groupName)
local persistentState = Persistence.UnitState(groupName)
if persistentState then
if persistentState.isDead == true then
spawnTemplate["dead"] = true
@@ -226,7 +231,7 @@ do --- privates
if isPersistent == true then
self._persistedUnits[groupName] = true
Spearhead.Events.addOnUnitLostEventListener(groupName, self)
SpearheadEvents.addOnUnitLostEventListener(groupName, self)
end
return object
@@ -238,7 +243,7 @@ do --- privates
if not unit then return end
local deadState = Spearhead.classes.persistence.Persistence.UnitState(unit:getName())
local deadState = Persistence.UnitState(unit:getName())
if deadState and deadState.isDead == true then
unit:destroy() -- Destroy the unit if it is dead
local staticObject = {
@@ -255,10 +260,7 @@ do --- privates
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.helpers then Spearhead.classes.helpers = {} end
Spearhead.classes.helpers.SpawnManager = SpawnManager
return SpawnManager
--Old Spawn Method
@@ -1,4 +1,6 @@
local Util = require("classes.util.Util")
---@class Perstistence
---@field private _path string
---@field private _updateRequired boolean
@@ -81,7 +83,7 @@ do
if lua then
tables = lua
logger:debug("Loaded persistence data: " .. Spearhead.Util.toString(lua))
logger:debug("Loaded persistence data: " .. Util.toString(lua))
else
logger:error("Could not load persistence file, using default tables")
end
@@ -143,8 +145,8 @@ do
local latestFile, lastNumber = default, 0
for file in lfs.dir(dir) do
local split = Spearhead.Util.split_string(file, ".")
local doesStartWith = Spearhead.Util.startswith(file, startsWith, true)
local split = Util.split_string(file, ".")
local doesStartWith = Util.startswith(file, startsWith, true)
if split and #split > 0 and split[#split] == EXTENSION and doesStartWith == true then
local numberString = split[#split-1]
local number = tonumber(numberString)
@@ -179,7 +181,7 @@ do
if SpearheadConfig.Persistence.fileName then
local userFileName = SpearheadConfig.Persistence.fileName
local split = Spearhead.Util.split_string(userFileName, ".")
local split = Util.split_string(userFileName, ".")
if not split and #split < 3 then
split[#split+1] = "0"
@@ -199,12 +201,12 @@ do
end
end
local split = Spearhead.Util.split_string(fileName, ".")
local matchingPart = table.concat(Spearhead.Util.sublist(split, 1, #split-2), ".")
local split = Util.split_string(fileName, ".")
local matchingPart = table.concat(Util.sublist(split, 1, #split-2), ".")
local lastFile = getLastFileOrDefault(dir--[[@as string]], matchingPart, fileName)
local fileSplit = Spearhead.Util.split_string(lastFile, ".")
local fileSplit = Util.split_string(lastFile, ".")
fileSplit[#fileSplit-1] = tostring(tonumber(fileSplit[#fileSplit-1]) + 1)
fileName = table.concat(fileSplit, ".")
@@ -329,7 +331,4 @@ do
end
end
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.persistence == nil then Spearhead.classes.persistence = {} end
Spearhead.classes.persistence.Persistence = Persistence
return Persistence
@@ -1009,5 +1009,4 @@ function Database:GetNewMissionCode()
]]
end
if not Spearhead then Spearhead = {} end
Spearhead.DB = Database
return Database
@@ -1,4 +1,4 @@
---@class SpearheadEvents
local SpearheadEvents = {}
do
@@ -398,5 +398,4 @@ do
world.addEventHandler(e)
end
if Spearhead == nil then Spearhead = {} end
Spearhead.Events = SpearheadEvents
return SpearheadEvents
@@ -1,3 +1,4 @@
---@class SpearheadRouteUtil
local ROUTE_UTIL = {}
do --setup route util
---comment
@@ -461,5 +462,4 @@ do --setup route util
end
end
if Spearhead == nil then Spearhead = {} end
Spearhead.RouteUtil = ROUTE_UTIL
return ROUTE_UTIL
@@ -20,6 +20,8 @@ local currentStage = -99
local GlobalStageManager = {}
GlobalStageManager.__index = GlobalStageManager
GlobalStageManager.getCurrentStage = function() return currentStage end
---comment
---@param database Database
---@param stageConfig StageConfig
@@ -45,6 +47,7 @@ function GlobalStageManager.NewAndStart(database, stageConfig, logLevel, spawnMa
end
}
Spearhead.Events.AddStageNumberChangedListener(OnStageNumberChangedListener)
for _, stageName in pairs(database:getStagezoneNames()) do
@@ -282,5 +285,4 @@ GlobalStageManager.isStageComplete = function (stageNumber)
return true
end
if not Spearhead.internal then Spearhead.internal = {} end
Spearhead.internal.GlobalStageManager = GlobalStageManager
return GlobalStageManager
@@ -1,5 +1,5 @@
local DcsUtil = require("classes.util.DcsUtil")
---@class SpearheadGroup : OnUnitLostListener
---@field private _groupName string
@@ -149,7 +149,7 @@ end
function SpearheadGroup:SetInvisible()
if self._isStatic == true then
local country = Spearhead.DcsUtil.GetNeutralCountry()
local country = DcsUtil.GetNeutralCountry()
---@type SpawnOverrides
local overrides = {
@@ -187,7 +187,4 @@ function SpearheadGroup:SetVisible()
end
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.Groups then Spearhead.classes.stageClasses.Groups = {} end
Spearhead.classes.stageClasses.Groups.SpearheadGroup = SpearheadGroup
return SpearheadGroup
@@ -1,3 +1,5 @@
local Persistence = require("classes.persistence.Persistence")
---@class SpearheadSceneryObject
---@field private persistentName string The persistent name of the scenery object
---@field private objectID number The ID of the scenery object
@@ -47,7 +49,7 @@ end
function SpearheadSceneryObject:MarkDead()
if self.isDead == true then return end
self.isDead = true
Spearhead.classes.persistence.Persistence.UnitKilled(self.persistentName, self:GetPoint(), 0, "Scenery")
Persistence.UnitKilled(self.persistentName, self:GetPoint(), 0, "Scenery")
end
function SpearheadSceneryObject:UpdateStatePersistently()
@@ -55,7 +57,7 @@ function SpearheadSceneryObject:UpdateStatePersistently()
return
end
local state = Spearhead.classes.persistence.Persistence.UnitState(self.persistentName)
local state = Persistence.UnitState(self.persistentName)
if state and state.isDead == true then
trigger.action.explosion(self:GetPoint(), 1000)
self.isDead = true
@@ -71,7 +73,4 @@ function SpearheadSceneryObject:GetPoint()
return Object.getPoint(self.internalObj)
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.Groups then Spearhead.classes.stageClasses.Groups = {} end
Spearhead.classes.stageClasses.Groups.SpearheadSceneryObject = SpearheadSceneryObject
return SpearheadSceneryObject
@@ -148,10 +148,4 @@ function BlueSam:OnBuildingComplete()
self:SpawnGroups()
end
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end
Spearhead.classes.stageClasses.SpecialZones.BlueSam = BlueSam
return BlueSam
@@ -132,8 +132,4 @@ function FarpZone:SetPadsBlue()
end
end
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end
Spearhead.classes.stageClasses.SpecialZones.FarpZone = FarpZone
return FarpZone
@@ -187,10 +187,4 @@ function StageBase:OnBuildingComplete()
self:FinaliseBlueStage()
end
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end
Spearhead.classes.stageClasses.SpecialZones.StageBase = StageBase
return StageBase
@@ -80,9 +80,4 @@ function SupplyHub:Activate()
end
if not Spearhead then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end
Spearhead.classes.stageClasses.SpecialZones.SupplyHub = SupplyHub
return SupplyHub
@@ -197,9 +197,4 @@ function BuildableZone:SpawnAmount(amount)
return true
end
if not Spearhead then Spearhead = {} end
Spearhead.classes = Spearhead.classes or {}
Spearhead.classes.stageClasses = Spearhead.classes.stageClasses or {}
Spearhead.classes.stageClasses.SpecialZones = Spearhead.classes.stageClasses.SpecialZones or {}
Spearhead.classes.stageClasses.SpecialZones.abstract = Spearhead.classes.stageClasses.SpecialZones.abstract or {}
Spearhead.classes.stageClasses.SpecialZones.abstract.BuildableZone = BuildableZone
return BuildableZone
@@ -575,11 +575,7 @@ function Stage:ActivateBlueStage()
timer.scheduleFunction(ActivateBlueAsync, self, timer.getTime() + 3)
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.Stages then Spearhead.classes.stageClasses.Stages = {} end
if not Spearhead.classes.stageClasses.Stages.BaseStage then Spearhead.classes.stageClasses.Stages.BaseStage = {} end
Spearhead.classes.stageClasses.Stages.BaseStage.Stage = Stage
return Stage
@@ -61,9 +61,6 @@ function ExtraStage:OnStageNumberChanged(number)
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.Stages then Spearhead.classes.stageClasses.Stages = {} end
Spearhead.classes.stageClasses.Stages.ExtraStage = ExtraStage
return ExtraStage
@@ -22,9 +22,6 @@ function PrimaryStage.New(database, stageConfig, logger, initData, spawnManager)
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.Stages then Spearhead.classes.stageClasses.Stages = {} end
Spearhead.classes.stageClasses.Stages.PrimaryStage = PrimaryStage
return PrimaryStage
@@ -69,9 +69,6 @@ function WaitingStage:GetExpectedTime()
return self._startTime + self._waitTimeSeconds
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.Stages then Spearhead.classes.stageClasses.Stages = {} end
Spearhead.classes.stageClasses.Stages.WaitingStage = WaitingStage
return WaitingStage
@@ -1,9 +1,10 @@
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
local Util = require("classes.util.Util")
---@class CustomDrawing
---@field private _id integer?
---@field private _drawingObject DrawingObject
---@field private _helper DrawingHelper
---@field private _startingStage number
---@field private _removeAtStage number
local CustomDrawing = {}
@@ -17,12 +18,11 @@ function CustomDrawing.New(drawingObject, id)
local self = setmetatable({}, CustomDrawing)
self._drawingObject = drawingObject
self._id = id
self._helper = Spearhead.classes.stageClasses.drawings.helper.DrawingHelper
local name = drawingObject.name
local split = Spearhead.Util.split_string(name or "", "_")
local split = Util.split_string(name or "", "_")
local secondPart = split[2] or "1"
local splitPart = Spearhead.Util.split_string(secondPart, ":")
local splitPart = Util.split_string(secondPart, ":")
self._startingStage = tonumber(splitPart[1]) or 1
self._removeAtStage = tonumber(splitPart[2]) or math.huge
return self
@@ -35,18 +35,14 @@ function CustomDrawing:GetStartAndStop()
end
function CustomDrawing:Draw()
self._id = self._helper.Draw(self._drawingObject)
self._id = DrawingHelper.Draw(self._drawingObject)
end
function CustomDrawing:Remove()
if self._id ~= nil then
self._helper.Remove(self._id)
DrawingHelper.Remove(self._id)
self._id = nil
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.drawings then Spearhead.classes.stageClasses.drawings = {} end
Spearhead.classes.stageClasses.drawings.CustomDrawing = CustomDrawing
return CustomDrawing
@@ -220,9 +220,4 @@ end
---@field public b number
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.drawings then Spearhead.classes.stageClasses.drawings = {} end
if not Spearhead.classes.stageClasses.drawings.helper then Spearhead.classes.stageClasses.drawings.helper = {} end
Spearhead.classes.stageClasses.drawings.helper.DrawingHelper = DrawingHelper
return DrawingHelper
@@ -1,3 +1,7 @@
local Logger = require("classes.util.Logger")
local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
---@class BattleManager
---@field private _name string
---@field private _logger Logger
@@ -21,7 +25,7 @@ function BattleManager.New(redGroups, blueGroups, name, logLevel)
self._isActive = false
self._name = name
self._logger = Spearhead.LoggerTemplate.new("BattleManager_" .. name, logLevel)
self._logger = Logger.new("BattleManager_" .. name, logLevel)
self._redGroups = redGroups
self._blueGroups = blueGroups
@@ -167,7 +171,7 @@ function BattleManager:getBestAmmo(unit)
end
end
local entry = Spearhead.Util.randomFromList(shells)
local entry = Util.randomFromList(shells)
if entry and entry.desc and entry.desc.warhead then
local caliber = entry.desc.warhead.caliber
if caliber > 50 then
@@ -213,10 +217,10 @@ function BattleManager:ToShootingHulls(groups)
end
end
local hulls = Spearhead.Util.getSeparatedConvexHulls(points, 50)
local hulls = Util.getSeparatedConvexHulls(points, 50)
local enlargedHulls = {}
for _, hull in pairs(hulls) do
local enlarged = Spearhead.Util.enlargeConvexHull(hull, 25)
local enlarged = Util.enlargeConvexHull(hull, 25)
if enlarged then
table.insert(enlargedHulls, enlarged)
end
@@ -237,15 +241,15 @@ end
---@return Vec2?
function BattleManager:GetRandomPoint(origin, groupHulls)
local hull = Spearhead.Util.randomFromList(groupHulls) --[[@as Array<Vec2>]]
local hull = Util.randomFromList(groupHulls) --[[@as Array<Vec2>]]
if not hull then return nil end
local shootPoints = Spearhead.Util.GetTangentHullPointsFromOrigin(hull, origin)
local shootPoints = Util.GetTangentHullPointsFromOrigin(hull, origin)
if debugDrawing == true then
self:DrawDebugZone({ hull })
end
return Spearhead.Util.randomFromList(shootPoints) --[[@as Vec2]]
return Util.randomFromList(shootPoints) --[[@as Vec2]]
end
do --DEBUG
@@ -258,7 +262,7 @@ do --DEBUG
color = {r = 0, g = 0, b = 1, a = 1}
end
Spearhead.DcsUtil.DrawLine(unit:getPoint(), {x = target.x, y = 0, z = target.y}, color, 1)
DcsUtil.DrawLine(unit:getPoint(), {x = target.x, y = 0, z = target.y}, color, 1)
end
---@param hulls Array<Array<Vec2>>
@@ -274,13 +278,9 @@ do --DEBUG
location = { x=drawHull[1].x, y=drawHull[1].y },
}
Spearhead.DcsUtil.DrawZone(zone, {r =0, g=0, b =1, a = 0.5} ,{r =0, g= 0, b =1, a = 0}, 1)
DcsUtil.DrawZone(zone, {r =0, g=0, b =1, a = 0.5} ,{r =0, g= 0, b =1, a = 0}, 1)
end
end
end --DEBUG
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
if Spearhead.classes.stageClasses.helpers == nil then Spearhead.classes.stageClasses.helpers = {} end
Spearhead.classes.stageClasses.helpers.BattleManager = BattleManager
return BattleManager
@@ -0,0 +1,20 @@
---@class MaxLoadConfig
---@field maxInternalLoad number
---@type table<string, MaxLoadConfig>
local MaxLoadConfig = {
["Mi-8MT"] = {
maxInternalLoad = 4000,
},
["CH-47Fbl1"] = {
maxInternalLoad = 10000
},
["Mi-24P"] = {
maxInternalLoad = 2000
},
["UH-1H"] = {
maxInternalLoad = 2000
}
}
return MaxLoadConfig
@@ -1,3 +1,10 @@
local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
local Logger = require("classes.util.Logger")
local SpearheadEvents = require("classes.spearhead_events")
local SupplyUnitsTracker = require("classes.stageClasses.helpers.SupplyUnitsTracker")
local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper")
---@class MissionCommandsHelper
---@field missionsByCode table<string, Mission> @table of missions by their code
@@ -17,8 +24,8 @@ MissionCommandsHelper.__index = MissionCommandsHelper
---@param groupPos Vec2
local function sortMissions(list, groupPos)
table.sort(list, function(a, b)
local distA = Spearhead.Util.VectorDistance2d(groupPos, a.location or {x=0, y=0})
local distB = Spearhead.Util.VectorDistance2d(groupPos, b.location or {x=0, y=0})
local distA = Util.VectorDistance2d(groupPos, a.location or {x=0, y=0})
local distB = Util.VectorDistance2d(groupPos, b.location or {x=0, y=0})
return distA < distB;
end)
end
@@ -33,7 +40,7 @@ function MissionCommandsHelper.getOrCreate(logLevel)
if instance == nil then
instance = setmetatable({}, MissionCommandsHelper)
instance._logger = Spearhead.LoggerTemplate.new("MissionCommandsHelper", logLevel)
instance._logger = Logger.new("MissionCommandsHelper", logLevel)
instance._logger:info("Creating MissionCommandsHelper instance")
@@ -45,7 +52,7 @@ function MissionCommandsHelper.getOrCreate(logLevel)
instance._supplyHubGroups = {}
instance._stageBriefings = {}
instance._supplyUnitsTracker = Spearhead.classes.stageClasses.helpers.SupplyUnitsTracker.getOrCreate(logLevel)
instance._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate(logLevel)
---comment
---@param selfA MissionCommandsHelper
@@ -56,7 +63,7 @@ function MissionCommandsHelper.getOrCreate(logLevel)
return time + 10
end
for _, unit in pairs(Spearhead.DcsUtil.getAllPlayerUnits()) do
for _, unit in pairs(DcsUtil.getAllPlayerUnits()) do
if unit and unit:isExist() then
local group = unit:getGroup()
if group then
@@ -71,7 +78,7 @@ function MissionCommandsHelper.getOrCreate(logLevel)
end
timer.scheduleFunction(instance.updateContinuous, instance, timer.getTime() + 5)
Spearhead.Events.AddOnPlayerEnterUnitListener(instance)
SpearheadEvents.AddOnPlayerEnterUnitListener(instance)
end
@@ -174,7 +181,7 @@ function MissionCommandsHelper:AddOverviewCommand(groupID)
local text = "Missions Overview\n\n"
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(id)
local group = DcsUtil.GetPlayerGroupByGroupID(id)
---@type Vec2
local groupPos = { x=0, y=0 }
if group then
@@ -193,7 +200,7 @@ function MissionCommandsHelper:AddOverviewCommand(groupID)
if lead and lead:isExist() == true then
local pos = lead:getPoint()
local Vec2Pos = { x= pos.x, y=pos.z }
local distance = Spearhead.Util.VectorDistance2d(Vec2Pos, mission.location) / 1852
local distance = Util.VectorDistance2d(Vec2Pos, mission.location) / 1852
distanceText = string.format("~%d", math.floor(distance))
end
end
@@ -323,7 +330,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID)
local perFolder = 9
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
---@type Vec2
local groupPos = { x=0, y=0 }
if group then
@@ -351,7 +358,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID)
for _, mission in pairs(primaryMissions) do
count = count + 1
if count <= perFolder then
local copied = Spearhead.Util.deepCopyTable(path)
local copied = Util.deepCopyTable(path)
self:addMissionCommands(groupID, copied, mission)
else
local name = "Next Menu ..."
@@ -380,7 +387,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID)
for _, mission in pairs(secondaryMissions) do
count = count + 1
if count <= perFolder then
local copied = Spearhead.Util.deepCopyTable(path)
local copied = Util.deepCopyTable(path)
self:addMissionCommands(groupID, copied, mission)
else
local name = "Next Menu ..."
@@ -401,14 +408,14 @@ function MissionCommandsHelper:addMissionCommands(groupId, path, mission)
if path then
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupId)
local group = DcsUtil.GetPlayerGroupByGroupID(groupId)
local distance = "[?]"
if group then
local lead = group:getUnit(1)
if lead and lead:isExist() == true then
local pos = lead:getPoint()
local Vec2Pos = { x= pos.x, y=pos.z }
local dist = Spearhead.Util.VectorDistance2d(Vec2Pos, mission.location) / 1852
local dist = Util.VectorDistance2d(Vec2Pos, mission.location) / 1852
distance = "[" .. string.format("~%dnM", math.floor(dist)) .. "]"
end
end
@@ -435,7 +442,7 @@ function MissionCommandsHelper:AddSupplyHubCommandsIfApplicable(groupID)
self._logger:debug("Adding supply hub commands for group: " .. tostring(groupID))
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
if group == nil then return end
local unit = group:getUnit(1)
@@ -482,7 +489,7 @@ end
function MissionCommandsHelper:AddCargoCommands(groupID)
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
if group == nil then return end
local unit = group:getUnit(1)
@@ -504,7 +511,7 @@ function MissionCommandsHelper:AddCargoCommands(groupID)
local cargo = self._supplyUnitsTracker:GetCargoInUnit(unit:getID())
if cargo then
for cargoType, amount in pairs(cargo) do
local cargoConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(cargoType)
local cargoConfig = SupplyConfigHelper.getSupplyConfig(cargoType)
if cargoConfig then
for i = 1, amount do
local path = { [1] = folderNames.cargo }
@@ -531,7 +538,7 @@ function MissionCommandsHelper:addMissionFolders(groupId)
missionCommands.addSubMenuForGroup(groupId, folderNames.supplyHub)
end
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupId)
local group = DcsUtil.GetPlayerGroupByGroupID(groupId)
if group == nil then return end
local unit = group:getUnit(1)
@@ -561,8 +568,4 @@ function MissionCommandsHelper:ResetFolders(groupID)
self:addMissionFolders(groupID)
end
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
if Spearhead.classes.stageClasses.helpers == nil then Spearhead.classes.stageClasses.helpers = {} end
Spearhead.classes.stageClasses.helpers.MissionCommandsHelper = MissionCommandsHelper
return MissionCommandsHelper
@@ -1,4 +1,6 @@
local Util = require("classes.util.Util")
---@alias SupplyType
---| "FARP_CRATE"
---| "SAM_CRATE"
@@ -65,24 +67,6 @@ local SupplyConfig = {
},
}
---@class MaxLoadConfig
---@field maxInternalLoad number
---@type table<string, MaxLoadConfig>
MaxLoadConfig = {
["Mi-8MT"] = {
maxInternalLoad = 4000,
},
["CH-47Fbl1"] = {
maxInternalLoad = 10000
},
["Mi-24P"] = {
maxInternalLoad = 2000
},
["UH-1H"] = {
maxInternalLoad = 2000
}
}
---@class SupplyConfigHelper
local SupplyConfigHelper = {}
@@ -92,7 +76,7 @@ local SupplyConfigHelper = {}
---@return SupplyConfig?
function SupplyConfigHelper.fromObjectName(name)
for configName, config in pairs(SupplyConfig) do
if Spearhead.Util.startswith(name, configName, true) == true then
if Util.startswith(name, configName, true) == true then
return config
end
end
@@ -104,11 +88,6 @@ function SupplyConfigHelper.getSupplyConfig(type)
return SupplyConfig[type]
end
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
if Spearhead.classes.stageClasses.helpers == nil then Spearhead.classes.stageClasses.helpers = {} end
if Spearhead.classes.stageClasses.helpers.supplies == nil then Spearhead.classes.stageClasses.helpers.supplies = {} end
Spearhead.classes.stageClasses.helpers.supplies.MaxLoadConfig = MaxLoadConfig
Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper = SupplyConfigHelper
return SupplyConfigHelper
@@ -1,4 +1,12 @@
local Logger = require("classes.util.Logger")
local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
local SpearheadEvents = require("classes.spearhead_events")
local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper")
local MaxLoadConfig = require("classes.stageClasses.helpers.MaxLoadConfig")
env.info("Spearhead SupplyUnitsTracker loaded")
---@class SupplyUnitsTracker
@@ -23,7 +31,7 @@ function SupplyUnitsTracker.getOrCreate(logLevel)
if singleton == nil then
singleton = setmetatable({}, SupplyUnitsTracker)
singleton._logger = Spearhead.LoggerTemplate.new("SupplyUnitsTracker", logLevel)
singleton._logger = Logger.new("SupplyUnitsTracker", logLevel)
singleton._unitPositions = {}
singleton._cargoInUnits = {}
singleton._supplyUnitsByName = {}
@@ -31,9 +39,9 @@ function SupplyUnitsTracker.getOrCreate(logLevel)
singleton._registeredHubs = {}
singleton._supplyUnitSpawnedListener = {}
singleton._commandsHelper = Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(singleton._logger.LogLevel)
singleton._commandsHelper = MissionCommandsHelper.getOrCreate(singleton._logger.LogLevel)
Spearhead.Events.AddOnPlayerEnterUnitListener(singleton)
SpearheadEvents.AddOnPlayerEnterUnitListener(singleton)
---@param selfA SupplyUnitsTracker
local function updateTask(selfA, time)
@@ -96,7 +104,7 @@ function SupplyUnitsTracker:AddOnSupplyUnitSpawnedListener(listener)
end
function SupplyUnitsTracker:Update()
local players = Spearhead.DcsUtil.getAllPlayerUnits()
local players = DcsUtil.getAllPlayerUnits()
for _, player in pairs(players) do
if player ~= nil and player:isExist() and self:IsSupplyUnit(player) == true then
self._supplyUnitsByName[player:getName()] = player
@@ -127,7 +135,7 @@ function SupplyUnitsTracker:AddCargoToUnit(unitID, crateType)
if unitID == nil or crateType == nil then return end
local unit = Spearhead.DcsUtil.GetPLayerUnitByID(unitID)
local unit = DcsUtil.GetPlayerUnitByID(unitID)
if unit == nil then return end
if self._cargoInUnits[unitID] == nil then
@@ -174,7 +182,7 @@ function SupplyUnitsTracker:UpdateWeightForUnit(unit)
local weight = 0
if self._cargoInUnits[tostring(unit:getID())] then
for crateType, count in pairs(self._cargoInUnits[tostring(unit:getID())]) do
local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
local crateConfig = SupplyConfigHelper.getSupplyConfig(crateType)
if crateConfig and count then
weight = weight + (crateConfig.weight * count)
end
@@ -197,7 +205,7 @@ function SupplyUnitsTracker:CheckUnitsInZones()
if enabled == true then
local zone = hub:GetZone()
if zone ~= nil then
if Spearhead.Util.is3dPointInZone(pos, zone) then
if Util.is3dPointInZone(pos, zone) then
self._commandsHelper:MarkUnitInSupplyHub(group:getID())
else
self._commandsHelper:MarkUnitOutsideSupplyHub(group:getID())
@@ -241,7 +249,7 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType)
self._logger:debug("Unload requested for unit: " .. unitID .. " crateType: " .. crateType)
local unit = Spearhead.DcsUtil.GetPLayerUnitByID(unitID)
local unit = DcsUtil.GetPlayerUnitByID(unitID)
if unit == nil or unit:isExist() == false then return end
local group = unit:getGroup()
if group == nil then
@@ -251,7 +259,7 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType)
self:RemoveCargoFromUnit(unitID, crateType)
self:UpdateWeightForUnit(unit)
local cargoConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
local cargoConfig = SupplyConfigHelper.getSupplyConfig(crateType)
if cargoConfig == nil then
self._logger:error("Invalid crate type: " .. crateType)
@@ -285,10 +293,10 @@ function SupplyUnitsTracker:UnitRequestCrateLoading(groupID, crateType)
self._logger:debug("UnitRequestCrateLoading called with groupID: " .. groupID .. " and crateType: " .. crateType)
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
if group ~= nil then
local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
local crateConfig = SupplyConfigHelper.getSupplyConfig(crateType)
if crateConfig == nil then
self._logger:error("Invalid crate type: " .. crateType)
return
@@ -341,7 +349,7 @@ end
---@return boolean
function SupplyUnitsTracker:TryLoadCrateInUnit(unit, crateType)
local crateConfigA = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
local crateConfigA = SupplyConfigHelper.getSupplyConfig(crateType)
if crateConfigA == nil then
trigger.action.outTextForUnit(unit:getID(), "Invalid crate type: " .. crateType, 5)
return false
@@ -354,7 +362,7 @@ function SupplyUnitsTracker:TryLoadCrateInUnit(unit, crateType)
end
end
local unitConfig = Spearhead.classes.stageClasses.helpers.supplies.MaxLoadConfig[unit:getTypeName()]
local unitConfig = MaxLoadConfig[unit:getTypeName()]
if unitConfig == nil then
trigger.action.outTextForUnit(unit:getID(), "Your unit type is not configured for logistics: " .. crateType, 5)
self._logger:error("Invalid unit type: " .. unit:getTypeName())
@@ -383,10 +391,10 @@ end
---@param crateType CrateType
function SupplyUnitsTracker:UnitRequestCrateSpawn(groupID, crateType)
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
if group == nil then
local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
local crateConfig = SupplyConfigHelper.getSupplyConfig(crateType)
if crateConfig == nil then
self._logger:error("Invalid crate type: " .. crateType)
return
@@ -446,9 +454,4 @@ function SupplyUnitsTracker:GetCargoPlacePosition(unit)
end
if Spearhead == nil then Spearhead = {} end
if Spearhead.classes == nil then Spearhead.classes = {} end
if Spearhead.classes.stageClasses == nil then Spearhead.classes.stageClasses = {} end
if Spearhead.classes.stageClasses.helpers == nil then Spearhead.classes.stageClasses.helpers = {} end
Spearhead.classes.stageClasses.helpers.SupplyUnitsTracker = SupplyUnitsTracker
return SupplyUnitsTracker
@@ -1,4 +1,10 @@
local Mission = require("classes.stageClasses.missions.baseMissions.Mission")
local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
local SupplyUnitsTracker = require("classes.stageClasses.helpers.SupplyUnitsTracker")
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
local GlobalConfig = require("classes.configuration.GlobalConfig")
local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper")
---@class BuildableMission : Mission, SupplyUnitSpawnedListener
---@field private _requiredKilos number
@@ -27,7 +33,6 @@ BuildableMission.__index = BuildableMission
---@param logger Logger
function BuildableMission.new(database, logger, targetZone, noLandingZone, requiredKilos, requiredCrateType)
local Mission = Spearhead.classes.stageClasses.missions.baseMissions.Mission
setmetatable(BuildableMission, Mission)
local self = setmetatable({}, { __index = BuildableMission })
@@ -42,7 +47,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi
if noLandingZone then
local verts = noLandingZone.verts
local enlarged = Spearhead.Util.enlargeConvexHull(verts, 300)
local enlarged = Util.enlargeConvexHull(verts, 300)
---@type SpearheadTriggerZone
local dropOfZone = {
@@ -71,7 +76,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi
self._onCrateDroppedOfListeners = {}
self._completeListeners = {}
self._markIDsPerGroup = {}
self._supplyUnitsTracker = Spearhead.classes.stageClasses.helpers.SupplyUnitsTracker.getOrCreate(logger.LogLevel)
self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate(logger.LogLevel)
self._state = "NEW"
@@ -82,7 +87,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi
self.priority = "secondary"
self._missionCommandsHelper = Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(self._logger.LogLevel)
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate(self._logger.LogLevel)
self._crateType = requiredCrateType
@@ -96,11 +101,11 @@ end
function BuildableMission:ShowBriefing(groupID)
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
if group == nil then return end
local unitType = Spearhead.DcsUtil.getUnitTypeFromGroup(group)
local coords = Spearhead.DcsUtil.convertVec2ToUnitUsableType(self.location, unitType)
local unitType = DcsUtil.getUnitTypeFromGroup(group)
local coords = DcsUtil.convertVec2ToUnitUsableType(self.location, unitType)
local siteType = "FARP"
if self._crateType == "SAM_CRATE" then
@@ -119,18 +124,18 @@ function BuildableMission:ShowBriefing(groupID)
"\n\n" ..
"NOTE: Do not land in the orange construction zone!"
trigger.action.outTextForGroup(groupID, briefing, Spearhead.GlobalConfig:getBriefingTime())
trigger.action.outTextForGroup(groupID, briefing, GlobalConfig:getBriefingTime())
end
function BuildableMission:MarkMissionAreaToGroup(groupID)
if self._markIDsPerGroup[groupID] then
Spearhead.DcsUtil.RemoveMark(self._markIDsPerGroup[groupID])
DcsUtil.RemoveMark(self._markIDsPerGroup[groupID])
end
local text = "[" .. self.code .. "] " .. self.name .. " | " .. self._crateType
local location = { x= self.location.x, y=land.getHeight(self.location), z=self.location.y }
local markID = Spearhead.DcsUtil.AddMarkToGroup(groupID, text, location)
local markID = DcsUtil.AddMarkToGroup(groupID, text, location)
self._markIDsPerGroup[groupID] = markID
end
@@ -163,7 +168,7 @@ function BuildableMission:SpawnActive()
local lineColor = { r=230/255, g=93/255, b=49/255, a=1}
---@type DrawColor
local fillColor = { r=230/255, g=93/255, b=49/255, a=0.2}
self._noLandingZoneId = Spearhead.DcsUtil.DrawZone(self._noLandingZone, lineColor, fillColor, 6)
self._noLandingZoneId = DcsUtil.DrawZone(self._noLandingZone, lineColor, fillColor, 6)
if self._dropOffZone == nil then
self._logger:error("No drop off zone found for mission: " .. self.code)
@@ -172,7 +177,7 @@ function BuildableMission:SpawnActive()
local lineColor2 = { r=0, g=0, b=1, a=1}
local fillColor2 = { r=0, g=0, b=1, a=0}
self._dropOffZoneId = Spearhead.DcsUtil.DrawZone(self._dropOffZone, lineColor2, fillColor2, 6)
self._dropOffZoneId = DcsUtil.DrawZone(self._dropOffZone, lineColor2, fillColor2, 6)
---@param selfA BuildableMission
---@param time number
@@ -230,17 +235,17 @@ function BuildableMission:CheckCratesInZone()
local crates = self._supplyUnitsTracker:GetCargoCratesDropped()
for _, staticObject in pairs(crates) do
if staticObject and staticObject:isExist() and Spearhead.Util.startswith(staticObject:getName(), self._crateType, true) then
if staticObject and staticObject:isExist() and Util.startswith(staticObject:getName(), self._crateType, true) then
local pos = staticObject:getPoint()
if Spearhead.Util.is3dPointInZone(pos, self._dropOffZone) then
if Util.is3dPointInZone(pos, self._dropOffZone) then
table.insert(foundCrates, staticObject)
end
end
end
for _, foundCrate in pairs(foundCrates) do
local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.fromObjectName(foundCrate:getName())
local crateConfig = SupplyConfigHelper.fromObjectName(foundCrate:getName())
if crateConfig then
self._droppedKilos = self._droppedKilos + crateConfig.weight
foundCrate:destroy()
@@ -249,8 +254,8 @@ function BuildableMission:CheckCratesInZone()
end
if self._droppedKilos >= self._requiredKilos then
Spearhead.DcsUtil.RemoveMark(self._noLandingZoneId)
Spearhead.DcsUtil.RemoveMark(self._dropOffZoneId)
DcsUtil.RemoveMark(self._noLandingZoneId)
DcsUtil.RemoveMark(self._dropOffZoneId)
self:NotifyMissionComplete()
self._state = "COMPLETED"
end
@@ -258,7 +263,7 @@ function BuildableMission:CheckCratesInZone()
if self._state == "COMPLETED" then
for groupID, markID in pairs(self._markIDsPerGroup) do
if markID then
Spearhead.DcsUtil.RemoveMark(markID)
DcsUtil.RemoveMark(markID)
self._markIDsPerGroup[groupID] = nil
end
end
@@ -267,7 +272,4 @@ function BuildableMission:CheckCratesInZone()
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.missions then Spearhead.classes.stageClasses.missions = {} end
Spearhead.classes.stageClasses.missions.BuildableMission = BuildableMission
return BuildableMission
@@ -537,9 +537,4 @@ function RunwayStrikeMission:RunwayToSpearheadZone(runway)
}
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.missions then Spearhead.classes.stageClasses.missions = {} end
Spearhead.classes.stageClasses.missions.RunwayStrikeMission = RunwayStrikeMission
return RunwayStrikeMission
@@ -517,7 +517,4 @@ function ZoneMission:MarkLastContact(unit)
self._lastContactMarkerID = Spearhead.DcsUtil.AddMarkToAll("Last Contact: " .. self.name .. " [" .. self.code .. "]", point)
end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.missions then Spearhead.classes.stageClasses.missions = {} end
Spearhead.classes.stageClasses.missions.ZoneMission = ZoneMission
return ZoneMission
@@ -1,5 +1,8 @@
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
local DcsUtil = require("classes.util.DcsUtil")
local Util = require("classes.util.Util")
local GlobalConfig = require("classes.configuration.GlobalConfig")
---@class Mission
---@field name string
@@ -49,7 +52,7 @@ function Mission.newSuper(self, zoneName, missionName, missionType, missionBrief
self.location = database:GetLocationForMissionZone(zoneName)
self.missionTypeDisplay = self.missionType
self._missionCommandsHelper = Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(logger.LogLevel)
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate(logger.LogLevel)
return true, "success"
end
@@ -77,11 +80,11 @@ end
---@param groupId number
function Mission:ShowBriefing(groupId)
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupId)
local group = DcsUtil.GetPlayerGroupByGroupID(groupId)
if group == nil then return end
local unitType = Spearhead.DcsUtil.getUnitTypeFromGroup(group)
local coords = Spearhead.DcsUtil.convertVec2ToUnitUsableType(self.location, unitType)
local unitType = DcsUtil.getUnitTypeFromGroup(group)
local coords = DcsUtil.convertVec2ToUnitUsableType(self.location, unitType)
self._logger:debug("Coords converted: " .. coords)
local stateString = self:ToStateString()
@@ -89,12 +92,12 @@ function Mission:ShowBriefing(groupId)
local briefing = self._missionBriefing
briefing = Spearhead.Util.replaceString(briefing, "{{coords}}", coords)
briefing = Spearhead.Util.replaceString(briefing, "{{ coords }}", coords)
briefing = Util.replaceString(briefing, "{{coords}}", coords)
briefing = Util.replaceString(briefing, "{{ coords }}", coords)
local text = "Mission [" ..
self.code .. "] " .. self.name .. "\n \n" .. briefing .. " \n \n" .. stateString
trigger.action.outTextForGroup(groupId, text, Spearhead.GlobalConfig:getBriefingTime());
trigger.action.outTextForGroup(groupId, text, GlobalConfig:getBriefingTime());
end
@@ -135,14 +138,6 @@ function Mission:ToStateString() return "status: in progress" end
--endregion
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.missions then Spearhead.classes.stageClasses.missions = {} end
if not Spearhead.classes.stageClasses.missions.baseMissions then Spearhead.classes.stageClasses.missions.baseMissions = {} end
Spearhead.classes.stageClasses.missions.baseMissions.Mission = Mission
do --aliases
--- @alias MissionPriority
@@ -168,4 +163,4 @@ do --aliases
end
return Mission
File diff suppressed because it is too large Load Diff
+75
View File
@@ -0,0 +1,75 @@
local Util = require("classes.util.Util")
--- @class Logger
--- @field LoggerName string the name of the logger
--- @field LogLevel string the log level of the logger
local LOGGER = {}
do
local PreFix = "Spearhead"
---comment
---@param logger_name any
---@param logLevel LogLevel
---@return Logger
function LOGGER.new(logger_name, logLevel)
LOGGER.__index = LOGGER
local self = setmetatable({}, LOGGER)
self.LoggerName = logger_name or "(loggername not set)"
self.LogLevel = logLevel or "INFO"
return self
end
---@param message any the message
function LOGGER:info(message)
if message == nil then
return
end
message = Util.toString(message)
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" then
env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
end
---comment
---@param message string
function LOGGER:warn(message)
if message == nil then
return
end
message = Util.toString(message)
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" then
env.warning("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
end
---@param message any -- the message
function LOGGER:error(message)
if message == nil then
return
end
message = Util.toString(message)
if self.LogLevel == "INFO" or self.LogLevel == "DEBUG" or self.LogLevel == "WARN" or self.LogLevel == "ERROR" then
env.error("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "] " .. message)
end
end
---@param message any the message
function LOGGER:debug(message)
if message == nil then
return
end
message = Util.toString(message)
if self.LogLevel == "DEBUG" then
env.info("[" .. PreFix .. "]" .. "[" .. self.LoggerName .. "][DEBUG] " .. message)
end
end
end
return LOGGER
@@ -0,0 +1,26 @@
---@class MissionEditingWarnings
local MissionEditingWarnings = {}
function MissionEditingWarnings.Add(warningMessage)
table.insert(MissionEditingWarnings, warningMessage or "skip")
end
---@param logger Logger
function MissionEditingWarnings.WriteAll(logger)
if not logger then
return
end
if not MissionEditingWarnings or #MissionEditingWarnings == 0 then
return
end
logger:warn("Mission Editor Warnings:")
for _, warning in ipairs(MissionEditingWarnings) do
logger:warn("- " .. warning)
end
end
return MissionEditingWarnings
+503
View File
@@ -0,0 +1,503 @@
---@class Util
local UTIL = {}
do -- INIT UTIL
---splits a string in sub parts by seperator
---@param input string
---@param seperator string
---@return table result list of strings
function UTIL.split_string(input, seperator)
if seperator == nil then
seperator = " "
end
local result = {}
if input == nil then
return result
end
for str in string.gmatch(input, "[^" .. seperator .. "]+") do
table.insert(result, str)
end
return result
end
---comment
---@param table any
---@return number
function UTIL.tableLength(table)
if table == nil then return 0 end
local count = 0
for _ in pairs(table) do count = count + 1 end
return count
end
---@param orig table
---@return table copy
function UTIL.deepCopyTable(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[UTIL.deepCopyTable(orig_key)] = UTIL.deepCopyTable(orig_value)
end
setmetatable(copy, UTIL.deepCopyTable(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
---Gets a random from the list
---@param list Array
---@return any @random element from the list
function UTIL.randomFromList(list)
local max = #list
if max == 0 or max == nil then
return nil
end
local random = math.random(0, max)
if random == 0 then random = 1 end
return list[random]
end
---@param list Array
---@param start number start
---@param n number length
---@return Array
function UTIL.sublist(list, start, n)
local result = {}
for i = start, n do
result[#result + 1] = list[i]
end
return result
end
---@param str string
---@param find string
---@param replace string
---@return string
function UTIL.replaceString(str, find, replace)
if str == nil then return "" end
if find == nil or replace == nil then return str end
local result = str:gsub(find, replace)
return result
end
local function table_print(tt, indent, done)
done = done or {}
indent = indent or 0
if type(tt) == "table" then
local sb = {}
for key, value in pairs(tt) do
table.insert(sb, string.rep(" ", indent)) -- indent it
if type(value) == "table" and not done[value] then
done[value] = true
table.insert(sb, "[\"" ..key .. "\"]" .. " = {\n");
table.insert(sb, table_print(value, indent + 2, done))
table.insert(sb, string.rep(" ", indent)) -- indent it
table.insert(sb, "},\n");
elseif "number" == type(key) then
table.insert(sb, string.format("\"%s\",\n", tostring(value)))
else
table.insert(sb, string.format(
"[\"%s\"] = \"%s\",\n", tostring(key), tostring(value)))
end
end
return table.concat(sb)
else
return tt .. "\n"
end
end
---comment
---@param str string
---@param findable string
---@param ignoreCase boolean?
---@return boolean
UTIL.startswith = function(str, findable, ignoreCase)
if ignoreCase == true then
return string.lower(str):find('^' .. string.lower(findable)) ~= nil
end
return str:find('^' .. findable) ~= nil
end
---comment
---@param str string
---@param findable string
---@return boolean
UTIL.strContains = function(str, findable)
return str:find(findable) ~= nil
end
---comment
---@param str string
---@param findableTable table
---@return boolean
UTIL.startswithAny = function(str, findableTable)
for key, value in pairs(findableTable) do
if type(value) == "string" and UTIL.startswith(str, value) then return true end
end
return false
end
function UTIL.toString(something)
if something == nil then
return "nil"
elseif "table" == type(something) then
return table_print(something)
elseif "string" == type(something) then
return something
else
return tostring(something)
end
end
---comment
---@param a Vec2
---@param b Vec2
---@return number
function UTIL.VectorDistance2d(a, b)
return math.sqrt((b.x - a.x) ^ 2 + (b.y - a.y) ^ 2)
end
---comment
---@param a Vec3
---@param b Vec3
---@return number
function UTIL.VectorDistance3d(a, b)
return UTIL.vectorMagnitude({ x = a.x - b.x, y = a.y - b.y, z = a.z - b.z })
end
---comment
---@param vec Vec3
---@return number
function UTIL.vectorMagnitude(vec)
return (vec.x ^ 2 + vec.y ^ 2 + vec.z ^ 2) ^ 0.5
end
---@param vec Vec3
---@return Vec3
function UTIL.vectorNormalize(vec)
local magnitude = UTIL.vectorMagnitude(vec)
if magnitude == 0 then
return { x = 0, y = 0, z = 0 }
end
return { x = vec.x / magnitude, y = vec.y / magnitude, z = vec.z / magnitude }
end
---@param vec Vec2
---@param direction number @in degrees
---@param distance number
---@return Vec2
function UTIL.vectorMove(vec, direction, distance)
local rad = math.rad(direction)
local x = vec.x + (math.cos(rad) * distance)
local y = vec.y + (math.sin(rad) * distance)
return { x = x, y = y}
end
---comment
---@param vec1 Vec2
---@param vec2 Vec2
---@return number in degrees
function UTIL.vectorHeadingFromTo(vec1, vec2)
local dx = vec2.x - vec1.x
local dy = vec2.y - vec1.y
local heading = math.deg(math.atan2(dy, dx))
if heading < 0 then
heading = heading + 360
end
return heading
end
---@param vec1 Vec3
---@param vec2 Vec3
---@return number alignment a number in range [-1,1]. > 0 same direction. < 0 opposite direction
function UTIL.vectorAlignment(vec1, vec2)
local vec1Norm = UTIL.vectorNormalize(vec1)
local vec2Norm = UTIL.vectorNormalize(vec2)
return ((vec1Norm.x * vec2Norm.x) + (vec1Norm.y * vec2Norm.y) + (vec1Norm.z * vec2Norm.z))
end
local function isInComplexPolygon(polygon, x, y)
local function getEdges(poly)
local result = {}
for i = 1, #poly do
local point1 = poly[i]
local point2Index = i + 1
if point2Index > #poly then point2Index = 1 end
local point2 = poly[point2Index]
local edge = { x1 = point1.x, z1 = point1.y, x2 = point2.x, z2 = point2.y }
table.insert(result, edge)
end
return result
end
local edges = getEdges(polygon)
local count = 0;
for _, edge in pairs(edges) do
if (x < edge.x1) ~= (x < edge.x2) and y < edge.z1 + ((x - edge.x1) / (edge.x2 - edge.x1)) * (edge.z2 - edge.z1) then
count = count + 1
-- if (yp < y1) != (yp < y2) and xp < x1 + ((yp-y1)/(y2-y1))*(x2-x1) then
-- count = count + 1
end
end
return count % 2 == 1
end
---comment
---@param polygon Array<Vec2> of pairs { x, y }
---@param x number X location
---@param y number Y location
---@return boolean
function UTIL.IsPointInPolygon(polygon, x, y)
return isInComplexPolygon(polygon, x, y)
end
---@param point Vec3
---@param zone SpearheadTriggerZone
function UTIL.is3dPointInZone(point, zone)
if zone.zone_type == "Polygon" and zone.verts then
if UTIL.IsPointInPolygon(zone.verts, point.x, point.z) == true then
return true
end
else
if (((point.x - zone.location.x) ^ 2 + (point.z - zone.location.y) ^ 2) ^ 0.5 <= zone.radius) then
return true
end
end
return false
end
---@param point Vec2
---@param zone SpearheadTriggerZone
function UTIL.is2dPointInZone(point, zone)
if zone.zone_type == "Polygon" and zone.verts then
if UTIL.IsPointInPolygon(zone.verts, point.x, point.y) == true then
return true
end
else
if (((point.x - zone.location.x) ^ 2 + (point.y - zone.location.y) ^ 2) ^ 0.5 <= zone.radius) then
return true
end
end
return false
end
---comment
---@param points Array<Vec2> points
---@return Array<Vec2> hullPoints
function UTIL.getConvexHull(points)
if #points == 0 then
return {}
end
---comment
---@param a Vec2
---@param b Vec2
---@param c Vec2
---@return boolean
local function ccw(a, b, c)
return (b.y - a.y) * (c.x - a.x) > (b.x - a.x) * (c.y - a.y)
end
table.sort(points, function(left, right)
return left.y < right.y
end)
local hull = {}
-- lower hull
for _, point in pairs(points) do
while #hull >= 2 and not ccw(hull[#hull - 1], hull[#hull], point) do
table.remove(hull, #hull)
end
table.insert(hull, point)
end
-- upper hull
local t = #hull + 1
for i = #points, 1, -1 do
local point = points[i]
while #hull >= t and not ccw(hull[#hull - 1], hull[#hull], point) do
table.remove(hull, #hull)
end
table.insert(hull, point)
end
table.remove(hull, #hull)
return hull
end
---Splits points into clusters with at least minSeparation between clusters, returns convex hull for each cluster
---@param points Array<Vec2>
---@param minSeparation number
---@return Array<Array<Vec2>> hulls
function UTIL.getSeparatedConvexHulls(points, minSeparation)
if #points == 0 then return {} end
-- Simple clustering: group points that are within minSeparation of each other
local clusters = {}
local assigned = {}
for i, p in ipairs(points) do
if not assigned[i] then
local cluster = { p }
assigned[i] = true
-- Find all points close to p (BFS)
local queue = { i }
while #queue > 0 do
local idx = table.remove(queue)
local base = points[idx]
for j, q in ipairs(points) do
if not assigned[j] then
local dx = base.x - q.x
local dy = base.y - q.y
if (dx * dx + dy * dy) <= (minSeparation * minSeparation) then
table.insert(cluster, q)
assigned[j] = true
table.insert(queue, j)
end
end
end
end
table.insert(clusters, cluster)
end
end
-- Compute convex hull for each cluster
local hulls = {}
for _, cluster in ipairs(clusters) do
local hull = UTIL.getConvexHull(cluster)
if #hull > 0 then
table.insert(hulls, hull)
end
end
return hulls
end
---@param points Array<Vec2>
function UTIL.enlargeConvexHull(points, meters)
if points == nil or #points == 0 then
return {}
end
---@type Array<Vec2>
local allpoints = {}
for _, point in pairs(points) do
table.insert(allpoints, point)
allpoints[#allpoints + 1] = point
allpoints[#allpoints+1] = { x = point.x + meters, y = point.y, }
allpoints[#allpoints+1] = { x = point.x - meters, y = point.y, }
allpoints[#allpoints+1] = { x = point.x, y = point.y + meters, }
allpoints[#allpoints+1] = { x = point.x, y = point.y - meters, }
allpoints[#allpoints+1] = { x = point.x + math.cos(math.rad(45)) * meters, y = point.y + math.sin(math.rad(45)) * meters, }
allpoints[#allpoints+1] = { x = point.x - math.cos(math.rad(45)) * meters, y = point.y - math.sin(math.rad(45)) * meters, }
allpoints[#allpoints+1] = { x = point.x - math.cos(math.rad(45)) * meters, y = point.y + math.sin(math.rad(45)) * meters, }
allpoints[#allpoints+1] = { x = point.x + math.cos(math.rad(45)) * meters, y = point.y - math.sin(math.rad(45)) * meters, }
end
return UTIL.getConvexHull(allpoints)
end
---Returns hull points visible from origin (not blocked by hull edges)
---@param hull Array<Vec2>
---@param origin Vec2
---@return Array<Vec2>
function UTIL.GetVisibleHullPointsFromOrigin(hull, origin)
local function segmentsIntersect(a, b, c, d)
-- Helper: returns true if segment ab intersects cd (excluding endpoints)
local function ccw(p1, p2, p3)
return (p3.y - p1.y) * (p2.x - p1.x) > (p2.y - p1.y) * (p3.x - p1.x)
end
return (ccw(a, c, d) ~= ccw(b, c, d)) and (ccw(a, b, c) ~= ccw(a, b, d))
end
local n = #hull
local visible = {}
for i = 1, n do
local p = hull[i]
local isVisible = true
-- Check against all hull edges except those incident to p
for j = 1, n do
local a = hull[j]
local b = hull[(j % n) + 1]
-- skip edges incident to p
if (a ~= p and b ~= p) then
if segmentsIntersect(origin, p, a, b) then
isVisible = false
break
end
end
end
if isVisible then
table.insert(visible, p)
end
end
return visible
end
---Returns the two tangent points ("scratch points") from origin to the convex hull
---@param hull Array<Vec2>
---@param origin Vec2
---@return Array<Vec2>
function UTIL.GetTangentHullPointsFromOrigin(hull, origin)
if hull == nil or #hull <= 0 then
return {}
end
local function orientation(a, b, c)
-- 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)
end
local n = #hull
if n == 0 then return {} end
if n == 1 then return { hull[1] } end
-- Find left tangent: the hull point where all other points are to the right of the line from origin to that point
local function findTangent(isLeft)
local best = 1
for i = 2, n do
local o = orientation(origin, hull[best], hull[i])
if (isLeft and o < 0) or (not isLeft and o > 0) then
best = i
end
end
return hull[best]
end
local leftTangent = findTangent(true)
local rightTangent = findTangent(false)
-- If tangents are the same (can happen if origin is colinear), only return one
if leftTangent.x == rightTangent.x and leftTangent.y == rightTangent.y then
return { leftTangent }
else
return { leftTangent, rightTangent }
end
end
end
return UTIL
+96
View File
@@ -0,0 +1,96 @@
--Single player purpose
local Logger = require("classes.util.Logger")
local DcsUtil = require("classes.util.DcsUtil")
local Database = require("classes.spearhead_db")
local SpearheadEvents = require("classes.spearhead_events")
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
local CapConfig = require("classes.configuration.CapConfig")
local StageConfig = require("classes.configuration.StageConfig")
local Persistence = require("classes.persistence.Persistence")
local SpawnManager = require("classes.helpers.SpawnManager")
local DetectionManager = require("classes.capClasses.detection.DetectionManager")
local GlobalCapManager = require("classes.capClasses.GlobalCapManager")
local GlobalStageManager = require("classes.stageClasses.GlobalStageManager")
local GlobalFleetManager = require("classes.fleetClasses.GlobalFleetManager")
local MissionEditorWarnings = require("classes.util.MissionEditorWarnings")
local defaultLogLevel = "INFO"
if SpearheadConfig and SpearheadConfig.debugEnabled == true then
defaultLogLevel = "DEBUG"
end
local startTime = timer.getTime() * 1000
SpearheadEvents.Init(defaultLogLevel)
local dbLogger = Logger.new("database", defaultLogLevel)
local standardLogger = Logger.new("", defaultLogLevel)
local databaseManager = Database.New(dbLogger)
MissionCommandsHelper.getOrCreate(defaultLogLevel) -- initiate
local capConfig = CapConfig:new();
local stageConfig = StageConfig:new();
local startingStage = stageConfig.startingStage or 1
if SpearheadConfig and SpearheadConfig.Persistence and SpearheadConfig.Persistence.enabled == true then
standardLogger:info("Persistence enabled")
local persistenceLogger = Logger.new("Persistence", defaultLogLevel)
Persistence.Init(persistenceLogger)
local persistanceStage = Persistence.GetActiveStage()
if persistanceStage then
standardLogger:info("Persistance activated and using persistant active stage: " .. persistanceStage)
startingStage = persistanceStage
end
else
standardLogger:info("Persistence disabled")
end
local spawnLogger = Logger.new("SpawnManager", defaultLogLevel)
local spawnManager = SpawnManager.new(spawnLogger)
local detectionLogger = Logger.new("DetectionManager", defaultLogLevel)
local detectionManager = DetectionManager.New(detectionLogger)
GlobalCapManager.start(databaseManager, capConfig, detectionManager, stageConfig, defaultLogLevel, spawnManager)
GlobalStageManager.NewAndStart(databaseManager, stageConfig, defaultLogLevel, spawnManager)
GlobalFleetManager.start(databaseManager)
local SetStageDelayed = function(number, time)
SpearheadEvents.PublishStageNumberChanged(number)
return nil
end
timer.scheduleFunction(SetStageDelayed, startingStage, timer.getTime() + 3)
env.info(startTime .. "ms / " .. timer.getTime() * 1000 .. "ms")
local duration = (timer.getTime() * 1000) - startTime
standardLogger:info("Spearhead Initialisation duration: " .. tostring(duration) .. "ms")
local missionEditorWarningsLogger = Logger.new("MissionEditorWarnings", defaultLogLevel)
MissionEditorWarnings.WriteAll(missionEditorWarningsLogger)
GlobalStageManager:printFullOverview()
--Check lines of code in directory per file:
-- Get-ChildItem . -Include *.lua -Recurse | foreach {""+(Get-Content $_).Count + " => " + $_.name }; GCI . -Include *.lua* -Recurse | foreach{(GC $_).Count} | measure-object -sum | % Sum
-- find . -name '*.lua' | xargs wc -l
--- ==================== DEBUG ORDER OR ZONE VEC ===========================
-- local zone = Spearhead.DcsUtil.getZoneByName("MISSIONSTAGE_99")
-- local count = Spearhead.Util.tableLength(zone.verts)
-- for i = 1, count - 1 do
-- local a = zone.verts[i]
-- local b = zone.verts[i+1]
-- local color = {0,0,0,1}
-- color[i] = 1
-- trigger.action.textToAll(-1, 46+i , { x= a.x, y = 0, z = a.z } , color, {0,0,0}, 24 , true , "" .. i )
-- trigger.action.lineToAll(-1 , 56+i , { x= a.x, y = 0, z = a.z } , { x = b.x, y = 0, z = b.z } , color , 1, true)
-- end