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:
@@ -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
|
||||
Reference in New Issue
Block a user