Sweep cap (#54)

* Added initial implementation of Sweep groups

* Added initial implementation of Sweep groups

* Added initial implementation of Sweep groups

* Added initial implementation of Sweep groups

* fixed issues when testing

* Intercept cap (#55)

* First intial WIP for intercept units

* First intial WIP for intercept units

* major updates

---------

Co-authored-by: ex61wi <tim.rorije@ing.com>
Co-authored-by: dutchie032 <dutchie032>

---------

Co-authored-by: ex61wi <tim.rorije@ing.com>
Co-authored-by: dutchie032 <dutchie032>
This commit is contained in:
2025-06-12 22:40:55 +02:00
committed by GitHub
co-authored by ex61wi dutchie032 <dutchie032>
parent bdf7154333
commit ef65f5a353
22 changed files with 1834 additions and 353 deletions
+399
View File
@@ -0,0 +1,399 @@
---@class InterceptTasking
local INTERCEPT = {}
---@param groupName string
---@param interceptPoint Vec2
---@param airbase Airbase
---@param speed number?
---@param alt number?
---@param config CapConfig
function INTERCEPT.getMissionFromAirbase(groupName, interceptPoint, airbase, config, speed, alt)
local airbaseVec3 = airbase:getPoint()
local airbaseVec2 = { x = airbaseVec3.x, y = airbaseVec3.z }
local heading = Spearhead.Util.vectorHeadingFromTo(airbaseVec2, interceptPoint)
env.info("BLAAT: heading from runway to first point: " .. heading)
local point = Spearhead.Util.vectorMove(airbaseVec2, heading, 3*1852)
local pointA, pointB, pointC, pointD = INTERCEPT.getInterceptTaskPoint(groupName, point, interceptPoint, airbaseVec2, config, speed, alt)
local points = {
[1] = pointA,
[2] = pointA,
[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)
}
local mission = {
id = 'Mission',
params = {
airborne = true,
route = {
points = points
}
}
}
return mission
end
---comment
---@param groupName string
---@param currentPosition Vec2
---@param interceptPoint Vec2
---@param airbase Airbase
---@param speed number?
---@param alt number?
---@param config CapConfig
---@return table
function INTERCEPT.getMissionFromInAir(groupName, currentPosition, interceptPoint, airbase, config, speed, alt)
local pointAirbasev3 = airbase:getPoint()
local airbase2 = { x = pointAirbasev3.x, y = pointAirbasev3.z }
local pointA, pointB, pointC, pointD = INTERCEPT.getInterceptTaskPoint(groupName, currentPosition, interceptPoint, airbase2, config, speed, alt)
local points = {
[1] = pointA,
[2] = pointA,
[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)
}
local mission = {
id = 'Mission',
params = {
airborne = true,
route = {
points = points
}
}
}
return mission
end
---comment
---@param groupName string
---@param currentPoint Vec2
---@param targetPosition Vec2
---@param targetUnit Unit
---@param airbase any
---@param config any
---@param speed number?
---@param alt number?
---@return table
function INTERCEPT.getUnitInterceptMissionFromAir(groupName, currentPoint, targetPosition, targetUnit, airbase, config, speed, alt)
local pointAirbasev3 = airbase:getPoint()
local airbase2 = { x = pointAirbasev3.x, y = pointAirbasev3.z }
local pointA, pointB, pointC, pointD = INTERCEPT.getUnitInterceptTaskPoint(groupName, currentPoint, targetPosition, targetUnit, airbase2, config, speed, alt)
local points = {
[1] = pointA,
[2] = pointA,
[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)
}
local mission = {
id = 'Mission',
params = {
airborne = true,
route = {
points = points
}
}
}
return mission
end
---@private
---@param groupName string
---@param currentPoint Vec2
---@param targetPoint Vec2
---@param airbasePoint Vec2
---@param config CapConfig
---@param speed number?
---@param alt number?
---@return table pointA @Starts the task right away
---@return table pointB @The actual target point to fly to and search, but searching started at pointA
---@return table pointC A fly over point halfway between the target and the airbase, if nothing it found then the unit will fly it's route till here
---@return table pointD THe point after Point C where the unit will execute the RTB command
function INTERCEPT.getInterceptTaskPoint(groupName, currentPoint, targetPoint, airbasePoint, config, speed, alt)
local pointA = {
alt = alt or config:getMinAlt(),
action = "Turning Point",
alt_type = "BARO",
speed = speed or config:getMaxSpeed(),
ETA = 0,
ETA_locked = false,
x = currentPoint.x,
y = currentPoint.y,
speed_locked = true,
formation_template = "",
task = {
id = "ComboTask",
params = {
tasks = {
id = 'EngageTargetsInZone',
params = {
point = targetPoint,
zoneRadius = 10 * 1852, -- 10 NM, point will be updated, so target should be in this zone.
targetTypes = {
[1] = "Planes",
},
priority = 0
}
}
}
}
}
local pointB = {
alt = alt or config:getMinAlt(),
action = "Turning Point",
alt_type = "BARO",
speed = speed or config:getMaxSpeed(),
ETA = 0,
ETA_locked = false,
x = targetPoint.x,
y = targetPoint.y,
speed_locked = true,
formation_template = "",
task = {
id = "ComboTask",
params = {
tasks = {
id = 'EngageTargetsInZone',
params = {
point = targetPoint,
zoneRadius = 10 * 1852, -- 10 NM, point will be updated, so target should be in this zone.
targetTypes = {
[1] = "Planes",
},
priority = 0
}
}
}
}
}
local midPoint = {
x = (targetPoint.x + airbasePoint.x) / 2,
y = (targetPoint.y + airbasePoint.y) / 2
}
local pointC = {
alt = config:getMinAlt(),
action = "Fly Over Point",
alt_type = "BARO",
speed = config:getMaxSpeed(),
ETA = 0,
ETA_locked = false,
x = midPoint.x,
y = midPoint.y,
speed_locked = true,
formation_template = "",
task = {
id = "ComboTask",
params = {}
}
}
local pointD = {
alt = config:getMinAlt(),
action = "Turning Point",
alt_type = "BARO",
speed = config:getMaxSpeed(),
ETA = 0,
ETA_locked = false,
x = midPoint.x,
y = midPoint.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.PublishRTB, \"" .. groupName .. "\")"
}
}
}
}
}
}
}
}
return pointA, pointB, pointC, pointD
end
---@private
---@param groupName string
---@param currentPoint Vec2
---@param targetPosition Vec2
---@param targetUnit Unit
---@param airbasePoint Vec2
---@param config CapConfig
---@param speed number?
---@param alt number?
---@return table pointA @Starts the task right away
---@return table pointB @The actual target point to fly to and search, but searching started at pointA
---@return table pointC A fly over point halfway between the target and the airbase, if nothing it found then the unit will fly it's route till here
---@return table pointD THe point after Point C where the unit will execute the RTB command
function INTERCEPT.getUnitInterceptTaskPoint(groupName, currentPoint, targetPosition, targetUnit, airbasePoint, config, speed, alt)
local pointA = {
alt = alt or config:getMinAlt(),
action = "Turning Point",
alt_type = "BARO",
speed = speed or config:getMaxSpeed(),
ETA = 0,
ETA_locked = false,
x = currentPoint.x,
y = currentPoint.y,
speed_locked = true,
formation_template = "",
task = {
id = "ComboTask",
params = {
tasks = {
[1] = {
id = 'EngageUnit',
params = {
unitId = targetUnit:getID(),
groupAttack = true,
priority = 0
}
}
}
}
}
}
local pointB = {
alt = alt or config:getMinAlt(),
action = "Turning Point",
alt_type = "BARO",
speed = speed or config:getMaxSpeed(),
ETA = 0,
ETA_locked = false,
x = targetPosition.x,
y = targetPosition.y,
speed_locked = true,
formation_template = "",
task = {
id = "ComboTask",
params = {
tasks = {
[1] = {
id = 'EngageUnit',
params = {
unitId = targetUnit:getID(),
groupAttack = true,
priority = 0
}
}
}
}
}
}
local midPoint = {
x = (targetPosition.x + airbasePoint.x) / 2,
y = (targetPosition.y + airbasePoint.y) / 2
}
local pointC = {
alt = config:getMinAlt(),
action = "Fly Over Point",
alt_type = "BARO",
speed = config:getMaxSpeed(),
ETA = 0,
ETA_locked = false,
x = midPoint.x,
y = midPoint.y,
speed_locked = true,
formation_template = "",
task = {
id = "ComboTask",
params = {}
}
}
local pointD = {
alt = config:getMinAlt(),
action = "Turning Point",
alt_type = "BARO",
speed = config:getMaxSpeed(),
ETA = 0,
ETA_locked = false,
x = midPoint.x,
y = midPoint.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.PublishRTB, \"" .. groupName .. "\")"
}
}
}
}
}
}
}
}
return pointA, pointB, pointC, pointD
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
+287
View File
@@ -0,0 +1,287 @@
---@class SWEEPTasking
local SWEEP = {}
---@param attackHelos boolean
---@return table
local function GetCAPTargetTypes(attackHelos)
local targetTypes = {
[1] = "Planes",
}
if attackHelos then
targetTypes[2] = "Helicopters"
end
return targetTypes
end
---@class SWEEPTaskingOptions
---@field furthest Vec2
---@field closest Vec2
---@param capZone SpearheadTriggerZone
---@param airBase Airbase
---@return SWEEPTaskingOptions
local function GetCAPPointFromTriggerZone(airBase, capZone)
local furthestA = nil
local furthestB = nil
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(),
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 SWEEP.getAsMissionFromAirbase(groupName, airbase, capZone, capConfig)
local pointA, pointB, pointC = SWEEP.getAsTasking(groupName, airbase, capZone, capConfig)
local points = {
[1] = GetOutboundTask(airbase, capZone, capConfig),
[2] = GetOutboundTask(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)
}
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
---@return table TurningPointA
---@return table TurningPointB
---@return table TurningPointC
function SWEEP.getAsTasking(groupName, airbase, capZone, capConfig)
local capTaskingOptions = GetCAPPointFromTriggerZone(airbase, capZone)
local alt = math.random(capConfig:getMinAlt(), capConfig:getMaxAlt())
local speed = capConfig:getMaxSpeed()
local pointA = {
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
}
}
}
}
}
}
local pointB = {
alt = alt,
action = "Turning Point",
alt_type = "BARO",
speed = speed,
ETA = 0,
ETA_locked = false,
x = capTaskingOptions.furthest.x,
y = capTaskingOptions.furthest.y,
speed_locked = true,
formation_template = "",
task = {
id = "ComboTask",
params = {
tasks = {
[1] = {
id = 'EngageTargets',
params = {
maxDist = capConfig:getMaxDeviationRange(),
maxDistEnabled = capConfig:getMaxDeviationRange() >= 0, -- required to check maxDist
targetTypes = GetCAPTargetTypes(false),
priority = 0
}
}
}
}
}
}
local pointC = {
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] = {
id = 'EngageTargets',
params = {
maxDist = capConfig:getMaxDeviationRange(),
maxDistEnabled = capConfig:getMaxDeviationRange() >= 0, -- required to check maxDist
targetTypes = GetCAPTargetTypes(false),
priority = 0
}
},
[2] = {
number = 2,
auto = false,
id = "WrappedAction",
enabled = "true",
params = {
action = {
id = "Script",
params = {
command = "pcall(Spearhead.Events.PublishRTB, \"" .. groupName .. "\")"
}
}
}
}
}
}
}
}
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