Cap rework (#48)
- Refactored all CAP classes. - Improved timing - Zones are now not tied to MissionStages - CAPROUTE_<routeID>_<free> - routeID is now what is used in the naming convention. - Units taxi back to their spawn parking space and rearm there. (Units destroyed while in the Rearming or Repairing state are not taken into account)
This commit is contained in:
@@ -0,0 +1,327 @@
|
||||
---@class CAPTasking
|
||||
local CAP = {}
|
||||
|
||||
---@param attackHelos boolean
|
||||
---@return table
|
||||
local function GetCAPTargetTypes(attackHelos)
|
||||
local targetTypes = {
|
||||
[1] = "Planes",
|
||||
}
|
||||
|
||||
if attackHelos then
|
||||
targetTypes[2] = "Helicopters"
|
||||
end
|
||||
|
||||
return targetTypes
|
||||
end
|
||||
|
||||
---@class CapTaskingOptions
|
||||
---@field furthest Vec2
|
||||
---@field closest Vec2
|
||||
---@field legLength number
|
||||
---@field width number
|
||||
---@field hotLegDir number
|
||||
|
||||
|
||||
---@param capZone SpearheadTriggerZone
|
||||
---@param airBase Airbase
|
||||
---@return CapTaskingOptions
|
||||
local function GetCAPPointFromTriggerZone(airBase, capZone)
|
||||
local furthestA = nil
|
||||
local furthestB = nil
|
||||
|
||||
local furthestFromBase = nil
|
||||
local furthestFromBaseDistance = 0
|
||||
|
||||
local furthestDistance = 0
|
||||
|
||||
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)
|
||||
if distance > furthestDistance then
|
||||
furthestDistance = distance
|
||||
furthestA = indexA
|
||||
furthestB = indexB
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local baseVec3 = airBase:getPoint()
|
||||
|
||||
---@type Vec2
|
||||
local baseVec2 = { x = baseVec3.x, y = baseVec3.z }
|
||||
|
||||
local pointA = capZone.verts[furthestA]
|
||||
local pointB = capZone.verts[furthestB]
|
||||
local furthest = pointA
|
||||
local closest = pointB
|
||||
|
||||
local heading = Spearhead.Util.vectorHeadingFromTo(pointA, pointB)
|
||||
|
||||
if Spearhead.Util.VectorDistance2d(baseVec2, pointB) > Spearhead.Util.VectorDistance2d(baseVec2, pointA) then
|
||||
furthest = pointB
|
||||
closest = pointA
|
||||
heading = Spearhead.Util.vectorHeadingFromTo(pointB, pointA)
|
||||
end
|
||||
|
||||
local distance = furthestDistance
|
||||
if distance > 15000 then
|
||||
distance = distance - 10000
|
||||
end
|
||||
|
||||
return {
|
||||
width = 10000,
|
||||
furthest = furthest,
|
||||
closest = closest,
|
||||
legLength = distance,
|
||||
hotLegDir = math.rad(heading),
|
||||
orbitOriginPoint = closest
|
||||
}
|
||||
end
|
||||
|
||||
---@param airbase Airbase
|
||||
---@param capZone SpearheadTriggerZone
|
||||
---@param capConfig CapConfig
|
||||
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)
|
||||
|
||||
return {
|
||||
alt = 2000,
|
||||
action = "Fly Over Point",
|
||||
type = "Turning Point",
|
||||
alt_type = "BARO",
|
||||
speed = capConfig:getMinSpeed(),
|
||||
ETA = 0,
|
||||
ETA_locked = false,
|
||||
x = point.x,
|
||||
y = point.y,
|
||||
speed_locked = false,
|
||||
formation_template = "",
|
||||
task = {
|
||||
id = "ComboTask",
|
||||
params = {
|
||||
tasks = {
|
||||
[1] = {
|
||||
id = 'EngageTargets',
|
||||
params = {
|
||||
maxDist = capConfig:getMaxDeviationRange() + 10 * 1852,
|
||||
maxDistEnabled = capConfig:getMaxDeviationRange() > 0, -- required to check maxDist
|
||||
targetTypes = GetCAPTargetTypes(false),
|
||||
priority = 0
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
---@param groupName string
|
||||
---@param airbase Airbase
|
||||
---@param capZone SpearheadTriggerZone
|
||||
---@param capConfig CapConfig
|
||||
function CAP.getAsMissionFromAirbase(groupName, airbase, capZone, capConfig)
|
||||
local points = {
|
||||
[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)
|
||||
}
|
||||
|
||||
local mission = {
|
||||
id = 'Mission',
|
||||
params = {
|
||||
airborne = true,
|
||||
route = {
|
||||
points = points
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
---@param groupName string
|
||||
---@param airbase Airbase
|
||||
---@param capZone SpearheadTriggerZone
|
||||
---@param capConfig CapConfig
|
||||
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)
|
||||
}
|
||||
|
||||
local mission = {
|
||||
id = 'Mission',
|
||||
params = {
|
||||
airborne = true,
|
||||
route = {
|
||||
points = points
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mission
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param groupName string
|
||||
---@param airbase Airbase
|
||||
---@param capZone SpearheadTriggerZone
|
||||
---@param capConfig CapConfig
|
||||
function CAP.getAsTasking(groupName, airbase, capZone, capConfig)
|
||||
local duration = math.random(capConfig:getMinDurationOnStation(), capConfig:getMaxDurationOnStation()) or 1500
|
||||
|
||||
local capTaskingOptions = GetCAPPointFromTriggerZone(airbase, capZone)
|
||||
|
||||
local durationBefore10 = duration - 600
|
||||
if durationBefore10 < 0 then durationBefore10 = 0 end
|
||||
local durationAfter10 = 600
|
||||
if duration < 600 then
|
||||
durationAfter10 = duration
|
||||
end
|
||||
|
||||
local alt = math.random(capConfig:getMinAlt(), capConfig:getMaxAlt())
|
||||
local speed = math.random(capConfig:getMinSpeed(), capConfig:getMaxSpeed())
|
||||
|
||||
return {
|
||||
alt = alt,
|
||||
action = "Turning Point",
|
||||
alt_type = "BARO",
|
||||
speed = speed,
|
||||
ETA = 0,
|
||||
ETA_locked = false,
|
||||
x = capTaskingOptions.closest.x,
|
||||
y = capTaskingOptions.closest.y,
|
||||
speed_locked = true,
|
||||
formation_template = "",
|
||||
task = {
|
||||
id = "ComboTask",
|
||||
params = {
|
||||
tasks = {
|
||||
[1] = {
|
||||
number = 1,
|
||||
auto = false,
|
||||
id = "WrappedAction",
|
||||
enabled = "true",
|
||||
params = {
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishOnStation, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
[2] = {
|
||||
id = 'EngageTargets',
|
||||
params = {
|
||||
maxDist = capConfig:getMaxDeviationRange(),
|
||||
maxDistEnabled = capConfig:getMaxDeviationRange() >= 0, -- required to check maxDist
|
||||
targetTypes = GetCAPTargetTypes(false),
|
||||
priority = 0
|
||||
}
|
||||
},
|
||||
[3] = {
|
||||
number = 3,
|
||||
auto = false,
|
||||
id = "ControlledTask",
|
||||
enabled = true,
|
||||
params = {
|
||||
task = {
|
||||
id = "Orbit",
|
||||
params = {
|
||||
altitude = alt,
|
||||
pattern = "Anchored",
|
||||
speed = speed,
|
||||
point = {
|
||||
x = capTaskingOptions.closest.x,
|
||||
y = capTaskingOptions.closest.y
|
||||
},
|
||||
speedEdited = true,
|
||||
clockWise = false,
|
||||
hotLegDir = capTaskingOptions.hotLegDir,
|
||||
legLength = capTaskingOptions.legLength,
|
||||
width = capTaskingOptions.width,
|
||||
}
|
||||
},
|
||||
stopCondition = {
|
||||
duration = durationBefore10,
|
||||
condition = "return Spearhead.DcsUtil.NeedsRTBInTen(\"" .. groupName .. "\", 0.10)",
|
||||
}
|
||||
}
|
||||
},
|
||||
[4] = {
|
||||
number = 4,
|
||||
auto = false,
|
||||
id = "WrappedAction",
|
||||
enabled = "true",
|
||||
params = {
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTBInTen, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[5] = {
|
||||
number = 5,
|
||||
auto = false,
|
||||
id = "ControlledTask",
|
||||
enabled = true,
|
||||
params = {
|
||||
task = {
|
||||
id = "Orbit",
|
||||
params = {
|
||||
altitude = alt,
|
||||
pattern = "Circle",
|
||||
speed = speed,
|
||||
-- speedEdited = true,
|
||||
-- clockWise = false,
|
||||
-- hotLegDir = capTaskingOptions.hotLegDir,
|
||||
-- legLength = capTaskingOptions.legLength,
|
||||
-- width = capTaskingOptions.width,
|
||||
}
|
||||
},
|
||||
stopCondition = {
|
||||
duration = durationAfter10,
|
||||
condition = "return Spearhead.DcsUtil.IsBingoFuel(\"" .. groupName .. "\")",
|
||||
}
|
||||
}
|
||||
},
|
||||
[6] = {
|
||||
number = 6,
|
||||
auto = false,
|
||||
id = "WrappedAction",
|
||||
enabled = "true",
|
||||
params = {
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTB, \"" .. 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.taskings then Spearhead.classes.capClasses.taskings = {} end
|
||||
Spearhead.classes.capClasses.taskings.CAP = CAP
|
||||
@@ -0,0 +1,201 @@
|
||||
|
||||
---@class RTBTasking
|
||||
local RTB = {}
|
||||
|
||||
|
||||
---@param airbase Airbase
|
||||
---@param missionPoint Vec2
|
||||
---@param capConfig CapConfig
|
||||
function RTB.getAsMission(airbase, missionPoint, capConfig)
|
||||
return {
|
||||
id = "Mission",
|
||||
params = {
|
||||
airborne = true,
|
||||
route = {
|
||||
points = {
|
||||
[1] = RTB.getApproachPoint(airbase, missionPoint, capConfig),
|
||||
[2] = RTB.getInitialPoint(airbase),
|
||||
[3] = RTB.getLandingPoint(airbase)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
---@param airbase Airbase
|
||||
---@return number
|
||||
local getRunwayIntoWindCourseRad = function(airbase)
|
||||
|
||||
local activeCourse = nil
|
||||
local minAlignment = nil
|
||||
|
||||
local runways = airbase:getRunways()
|
||||
|
||||
local windVec = atmosphere.getWind(airbase:getPoint())
|
||||
local mPerS = Spearhead.Util.vectorMagnitude(windVec)
|
||||
|
||||
if mPerS > 0 then
|
||||
for i = 1, #runways do
|
||||
local runway = runways[i]
|
||||
|
||||
do --normal
|
||||
local rad = runway.course
|
||||
if rad < 0 then
|
||||
rad = math.abs(rad)
|
||||
else
|
||||
rad = 0 - rad
|
||||
end
|
||||
|
||||
local runwayVec = {x = math.cos(rad), z = math.sin(rad), y = 0}
|
||||
local alignment = Spearhead.Util.vectorAlignment(windVec, runwayVec)
|
||||
|
||||
if minAlignment == nil or alignment < minAlignment then
|
||||
activeCourse = i
|
||||
minAlignment = alignment
|
||||
end
|
||||
end
|
||||
|
||||
do --inverse
|
||||
local degree = math.deg(runway.course)
|
||||
degree = (degree + 180) % 360
|
||||
|
||||
local rad = math.rad(degree)
|
||||
if rad < 0 then
|
||||
rad = math.abs(rad)
|
||||
else
|
||||
rad = 0 - rad
|
||||
end
|
||||
|
||||
local runwayVec = {x = math.cos(rad), z = math.sin(rad), y = 0}
|
||||
local alignment = Spearhead.Util.vectorAlignment(windVec, runwayVec)
|
||||
|
||||
if minAlignment == nil or alignment < minAlignment then
|
||||
activeCourse = i
|
||||
minAlignment = alignment
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local rad = runways[1].course
|
||||
|
||||
if activeCourse ~= nil then
|
||||
rad = runways[activeCourse].course
|
||||
end
|
||||
|
||||
if rad < 0 then
|
||||
return math.abs(rad)
|
||||
else
|
||||
return 0 - rad
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param airbase Airbase
|
||||
---@return Vec2
|
||||
---@return number headingFromRunwayDegrees
|
||||
local function calcInitialPoint(airbase)
|
||||
local runwayCourseRad = getRunwayIntoWindCourseRad(airbase)
|
||||
local heading = math.deg(runwayCourseRad)
|
||||
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)
|
||||
|
||||
return point, flipped
|
||||
|
||||
end
|
||||
|
||||
|
||||
---comment
|
||||
---@param airbase Airbase
|
||||
---@param missionPoint Vec2
|
||||
---@param capConfig CapConfig
|
||||
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)
|
||||
|
||||
if Spearhead.Util.VectorDistance2d(missionPoint, pointA) > Spearhead.Util.VectorDistance2d(missionPoint, pointB) then
|
||||
pointA = pointB
|
||||
end
|
||||
|
||||
return {
|
||||
alt = 3000,
|
||||
action = "Turning Point",
|
||||
alt_type = "BARO",
|
||||
speed = capConfig:getMinSpeed(),
|
||||
ETA = 0,
|
||||
ETA_locked = false,
|
||||
x = pointA.x,
|
||||
y = pointA.y,
|
||||
speed_locked = true,
|
||||
formation_template = "",
|
||||
type = "Turning Point",
|
||||
task = {
|
||||
id = "ComboTask",
|
||||
params = {
|
||||
tasks = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
---@param airbase Airbase
|
||||
function RTB.getInitialPoint(airbase)
|
||||
local point = calcInitialPoint(airbase)
|
||||
return {
|
||||
alt = 600,
|
||||
action = "Turning Point",
|
||||
alt_type = "BARO",
|
||||
speed = 180,
|
||||
ETA = 0,
|
||||
ETA_locked = false,
|
||||
x = point.x,
|
||||
y = point.y,
|
||||
speed_locked = true,
|
||||
formation_template = "",
|
||||
type = "Turning Point",
|
||||
task = {
|
||||
id = "ComboTask",
|
||||
params = {
|
||||
tasks = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function RTB.getLandingPoint(airbase)
|
||||
local basePoint = airbase:getPoint()
|
||||
return {
|
||||
alt = basePoint.y,
|
||||
action = "Landing",
|
||||
alt_type = "BARO",
|
||||
speed = 70,
|
||||
ETA = 0,
|
||||
ETA_locked = false,
|
||||
x = basePoint.x,
|
||||
y = basePoint.z,
|
||||
speed_locked = true,
|
||||
formation_template = "",
|
||||
airdromeId = airbase:getID(),
|
||||
type = "Land",
|
||||
task = {
|
||||
id = "ComboTask",
|
||||
params = {
|
||||
tasks = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
Reference in New Issue
Block a user