Buildable (#36)

- Buildable missions now working. 
- FARPS and BLUESAM zones are now buildable. 
- Secondary Logistics missions are created as buildables become available. 
- Logistic missions can be "marked" with a MAP marker. 
- Supplies can only be picked up in a SUPPLYHUB zone. 
- SUPPLYHUB zones are active once their parents are active. A supplyhub parent can be oneof: FARP, AIRBASE, STAGE. 
- Required supplies for a zone can be configured in kilos. 
- Crates can be picked up with 1000 or 2000 kilo per crate. 
- Max load for a helicopter is set based on public data. 
- TO COME: Sling load options
This commit is contained in:
2025-05-18 20:08:26 +02:00
committed by GitHub
parent 5b6ea49217
commit 3e65df9d20
21 changed files with 1708 additions and 181 deletions
@@ -5,10 +5,13 @@
---@field lastUpdate number @last update time
---@field updateContinuous fun(self: MissionCommandsHelper, time: number): number @function to update commands continuously
---@field pinnedByGroup table<string, Mission> @table of pinned missions by group ID
---@field private _supplyHubGroups table<string, boolean> @table of supply hub groups by their ID
---@field private _logger Logger @logger instance for logging
---@field private _supplyUnitsTracker SupplyUnitsTracker @supply units tracker instance
local MissionCommandsHelper = {}
MissionCommandsHelper.__index = MissionCommandsHelper
local id = 0
local instance = nil
@@ -16,21 +19,25 @@ local instance = nil
---@param logLevel string @log level for the logger
function MissionCommandsHelper.getOrCreate(logLevel)
if instance == nil then
local self = setmetatable({}, MissionCommandsHelper)
instance = setmetatable({}, MissionCommandsHelper)
self._logger = Spearhead.LoggerTemplate.new("MissionCommandsHelper", logLevel)
instance._logger = Spearhead.LoggerTemplate.new("MissionCommandsHelper", logLevel)
self.missionsByCode = {}
self.enabledByCode = {}
self.updateNeeded = false
self.pinnedByGroup = {}
self.lastUpdate = 0
instance._logger:info("Creating MissionCommandsHelper instance")
instance.missionsByCode = {}
instance.enabledByCode = {}
instance.updateNeeded = false
instance.pinnedByGroup = {}
instance.lastUpdate = 0
instance._supplyHubGroups = {}
instance._supplyUnitsTracker = Spearhead.classes.stageClasses.helpers.SupplyUnitsTracker.getOrCreate(logLevel)
---comment
---@param selfA MissionCommandsHelper
---@param time number
---@return number
self.updateContinuous = function(selfA, time)
instance.updateContinuous = function(selfA, time)
if selfA.updateNeeded == false then
return time + 10
end
@@ -49,14 +56,63 @@ function MissionCommandsHelper.getOrCreate(logLevel)
return time + 10
end
timer.scheduleFunction(self.updateContinuous, self, timer.getTime() + 5)
Spearhead.Events.AddOnPlayerEnterUnitListener(self)
instance = self
timer.scheduleFunction(instance.updateContinuous, instance, timer.getTime() + 5)
Spearhead.Events.AddOnPlayerEnterUnitListener(instance)
end
return instance
end
---@param mission Mission
function MissionCommandsHelper:AddMissionToCommands(mission)
self._logger:debug("Adding mission to commands: [" .. mission.code .. "]" .. mission.name)
self.missionsByCode[tostring(mission.code)] = mission
self.enabledByCode[tostring(mission.code)] = true
self.updateNeeded = true
end
---Removes a mission from the F10 commands menu
---@param mission Mission
function MissionCommandsHelper:RemoveMissionToCommands(mission)
self.enabledByCode[tostring(mission.code)] = false
self.updateNeeded = true
end
---@param groupID number
function MissionCommandsHelper:MarkUnitInSupplyHub(groupID)
self._logger:debug("Marking unit in supply hub: " .. tostring(groupID))
local updateNeeded = false
if self._supplyHubGroups[tostring(groupID)] ~= true then
updateNeeded = true
end
self._supplyHubGroups[tostring(groupID)] = true
if updateNeeded == true then self:updateCommandsForGroup(groupID) end
end
---@param groupID number
function MissionCommandsHelper:MarkUnitOutsideSupplyHub(groupID)
self._logger:debug("Marking unit outide supply hub: " .. tostring(groupID))
local updateNeeded = false
if self._supplyHubGroups[tostring(groupID)] == true then
updateNeeded = true
end
self._supplyHubGroups[tostring(groupID)] = false
if updateNeeded == true then self:updateCommandsForGroup(groupID) end
end
---@param unit Unit
function MissionCommandsHelper:OnPlayerEntersUnit(unit)
if unit then
local group = unit:getGroup()
if group then self:updateCommandsForGroup(group:getID()) end
end
end
---@class MissionBriefingRequestedArgs
---@field mission Mission @the mission object
@@ -72,6 +128,22 @@ local missionBriefingRequested = function(args)
mission:ShowBriefing(groupID)
end
---@class MarkRequestedArgs
---@field mission Mission @the mission object
---@field groupId integer @the group ID of the player requesting the briefing
---@param args MarkRequestedArgs
local markRequested = function(args)
local mission = args.mission
if not mission then return end
if mission.missionType == "LOGISTICS" then
mission:MarkMissionAreaToGroup(args.groupId)
end
end
---@class PinMissionCommandArgs
---@field self MissionCommandsHelper @the MissionCommandsHelper instance
@@ -114,7 +186,7 @@ function MissionCommandsHelper:AddOverviewCommand(groupID)
end
end
return string.format("[%s] %-15s %-20s %10s nM\n", mission.code, mission.missionTypeDisplay, mission.name, distanceText)
return string.format("[%s]\t%s \t%s \t%s nM\n", mission.code, mission.missionTypeDisplay, mission.name, distanceText)
end
---Primary missions
@@ -161,11 +233,11 @@ function MissionCommandsHelper:AddPinnedMission(groupID)
end
---comment
---@param groupID number
function MissionCommandsHelper:updateCommandsForGroup(groupID)
self._logger:debug("Updating commands for group: " .. tostring(groupID))
self:AddPinnedMission(groupID)
self:AddOverviewCommand(groupID)
@@ -180,6 +252,9 @@ function MissionCommandsHelper:updateCommandsForGroup(groupID)
end
end
self:AddSupplyHubCommandsIfApplicable(groupID)
self:AddCargoCommands(groupID)
---@param id number
local clearView = function(id)
trigger.action.outTextForGroup(id, "clearing...", 1, true)
@@ -192,7 +267,9 @@ end
local folderNames = {
primary = "Primary Missions",
secondary = "Secondary Missions"
secondary = "Secondary Missions",
supplyHub = "Supply Hub",
cargo = "Cargo"
}
@@ -221,31 +298,135 @@ function MissionCommandsHelper:addMissionCommands(groupId, mission)
local missionFolderName = "[" .. mission.code .. "]" .. mission.name
missionCommands.addSubMenuForGroup(groupId, missionFolderName, path)
table.insert(path, missionFolderName)
missionCommands.addCommandForGroup(groupId, "Briefing", path, missionBriefingRequested,{ groupId = groupId, mission = mission })
missionCommands.addCommandForGroup(groupId, "Pin", path, pinMissionCommand, { self = self, groupId = groupId, mission = mission })
---@type MissionBriefingRequestedArgs
local missionBriefingRequestedArgs = { groupId = groupId, mission = mission }
missionCommands.addCommandForGroup(groupId, "Briefing", path, missionBriefingRequested,missionBriefingRequestedArgs)
---@type PinMissionCommandArgs
local pinMissionCommandArgs = { self = self, groupId = groupId, mission = mission }
missionCommands.addCommandForGroup(groupId, "Pin", path, pinMissionCommand, pinMissionCommandArgs)
if mission.missionType == "LOGISTICS" then
---@type MarkRequestedArgs
local markRequestArgs = { groupId = groupId, mission = mission }
missionCommands.addCommandForGroup(groupId, "Mark", path, markRequested, markRequestArgs)
end
end
end
---@param mission Mission
function MissionCommandsHelper:AddMissionToCommands(mission)
self._logger:debug("Adding mission to commands: [" .. mission.code .. "]" .. mission.name)
self.missionsByCode[tostring(mission.code)] = mission
self.enabledByCode[tostring(mission.code)] = true
self.updateNeeded = true
---@private
---@param groupID integer
function MissionCommandsHelper:AddSupplyHubCommandsIfApplicable(groupID)
if self._supplyHubGroups[tostring(groupID)] ~= true then return end
self._logger:debug("Adding supply hub commands for group: " .. tostring(groupID))
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
if group == nil then return end
local unit = group:getUnit(1)
if unit == nil then return end
---@class LoadCargoCommandParams
---@field unitID number
---@field groupID number
---@field crateType CrateType
---@field supplyUnitsTracker SupplyUnitsTracker
---comment
---@param params LoadCargoCommandParams
local loadCargoCommand = function(params)
local crateType = params.crateType
local supplyUnitsTracker = params.supplyUnitsTracker
if supplyUnitsTracker then
supplyUnitsTracker:UnitRequestCrateLoading(params.groupID, crateType)
end
end
local path = { [1] = folderNames.supplyHub }
---@type LoadCargoCommandParams
local farpParams1000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "FARP_CRATE_1000", supplyUnitsTracker = self._supplyUnitsTracker }
missionCommands.addCommandForGroup(groupID, "Load FARP Crate (1000)", path, loadCargoCommand, farpParams1000)
---@type LoadCargoCommandParams
local farpParams2000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "FARP_CRATE_2000", supplyUnitsTracker = self._supplyUnitsTracker }
missionCommands.addCommandForGroup(groupID, "Load FARP Crate (2000)", path, loadCargoCommand, farpParams2000)
---@type LoadCargoCommandParams
local samParms1000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "FARP_CRATE_1000", supplyUnitsTracker = self._supplyUnitsTracker }
missionCommands.addCommandForGroup(groupID, "Load SAM Crate (1000)", path, loadCargoCommand, samParms1000)
---@type LoadCargoCommandParams
local samParms2000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "FARP_CRATE_2000", supplyUnitsTracker = self._supplyUnitsTracker }
missionCommands.addCommandForGroup(groupID, "Load SAM Crate (2000)", path, loadCargoCommand, samParms2000)
end
---Removes a mission from the F10 commands menu
---@param mission Mission
function MissionCommandsHelper:RemoveMissionToCommands(mission)
self.enabledByCode[tostring(mission.code)] = false
self.updateNeeded = true
function MissionCommandsHelper:AddCargoCommands(groupID)
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
if group == nil then return end
local unit = group:getUnit(1)
if unit == nil then return end
---@class UnloadCargoCommandParams
---@field unitID number
---@field crateType CrateType
---@field supplyUnitsTracker SupplyUnitsTracker
---comment
---@param params UnloadCargoCommandParams
local unloadCargoCommand = function(params)
local unitID = params.unitID
local crateType = params.crateType
params.supplyUnitsTracker:UnloadRequested(unitID, crateType)
end
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)
if cargoConfig then
for i = 1, amount do
local path = { [1] = folderNames.cargo }
---@type UnloadCargoCommandParams
local params = { unitID = unit:getID(), crateType = cargoType, supplyUnitsTracker = self._supplyUnitsTracker }
missionCommands.addCommandForGroup(groupID, "Unload " .. cargoConfig.displayName, path, unloadCargoCommand, params)
end
end
end
end
end
---@private
---@param groupId integer
function MissionCommandsHelper:addMissionFolders(groupId)
missionCommands.addSubMenuForGroup(groupId, folderNames.primary)
missionCommands.addSubMenuForGroup(groupId, folderNames.secondary)
if self._supplyHubGroups[tostring(groupId)] == true then
self._logger:debug("Adding supply hub commands folder for group: " .. tostring(groupId))
missionCommands.addSubMenuForGroup(groupId, folderNames.supplyHub)
end
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupId)
if group == nil then return end
local unit = group:getUnit(1)
if unit == nil then return end
local cargo = self._supplyUnitsTracker:GetCargoInUnit(unit:getID())
if cargo ~= nil then
missionCommands.addSubMenuForGroup(groupId, folderNames.cargo)
end
end
---@private
@@ -253,6 +434,8 @@ end
function MissionCommandsHelper:removeMissionFolders(groupId)
missionCommands.removeItemForGroup(groupId, { folderNames.primary })
missionCommands.removeItemForGroup(groupId, { folderNames.secondary })
missionCommands.removeItemForGroup(groupId, { folderNames.supplyHub })
missionCommands.removeItemForGroup(groupId, { folderNames.cargo })
end
---@private
@@ -264,15 +447,6 @@ function MissionCommandsHelper:ResetFolders(groupID)
self:addMissionFolders(groupID)
end
---comment
---@param unit Unit
function MissionCommandsHelper:OnPlayerEntersUnit(unit)
if unit then
local group = unit:getGroup()
if group then self:updateCommandsForGroup(group:getID()) end
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
@@ -0,0 +1,106 @@
---@alias SupplyType
---| "FARP_CRATE"
---| "SAM_CRATE"
---@alias CrateType
---| "FARP_CRATE_500"
---| "FARP_CRATE_1000"
---| "FARP_CRATE_2000"
---| "SAM_CRATE_500"
---| "SAM_CRATE_1000"
---| "SAM_CRATE_2000"
---@class SupplyConfig
---@field type SupplyType
---@field weight number
---@field staticType string
---@field displayName string
---@type table<CrateType, SupplyConfig>
local SupplyConfig = {
["FARP_CRATE_500"] = {
type = "FARP_CRATE",
weight = 500,
displayName = "FARP Crate (500)",
staticType = "container_cargo",
},
["FARP_CRATE_1000"] = {
type = "FARP_CRATE",
weight = 1000,
displayName = "FARP Crate (1000)",
staticType = "container_cargo",
},
["FARP_CRATE_2000"] = {
type = "FARP_CRATE",
weight = 2000,
displayName = "FARP Crate (2000)",
staticType = "container_cargo",
},
["SAM_CRATE_500"] = {
type = "SAM_CRATE",
weight = 1000,
displayName = "SAM Crate (500)",
staticType = "container_cargo",
},
["SAM_CRATE_1000"] = {
type = "SAM_CRATE",
weight = 1000,
displayName = "SAM Crate (1000)",
staticType = "container_cargo",
},
["SAM_CRATE_2000"] = {
type = "SAM_CRATE",
weight = 2000,
displayName = "SAM Crate (2000)",
staticType = "container_cargo",
},
}
---@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 = {}
---comment
---@param name string
---@return SupplyConfig?
function SupplyConfigHelper.fromObjectName(name)
for configName, config in pairs(SupplyConfig) do
if Spearhead.Util.startswith(name, configName, true) == true then
return config
end
end
return nil
end
---@param type CrateType
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
@@ -0,0 +1,407 @@
---@class SupplyUnitsTracker
---@field private _supplyUnitsByName table<string, Unit>
---@field private _cargoInUnits table<string, table<CrateType, number>>
---@field private _logger Logger
---@field private _unitPositions table<string, Vec3>
---@field private _commandsHelper MissionCommandsHelper
---@field private _droppedCrates table<string, StaticObject>
---@field private _registeredHubs table<SupplyHub, boolean>
local SupplyUnitsTracker = {}
SupplyUnitsTracker.__index = SupplyUnitsTracker
-- A single class tracking all units is more than enough.
local singleton = nil
---comment
---@param logLevel LogLevel
---@return SupplyUnitsTracker
function SupplyUnitsTracker.getOrCreate(logLevel)
if singleton == nil then
singleton = setmetatable({}, SupplyUnitsTracker)
singleton._logger = Spearhead.LoggerTemplate.new("SupplyUnitsTracker", logLevel)
singleton._unitPositions = {}
singleton._cargoInUnits = {}
singleton._supplyUnitsByName = {}
singleton._droppedCrates = {}
singleton._registeredHubs = {}
singleton._commandsHelper = Spearhead.classes.stageClasses.helpers.MissionCommandsHelper.getOrCreate(singleton._logger.LogLevel)
Spearhead.Events.AddOnPlayerEnterUnitListener(singleton)
---@param selfA SupplyUnitsTracker
local function updateTask(selfA, time)
selfA:Update()
return time + 15
end
timer.scheduleFunction(updateTask, singleton, timer.getTime() + 15)
---comment
---@param selfA SupplyUnitsTracker
---@param time number
---@return number
local function checkUnitsInZone(selfA, time)
pcall(function()
selfA:CheckUnitsInZones()
end)
return time + 5
end
timer.scheduleFunction(checkUnitsInZone, singleton, timer.getTime() + 5)
end
return singleton
end
---@param unit Unit
function SupplyUnitsTracker:OnPlayerEntersUnit(unit)
if unit == nil then return end
if self:IsSupplyUnit(unit) == true then
self._supplyUnitsByName[unit:getName()] = unit
end
end
function SupplyUnitsTracker:Update()
local players = Spearhead.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
end
end
end
---@private
function SupplyUnitsTracker:IsSupplyUnit(unit)
if unit == nil then return false end
if unit:hasAttribute("Transport helicopters") then
return true
end
return false
end
---comment
---@param unitID number
---@param crateType CrateType
function SupplyUnitsTracker:AddCargoToUnit(unitID, crateType)
if unitID == nil or crateType == nil then return end
local unit = Spearhead.DcsUtil.GetPLayerUnitByID(unitID)
if unit == nil then return end
if self._cargoInUnits[unitID] == nil then
self._cargoInUnits[unitID] = {}
end
if self._cargoInUnits[unitID][crateType] == nil then
self._cargoInUnits[unitID][crateType] = 0
end
self._cargoInUnits[unitID][crateType] = self._cargoInUnits[unitID][crateType] + 1
end
---@param unitID number
---@param crateType CrateType
function SupplyUnitsTracker:RemoveCargoFromUnit(unitID, crateType)
if unitID == nil or crateType == nil then return end
local unitIDStr = tostring(unitID)
if self._cargoInUnits[unitIDStr] == nil then return end
if self._cargoInUnits[unitIDStr][crateType] == nil then return end
self._cargoInUnits[unitIDStr][crateType] = self._cargoInUnits[unitIDStr][crateType] - 1
local hasCargo = false
for type, count in pairs(self._cargoInUnits[unitIDStr]) do
if count > 0 then
hasCargo = true
break
end
end
if hasCargo == false then
self._cargoInUnits[unitIDStr] = nil
end
end
function SupplyUnitsTracker:CheckUnitsInZones()
for name, unit in pairs(self._supplyUnitsByName) do
if unit ~= nil and unit:isExist() == true then
self._logger:debug("Checking unit: " .. unit:getName())
local pos = unit:getPoint()
local group = unit:getGroup()
for hub, enabled in pairs(self._registeredHubs) do
if enabled == true then
local zone = hub:GetZone()
if zone ~= nil then
if Spearhead.Util.is3dPointInZone(pos, zone) then
self._commandsHelper:MarkUnitInSupplyHub(group:getID())
else
self._commandsHelper:MarkUnitOutsideSupplyHub(group:getID())
end
end
end
end
self._unitPositions[unit:getID()] = pos
end
end
end
function SupplyUnitsTracker:RegisterHub(hub)
if hub == nil then return end
if self._registeredHubs[hub] == nil then
self._registeredHubs[hub] = true
end
end
---@param unitID number
---@return table<CrateType, number>?
function SupplyUnitsTracker:GetCargoInUnit(unitID)
if unitID == nil then return end
local unitIDStr = tostring(unitID)
if self._cargoInUnits[unitIDStr] == nil then return end
return self._cargoInUnits[unitIDStr]
end
---@return table<string, Unit>
function SupplyUnitsTracker:GetUnits()
return self._supplyUnitsByName
end
local cargoCount = 0
function SupplyUnitsTracker:UnloadRequested(unitID, crateType)
self._logger:debug("Unload requested for unit: " .. unitID .. " crateType: " .. crateType)
local unit = Spearhead.DcsUtil.GetPLayerUnitByID(unitID)
if unit == nil or unit:isExist() == false then return end
local group = unit:getGroup()
if group == nil then
return
end
self:RemoveCargoFromUnit(unitID, crateType)
local cargoConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
if cargoConfig == nil then
self._logger:error("Invalid crate type: " .. crateType)
return
end
local cargoPos = self:GetCargoPlacePosition(unit)
cargoCount = cargoCount + 1
local cargoSpawnObject = {
name = crateType .. "_" .. cargoCount,
type = cargoConfig.staticType,
x = cargoPos.x,
y = cargoPos.z,
}
local spawned = coalition.addStaticObject(unit:getCoalition(), cargoSpawnObject)
self._droppedCrates[cargoSpawnObject.name] = spawned
self._commandsHelper:updateCommandsForGroup(group:getID())
end
---@return table<string,StaticObject>
function SupplyUnitsTracker:GetCargoCratesDropped()
return self._droppedCrates
end
---Loads a crate directly into the unit
---@param groupID number
---@param crateType CrateType
function SupplyUnitsTracker:UnitRequestCrateLoading(groupID, crateType)
self._logger:debug("UnitRequestCrateLoading called with groupID: " .. groupID .. " and crateType: " .. crateType)
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
if group ~= nil then
local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
if crateConfig == nil then
self._logger:error("Invalid crate type: " .. crateType)
return
end
local unit = group:getUnit(1)
if unit == nil then return end
if unit:isExist() == false then return end
if unit:inAir() == true then
trigger.action.outTextForUnit(unit:getID(), "Land first before crates can be loaded", 10)
return
end
trigger.action.outTextForUnit(unit:getID(), "Loading crate of type " .. crateType, 13)
---@class LoadCargoParams
---@field self SupplyUnitsTracker
---@field unit Unit
---@field groupID number
---@field crateType CrateType
---@param params LoadCargoParams
local LoadCrateTask = function(params)
local loaded = params.self:TryLoadCrateInUnit(params.unit, params.crateType)
if loaded ~= false then
trigger.action.outTextForUnit(unit:getID(), "Loaded crate :" .. params.crateType, 10)
end
end
---@type LoadCargoParams
local params = {
self = self,
unit = unit,
crateType = crateType,
groupID = groupID
}
timer.scheduleFunction(LoadCrateTask, params, timer.getTime() + 15)
end
end
---comment
---@param unit Unit
---@param crateType CrateType
---@return boolean
function SupplyUnitsTracker:TryLoadCrateInUnit(unit, crateType)
local crateConfigA = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
if crateConfigA == nil then
trigger.action.outText("Invalid crate type: " .. crateType, 5)
return false
end
local currentWeight = 0
for _, cargo in pairs(self._cargoInUnits) do
if cargo[crateType] ~= nil then
currentWeight = currentWeight + (cargo[crateType] * crateConfigA.weight)
end
end
local unitConfig = Spearhead.classes.stageClasses.helpers.supplies.MaxLoadConfig[unit:getTypeName()]
if unitConfig == nil then
trigger.action.outText("Your unit type is not configured for logistics: " .. crateType, 5)
self._logger:error("Invalid unit type: " .. unit:getTypeName())
return false
end
local maxWeight = unitConfig.maxInternalLoad
if currentWeight + crateConfigA.weight > maxWeight then
trigger.action.outText("Failed to load crate due to it overloading your max weight of: " .. maxWeight .. "kg", 5)
return false
end
trigger.action.setUnitInternalCargo(unit:getName(), crateConfigA.weight)
self:AddCargoToUnit(unit:getID(), crateType)
local group = unit:getGroup()
if group == nil then return false end
local groupID = group:getID()
self._commandsHelper:updateCommandsForGroup(groupID)
return true
end
---Spawns a crate for sling loading
---@param groupID number
---@param crateType CrateType
function SupplyUnitsTracker:UnitRequestCrateSpawn(groupID, crateType)
local group = Spearhead.DcsUtil.GetPlayerGroupByGroupID(groupID)
if group == nil then
local crateConfig = Spearhead.classes.stageClasses.helpers.supplies.SupplyConfigHelper.getSupplyConfig(crateType)
if crateConfig == nil then
self._logger:error("Invalid crate type: " .. crateType)
return
end
end
end
---@private
---@param unit Unit
---@return Vec3
function SupplyUnitsTracker:GetCargoPlacePosition(unit)
local pos = unit:getPosition()
local preferedPos = {
x = pos.p.x - 10 * pos.x.x,
y = pos.p.y - 10 * pos.x.y,
z = pos.p.z - 10 * pos.x.z
}
return preferedPos
-- local volume = {
-- id = world.VolumeType.SPHERE,
-- params = {
-- point = preferedPos,
-- radius = 10
-- }
-- }
-- local occupiedPosX = {}
-- local occupiedPosZ = {}
-- ---@param foundItem Object
-- local found = function(foundItem, val)
-- local foundPos = foundItem:getPoint()
-- local z = math.floor(foundPos.z)
-- for i = z - 3 , z + 3 do
-- occupiedPosZ[i] = true
-- end
-- local x = math.floor(foundPos.x)
-- for i = x - 3 , x + 3 do
-- occupiedPosX[i] = true
-- end
-- end
-- world.searchObjects(volume.id, volume.params, found)
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