* added FARP zones logic
  A and B farps (Active and Blue zone farps). 
  Read more about the specifics in the reference docs
This commit is contained in:
2025-05-08 20:14:01 +02:00
committed by GitHub
parent f08cee4314
commit eba7931824
7 changed files with 213 additions and 39 deletions
+11 -4
View File
@@ -215,13 +215,20 @@
CAP routes define the patrol paths for CAP units. They are tied to specific stages and zones. CAP routes define the patrol paths for CAP units. They are tied to specific stages and zones.
</p> </p>
<h3 id="cap-zones">CAP Zones</h3> <h3 id="farp-zones">FARP Zones</h3>
<p> <p>
<strong>Format:</strong> <span class="inline-lua"><span class="lua-variable">CAPZONE_[Name]</span></span> <br /> <strong>Format:</strong> <span class="inline-lua"><span class="lua-variable">FARP_A|B_[Name]</span></span> <br />
<strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">CAPZONE_BRAVO</span></span> <strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">FARP_A_HOUSTON</span></span>
<strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">FARP_B_HOUSTON</span></span>
</p> </p>
<p> <p>
CAP zones are areas where CAP units operate. They are linked to CAP routes and stages. FARP zones are spawned and activated based on the "activation parameter". <br/>
A: Activates when the parent stage zone activates. <br/>
B: Activates when the parent stage is "Blue". <br/>
<br/>
Future: FARP zones will be "buildable" once logistics are implemented.
</p> </p>
<h2 id="mission-types">Mission Types</h2> <h2 id="mission-types">Mission Types</h2>
Binary file not shown.
+10
View File
@@ -346,8 +346,16 @@ do -- INIT DCS_UTIL
if category_id ~= nil and type(categorydata) == "table" and categorydata.group ~= nil and type(categorydata.group) == "table" then 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 for group_index, group in pairs(categorydata.group) do
local name = group.name local name = group.name
local skippable = false
if category_id == DCS_UTIL.GroupCategory.STATIC then if category_id == DCS_UTIL.GroupCategory.STATIC then
local unit = group.units[1] local unit = group.units[1]
if unit.category == "Heliports" then
skippable = true
end
name = unit.name name = unit.name
local staticObj = { local staticObj = {
heading = unit.heading, heading = unit.heading,
@@ -365,6 +373,7 @@ do -- INIT DCS_UTIL
group = staticObj group = staticObj
end end
if skippable == false then
table.insert(DCS_UTIL.__groupNames, name) table.insert(DCS_UTIL.__groupNames, name)
DCS_UTIL.__miz_groups[name] = DCS_UTIL.__miz_groups[name] =
{ {
@@ -385,6 +394,7 @@ do -- INIT DCS_UTIL
end end
end end
end end
end
do --init trigger zones do --init trigger zones
for i, trigger_zone in pairs(env.mission.triggers.zones) do for i, trigger_zone in pairs(env.mission.triggers.zones) do
+49 -17
View File
@@ -8,7 +8,6 @@
---@field MissionZonesLocations table<string, Vec2> All Mission Zone Locations ---@field MissionZonesLocations table<string, Vec2> All Mission Zone Locations
---@field StageZonesByNumber table<string, Array<string>> Stage zones grouped by index number ---@field StageZonesByNumber table<string, Array<string>> Stage zones grouped by index number
---@field AllFarpZones Array<string> ---@field AllFarpZones Array<string>
---@field FarpIdsInFarpZones table<string, Array<integer>> farp pad Id's in farp zones.
---@field CapRoutes Array<string> All Cap route zone names ---@field CapRoutes Array<string> All Cap route zone names
---@field CapDataPerStageNumber table<integer, CapData> table<StageNumber, table> ---@field CapDataPerStageNumber table<integer, CapData> table<StageNumber, table>
---@field CarrierRouteZones Array<string> All Carrier routes zones ---@field CarrierRouteZones Array<string> All Carrier routes zones
@@ -53,7 +52,8 @@
---@field Groups Array<string> ---@field Groups Array<string>
---@class FarpZoneData ---@class FarpZoneData
---@field Groups Array<string> ---@field groups Array<string>
---@field padNames Array<string>
---@class Database ---@class Database
---@field private _tables DatabaseTables ---@field private _tables DatabaseTables
@@ -73,7 +73,6 @@ function Database.New(Logger)
CapDataPerStageNumber = {}, CapDataPerStageNumber = {},
CarrierRouteZones = {}, CarrierRouteZones = {},
DescriptionsByMission = {}, DescriptionsByMission = {},
FarpIdsInFarpZones = {},
MissionZones = {}, MissionZones = {},
MissionZonesLocations = {}, MissionZonesLocations = {},
StageZoneNames = {}, StageZoneNames = {},
@@ -224,6 +223,13 @@ function Database.New(Logger)
end end
end end
--- fill farp zones
for _, farpZoneName in pairs(self._tables.AllFarpZones) do
if Spearhead.DcsUtil.isZoneInZone(farpZoneName, stageZoneName) then
table.insert(stageData.FarpZones, farpZoneName)
end
end
-- fill airbases -- fill airbases
for _, airbase in pairs(world.getAirbases()) do for _, airbase in pairs(world.getAirbases()) do
local point = airbase:getPoint() local point = airbase:getPoint()
@@ -231,22 +237,10 @@ function Database.New(Logger)
if Spearhead.DcsUtil.isPositionInZone(point.x, point.z, stageZoneName) == true then if Spearhead.DcsUtil.isPositionInZone(point.x, point.z, stageZoneName) == true then
if airbase:getDesc().category == 0 then if airbase:getDesc().category == 0 then
table.insert(stageData.AirbaseNames, airbase:getName()) table.insert(stageData.AirbaseNames, airbase:getName())
elseif airbase:getDesc().category == 1 then
-- farp
--[[
TODO: FARP ZONES FILL
]]
end end
end end
end end
--- fill farp zones
for _, farpZoneName in pairs(self._tables.AllFarpZones) do
if Spearhead.DcsUtil.isZoneInZone(farpZoneName, stageZoneName) then
table.insert(stageData.FarpZones, farpZoneName)
end
end
for _, missionZone in pairs(self._tables.MissionZones) do for _, missionZone in pairs(self._tables.MissionZones) do
if self._tables.DescriptionsByMission[missionZone] == nil then if self._tables.DescriptionsByMission[missionZone] == nil then
Spearhead.AddMissionEditorWarning("Mission with zonename: " .. missionZone .. " does not have a briefing") Spearhead.AddMissionEditorWarning("Mission with zonename: " .. missionZone .. " does not have a briefing")
@@ -262,6 +256,26 @@ function Database.New(Logger)
end end
end end
for _, farpZoneName in pairs(self._tables.AllFarpZones) do
for _, airbase in pairs(world.getAirbases()) do
if airbase:getDesc().category == Airbase.Category.HELIPAD then
local name = airbase:getName()
if self._tables.FarpZoneData[farpZoneName] == nil then
self._tables.FarpZoneData[farpZoneName] = {
groups = {},
padNames = {}
}
end
local position = airbase:getPoint()
if Spearhead.DcsUtil.isPositionInZone(position.x, position.z, farpZoneName) == true then
table.insert(self._tables.FarpZoneData[farpZoneName].padNames, name)
end
end
end
end
---@private ---@private
---@param baseName string ---@param baseName string
@@ -489,14 +503,18 @@ end
function Database:loadFarpGroups() function Database:loadFarpGroups()
local all_groups = getAvailableGroups() local all_groups = getAvailableGroups()
for _, farpZone in pairs(self._tables.AllFarpZones) do for _, farpZone in pairs(self._tables.AllFarpZones) do
if self._tables.FarpZoneData[farpZone] == nil then
self._tables.FarpZoneData[farpZone] = { self._tables.FarpZoneData[farpZone] = {
Groups = {} groups = {},
padNames = {}
} }
end
local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, farpZone) local groups = Spearhead.DcsUtil.getGroupsInZone(all_groups, farpZone)
for _, groupName in pairs(groups) do for _, groupName in pairs(groups) do
is_group_taken[groupName] = true is_group_taken[groupName] = true
table.insert(self._tables.FarpZoneData[farpZone].Groups, groupName) table.insert(self._tables.FarpZoneData[farpZone].groups, groupName)
end end
end end
end end
@@ -704,6 +722,20 @@ function Database:getAirbaseNamesInStage(stageName)
return stageData.AirbaseNames or {} return stageData.AirbaseNames or {}
end end
function Database:getFarpNamesInStage(stageName)
local stageData = self._tables.StageZones[stageName]
if not stageData then return {} end
return stageData.FarpZones or {}
end
---@return FarpZoneData?
function Database:getFarpDataForZone(farpZoneName)
local farpData = self._tables.FarpZoneData[farpZoneName]
if not farpData then return nil end
return farpData
end
---@param airbaseName string ---@param airbaseName string
---@return Array<string> ---@return Array<string>
@@ -0,0 +1,106 @@
---@class FarpZone
---@field private _startingFarp boolean
---@field private _groups Array<SpearheadGroup>
---@field private _padNames Array<string>
---@field private _database Database
---@field private _logger Logger
---@field private _zoneName string
local FarpZone = {}
FarpZone.__index = FarpZone
---comment
---@param database Database
---@param logger Logger
---@param zoneName string
---@return FarpZone
function FarpZone.New(database, logger, zoneName)
FarpZone.__index = FarpZone
local self = setmetatable({}, FarpZone)
self._database = database
self._logger = logger
self._zoneName = zoneName
local split = Spearhead.Util.split_string(zoneName, "_")
if string.lower(split[2]) == "a" then
self._startingFarp = true
else
self._startingFarp = false
end
logger:debug("FARP zone name: " .. zoneName .. " startingFarp" .. tostring(self._startingFarp))
local farpData = database:getFarpDataForZone(zoneName)
self._groups = {}
self._padNames = {}
if farpData then
self._padNames = farpData.padNames
for _, groupName in pairs(farpData.groups) do
local group = Spearhead.classes.stageClasses.Groups.SpearheadGroup.New(groupName)
table.insert(self._groups, group)
group:Destroy()
end
end
self:Deactivate()
return self
end
---@return boolean
function FarpZone:IsStartingFarp()
return self._startingFarp
end
function FarpZone:Activate()
self._logger:info("Activating FARP zone: " .. self._zoneName)
self:BuildUp()
self:SetPadsBlue()
end
function FarpZone:Deactivate()
self:NeutralisePads()
end
function FarpZone:BuildUp()
for _, group in pairs(self._groups) do
group:Spawn()
end
end
---@private
function FarpZone:NeutralisePads()
for _, name in pairs(self._padNames) do
local base = Airbase.getByName(name)
if base then
base:autoCapture(false) -- Disable auto capture
base:setCoalition(1) -- 1 = Red (Can't neutralise)
end
end
end
---@private
function FarpZone:SetPadsBlue()
for _, name in pairs(self._padNames) do
local base = Airbase.getByName(name)
if base then
base:autoCapture(false) -- Disable auto capture
base:setCoalition(2) -- 2 = Blue
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
if Spearhead.classes.stageClasses.SpecialZones == nil then Spearhead.classes.stageClasses.SpecialZones = {} end
Spearhead.classes.stageClasses.SpecialZones.FarpZone = FarpZone
@@ -12,6 +12,7 @@
--- @field airbases Array<StageBase> --- @field airbases Array<StageBase>
--- @field miscGroups Array<SpearheadGroup> --- @field miscGroups Array<SpearheadGroup>
--- @field maxMissions integer --- @field maxMissions integer
--- @field farps Array<FarpZone>
--- @class StageInitData --- @class StageInitData
--- @field stageZoneName string --- @field stageZoneName string
@@ -45,7 +46,6 @@ local Stage = {}
Stage.__index = Stage Stage.__index = Stage
local stageDrawingId = 100
Stage.StageColors = { Stage.StageColors = {
INVISIBLE = { r=0, g=0, b=0, a=0 }, INVISIBLE = { r=0, g=0, b=0, a=0 },
@@ -86,7 +86,8 @@ function Stage:superNew(database, stageConfig, logger, initData, missionPriority
blueSams = {}, blueSams = {},
airbases ={}, airbases ={},
miscGroups = {}, miscGroups = {},
maxMissions = stageConfig.maxMissionsPerStage maxMissions = stageConfig.maxMissionsPerStage,
farps = {},
} }
self._activeStage = -99 self._activeStage = -99
self._preActivated = false self._preActivated = false
@@ -101,7 +102,12 @@ function Stage:superNew(database, stageConfig, logger, initData, missionPriority
self._missionPriority = missionPriority self._missionPriority = missionPriority
self._stageCompleteListeners = {} self._stageCompleteListeners = {}
stageDrawingId = stageDrawingId + 1 local farpNames = database:getFarpNamesInStage(self.zoneName)
for _, farpName in pairs(farpNames) do
local farp = Spearhead.classes.stageClasses.SpecialZones.FarpZone.New(database, logger, farpName)
table.insert(self._db.farps, farp)
end
self._logger:info("Initiating new Stage with name: " .. self.zoneName) self._logger:info("Initiating new Stage with name: " .. self.zoneName)
@@ -364,6 +370,12 @@ function Stage:ActivateStage()
end end
end end
for _, farp in pairs(self._db.farps) do
if farp:IsStartingFarp() == true then
farp:Activate()
end
end
timer.scheduleFunction(self.CheckContinuousAsync, self, timer.getTime() + 3) timer.scheduleFunction(self.CheckContinuousAsync, self, timer.getTime() + 3)
end end
@@ -430,6 +442,12 @@ function Stage:ActivateBlueGroups()
self:OnPostBlueActivated() self:OnPostBlueActivated()
end) end)
end end
for _, farp in pairs(self._db.farps) do
if farp:IsStartingFarp() == true then
farp:Activate()
end
end
end end
function Stage:ActivateBlueStage() function Stage:ActivateBlueStage()
+1
View File
@@ -37,6 +37,7 @@ assert(loadfile(classPath .. "stageClasses\\helpers\\MissionCommandsHelper.lua")
assert(loadfile(classPath .. "stageClasses\\SpecialZones\\StageBase.lua"))() assert(loadfile(classPath .. "stageClasses\\SpecialZones\\StageBase.lua"))()
assert(loadfile(classPath .. "stageClasses\\SpecialZones\\BlueSam.lua"))() assert(loadfile(classPath .. "stageClasses\\SpecialZones\\BlueSam.lua"))()
assert(loadfile(classPath .. "stageClasses\\SpecialZones\\FarpZone.lua"))()
assert(loadfile(classPath .. "capClasses\\CapGroup.lua"))() assert(loadfile(classPath .. "capClasses\\CapGroup.lua"))()
assert(loadfile(classPath .. "capClasses\\GlobalCapManager.lua"))() assert(loadfile(classPath .. "capClasses\\GlobalCapManager.lua"))()