custom drawings and animations for video

This commit is contained in:
2025-12-28 14:35:31 +01:00
parent c027921527
commit ca82c3357d
16 changed files with 5500 additions and 72 deletions
+28 -2
View File
@@ -20,7 +20,7 @@
---@field MissionZoneData table<string, MissionZoneData>
---@field FarpZoneData table<string,FarpZoneData>
---@field missionCodes table<string, boolean>
---@field CustomDrawings Array<CustomDrawing>
---@class CapRoute
---@field zones Array<SpearheadTriggerZone>
@@ -99,7 +99,8 @@ function Database.New(Logger)
MissionZoneData = {},
FarpZoneData = {},
missionCodes = {},
SupplyHubZones = {}
SupplyHubZones = {},
CustomDrawings = {}
}
Database.__index = Database
@@ -215,6 +216,23 @@ function Database.New(Logger)
end
end
---@type table<integer, boolean>
do -- custom drawings
if env.mission.drawings and env.mission.drawings.layers then
for i, layer in pairs(env.mission.drawings.layers) do
if string.lower(layer.name) == "author" then
for key, layer_object in pairs(layer.objects) do
if Spearhead.Util.startswith(layer_object.name, "drawing_", true) then
local object = layer_object --[[@as DrawingObject]]
local customDrawing = Spearhead.classes.stageClasses.drawings.CustomDrawing.New(object)
table.insert(self._tables.CustomDrawings, customDrawing)
end
end
end
end
end
end
---@type table<string, boolean>
local availableSupplyHubs = {}
for _, supplyHubZoneName in pairs(self._tables.SupplyHubZones) do
@@ -593,6 +611,14 @@ function Database:loadBlueSamUnits()
end
end
---@return Array<CustomDrawing>
function Database:getCustomDrawings()
if self._tables.CustomDrawings == nil then
return {}
end
return self._tables.CustomDrawings
end
---Loads all units, data and briefings
---@private
function Database:LoadZoneData(missionZoneName)
+71 -57
View File
@@ -13,8 +13,12 @@ local WaitingStagesByIndex = {}
local currentStage = -99
GlobalStageManager = {}
---@class GlobalStageManager : StageCompleteListener
---@field private database Database
---@field private logger Logger
---@field private stageConfig StageConfig
local GlobalStageManager = {}
GlobalStageManager.__index = GlobalStageManager
---comment
---@param database Database
@@ -22,13 +26,14 @@ GlobalStageManager = {}
---@param logLevel LogLevel
---@param spawnManager SpawnManager
---@return nil
function GlobalStageManager:NewAndStart(database, stageConfig, logLevel, spawnManager)
function GlobalStageManager.NewAndStart(database, stageConfig, logLevel, spawnManager)
local logger = Spearhead.LoggerTemplate.new("StageManager", logLevel)
logger:info("Using Stage Log Level: " .. logLevel)
local o = {}
setmetatable(o, { __index = self })
local self = setmetatable({}, GlobalStageManager)
self.database = database
self.stageConfig = stageConfig
o.logger = logger
self.logger = logger
if stageConfig.isAutoStages ~= true then
logger:warn("Spearhead will not automatically progress stages due to the given settings. If you manually have implemented this, please ignore this message")
end
@@ -42,53 +47,6 @@ function GlobalStageManager:NewAndStart(database, stageConfig, logLevel, spawnMa
Spearhead.Events.AddStageNumberChangedListener(OnStageNumberChangedListener)
---@type StageCompleteListener
local OnStageCompleteListener = {
OnStageComplete = function(self, stage)
logger:debug("Receiving stage complete event from: " .. stage.zoneName)
local anyIncomplete = false
logger:debug("Checking stages for index: " .. tostring(currentStage))
for index, stage in pairs(StagesByIndex[tostring(currentStage)]) do
if stage:IsComplete() == false then
anyIncomplete = true
logger:debug("Need to wait for Stage " .. stage.zoneName .. " to be completed")
else
logger:debug("Stage verified to be completed: " .. stage.zoneName)
end
end
if anyIncomplete == false and stageConfig.isAutoStages == true then
-- CHECK WAITING STAGES
local nextStage = currentStage + 1
if WaitingStagesByIndex[tostring(nextStage)] then
for _, waitingStage in pairs(WaitingStagesByIndex[tostring(nextStage)]) do
if waitingStage:IsActive() == false then
waitingStage:ActivateStage()
end
end
end
local anyWaiting = false
if WaitingStagesByIndex[tostring(nextStage)] then
for _, waitingStage in pairs(WaitingStagesByIndex[tostring(nextStage)]) do
if waitingStage:IsComplete() == false then
anyWaiting = true
end
end
end
if anyWaiting == false then
logger:debug("Setting next stage to: " .. tostring(currentStage + 1))
Spearhead.Events.PublishStageNumberChanged(currentStage + 1)
end
end
end
}
for _, stageName in pairs(database:getStagezoneNames()) do
logger:debug("Found stage zone with name: " .. stageName)
@@ -136,13 +94,13 @@ function GlobalStageManager:NewAndStart(database, stageConfig, logLevel, spawnMa
if isSideStage == true then
local stage = Spearhead.classes.stageClasses.Stages.ExtraStage.New(database, stageConfig, stagelogger, initData, spawnManager)
stage:AddStageCompleteListener(OnStageCompleteListener)
stage:AddStageCompleteListener(self)
if SideStageByIndex[tostring(orderNumber)] == nil then SideStageByIndex[tostring(orderNumber)] = {} end
table.insert(SideStageByIndex[tostring(orderNumber)], stage)
else
local stage = Spearhead.classes.stageClasses.Stages.PrimaryStage.New(database, stageConfig, stagelogger, initData, spawnManager)
stage:AddStageCompleteListener(OnStageCompleteListener)
stage:AddStageCompleteListener(self)
if StagesByIndex[tostring(orderNumber)] == nil then StagesByIndex[tostring(orderNumber)] = {} end
table.insert(StagesByIndex[tostring(orderNumber)], stage)
@@ -193,15 +151,71 @@ function GlobalStageManager:NewAndStart(database, stageConfig, logLevel, spawnMa
end
table.insert(WaitingStagesByIndex[tostring(stageIndex)], waitingStage)
waitingStage:AddStageCompleteListener(OnStageCompleteListener)
waitingStage:AddStageCompleteListener(self)
end
end
end
end
return self
end
function GlobalStageManager:OnStageComplete(stage)
self.logger:debug("Receiving stage complete event from: " .. stage.zoneName)
return o
local anyIncomplete = false
self.logger:debug("Checking stages for index: " .. tostring(currentStage))
for index, stage in pairs(StagesByIndex[tostring(currentStage)]) do
if stage:IsComplete() == false then
anyIncomplete = true
self.logger:debug("Need to wait for Stage " .. stage.zoneName .. " to be completed")
else
self.logger:debug("Stage verified to be completed: " .. stage.zoneName)
end
end
if anyIncomplete == false and self.stageConfig.isAutoStages == true then
-- CHECK WAITING STAGES
local nextStage = currentStage + 1
if WaitingStagesByIndex[tostring(nextStage)] then
for _, waitingStage in pairs(WaitingStagesByIndex[tostring(nextStage)]) do
if waitingStage:IsActive() == false then
waitingStage:ActivateStage()
end
end
end
local anyWaiting = false
if WaitingStagesByIndex[tostring(nextStage)] then
for _, waitingStage in pairs(WaitingStagesByIndex[tostring(nextStage)]) do
if waitingStage:IsComplete() == false then
anyWaiting = true
end
end
end
if anyWaiting == false then
local newStageNumber = currentStage + 1
self:UpdateDrawings(newStageNumber)
self.logger:debug("Setting next stage to: " .. tostring(newStageNumber))
Spearhead.Events.PublishStageNumberChanged(newStageNumber)
end
end
end
---@private
function GlobalStageManager:UpdateDrawings(stageNumber)
local drawings = self.database:getCustomDrawings()
for _, drawing in pairs(drawings) do
local startStage, stopStage = drawing:GetStartAndStop()
if stageNumber >= startStage and stageNumber < stopStage then
drawing:Draw()
else
drawing:Remove()
end
end
end
@@ -0,0 +1,52 @@
---@class CustomDrawing
---@field private _id integer?
---@field private _drawingObject DrawingObject
---@field private _helper DrawingHelper
---@field private _startingStage number
---@field private _removeAtStage number
local CustomDrawing = {}
CustomDrawing.__index = CustomDrawing
---@param drawingObject DrawingObject
---@param id integer?
---@return CustomDrawing
function CustomDrawing.New(drawingObject, id)
local self = setmetatable({}, CustomDrawing)
self._drawingObject = drawingObject
self._id = id
self._helper = Spearhead.classes.stageClasses.drawings.helper.DrawingHelper
local name = drawingObject.name
local split = Spearhead.Util.split_string(name or "", "_")
local secondPart = split[2] or "1"
local splitPart = Spearhead.Util.split_string(secondPart, ":")
self._startingStage = tonumber(splitPart[1]) or 1
self._removeAtStage = tonumber(splitPart[2]) or math.huge
return self
end
---@return number start
---@return number stop
function CustomDrawing:GetStartAndStop()
return self._startingStage, self._removeAtStage
end
function CustomDrawing:Draw()
self._id = self._helper.Draw(self._drawingObject)
end
function CustomDrawing:Remove()
if self._id ~= nil then
self._helper.Remove(self._id)
self._id = nil
end
end
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.drawings then Spearhead.classes.stageClasses.drawings = {} end
Spearhead.classes.stageClasses.drawings.CustomDrawing = CustomDrawing
@@ -0,0 +1,228 @@
---@class DrawingHelper
local DrawingHelper = {}
DrawingHelper.__index = DrawingHelper
local customDrawingIdIncrementer = 4210
---@param object DrawingObject
---@return integer? id
function DrawingHelper.Draw(object)
if object == nil then
return nil
end
local id = DrawingHelper.GetAndAddId()
if(object.primitiveType == "Polygon") then
DrawingHelper.DrawPolygon(object--[[@as Polygon]], id)
elseif(object.primitiveType == "Line") then
DrawingHelper.DrawLine(object--[[@as Line]], id)
elseif(object.primitiveType == "TextBox") then
DrawingHelper.DrawTextBox(object--[[@as TextBox]], id)
end
return id
end
function DrawingHelper.GetAndAddId()
customDrawingIdIncrementer = customDrawingIdIncrementer + 1
return customDrawingIdIncrementer
end
---@private
---@param shapeID ShapeId
---@param drawID integer
---@param points Array<Vec3>
---@param fillColor table
---@param lineColor table
local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineStyle)
local functionString = "trigger.action.markupToAll(" .. shapeID .. ", -1, " .. drawID .. ","
for _, point in ipairs(points) do
functionString = functionString .. " { x=" .. point.x .. ", y=0,z=" .. point.z .. "},"
end
functionString = functionString ..
"{ " .. lineColor[1] .. "," .. lineColor[2] .. "," .. lineColor[3] .. "," .. lineColor[4] .. "}, " ..
"{ " .. fillColor[1] .. "," .. fillColor[2] .. "," .. fillColor[3] .. "," .. fillColor[4] .. "}, " ..
lineStyle .. ")"
---@diagnostic disable-next-line: deprecated
local f, err = loadstring(functionString)
if f then
f()
else
env.error("Something failed when drawing complex drawing" .. err)
end
end
---@private
---@param object Polygon
---@param id integer
function DrawingHelper.DrawPolygon(object, id)
if object == nil then
return
end
---@param circle Circle
local function DrawCircle(circle)
local vec3 = { x = circle.mapX, y = 0, z = circle.mapY }
local fillColor = DrawingHelper.ColorToColorTable(circle.fillColorString)
local colorString = DrawingHelper.ColorToColorTable(circle.colorString)
local style = DrawingHelper.ToLineStyleInteger(circle.style)
trigger.action.circleToAll(-1, id, vec3, circle.radius, colorString, fillColor, style, true)
end
---@param oval Oval
local function DrawOval(oval)
---@type Array<Vec3>
local points = {}
local pointsNo = 30
local angleStep = (2 * math.pi) / points
local fillColor = DrawingHelper.ColorToColorTable(oval.fillColorString)
local color = DrawingHelper.ColorToColorTable(oval.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(oval.style)
for i = 1, pointsNo do
local angle = i * angleStep
local x = oval.mapX + (oval.r1 * math.cos(angle))
local y = oval.mapY + (oval.r2 * math.sin(angle))
table.insert(points, { x = x, y = 0, z = y } )
end
MarkupToAll(7, id, points, fillColor, color, lineStyle)
end
---@param free Free
local function DrawFree(free)
local fillColor = DrawingHelper.ColorToColorTable(free.fillColorString)
local color = DrawingHelper.ColorToColorTable(free.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(free.style)
local points = {}
for _, point in ipairs(free.points) do
table.insert(points, { x = point.x, y = 0, z = point.y } )
end
MarkupToAll(7, id, points, fillColor, color, lineStyle)
end
---@param rect Rect
local function DrawRect(rect)
local fillColor = DrawingHelper.ColorToColorTable(rect.fillColorString)
local color = DrawingHelper.ColorToColorTable(rect.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(rect.style)
local pointA = { x = rect.mapX, y = 0, z = rect.mapY }
local pointB = { x = rect.mapX + rect.width, y = 0, z = rect.mapY + rect.height }
trigger.action.rectToAll(-1, id, pointA, pointB, color, fillColor, lineStyle, true)
end
---@param arrow Arrow
local function DrawArrow(arrow)
local fillColor = DrawingHelper.ColorToColorTable(arrow.fillColorString)
local color = DrawingHelper.ColorToColorTable(arrow.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(arrow.style)
local startPoint = { x = arrow.mapX, y = 0, z = arrow.mapY }
local rad = math.rad(arrow.angle or 0)
local length = arrow.length or 100
local endPoint = { x = arrow.mapX + length * math.cos(rad), y = 0, z = arrow.mapY + length * math.sin(rad) }
trigger.action.arrowToAll(-1, id, startPoint, endPoint, color, fillColor, lineStyle, true)
end
if object.polygonMode == "circle" then
DrawCircle(object--[[@as Circle]])
elseif object.polygonMode == "oval" then
DrawOval(object--[[@as Oval]])
elseif object.polygonMode == "free" then
DrawFree(object--[[@as Free]])
elseif object.polygonMode == "rect" then
DrawRect(object--[[@as Rect]])
elseif object.polygonMode == "arrow" then
DrawArrow(object--[[@as Arrow]])
end
end
---@private
---@param object Line
---@param id integer
function DrawingHelper.DrawLine(object, id)
---@type Array<Vec3>
local points = {}
for _, point in ipairs(object.points) do
table.insert(points, { x = point.x, y = 0, z = point.y } )
end
local color = DrawingHelper.ColorToColorTable(object.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(object.style)
MarkupToAll(1, id, points, color, color, lineStyle)
end
---@private
---@param object TextBox
---@param id integer
function DrawingHelper.DrawTextBox(object, id)
trigger.action.textToAll(-1, id, { x= object.mapX, y = 0, z = object.mapY },
DrawingHelper.ColorToColorTable(object.colorString),
DrawingHelper.ColorToColorTable(object.fillColorString),
object.fontSize or 12,
true,
object.text or "")
end
function DrawingHelper.Remove(id)
trigger.action.removeMark(id)
end
---@param hexStr string
---@return table
function DrawingHelper.ColorToColorTable(hexStr)
hexStr = hexStr:gsub("0x", "")
local a = tonumber(hexStr:sub(1, 2), 16) / 255
local r = tonumber(hexStr:sub(3, 4), 16) / 255
local g = tonumber(hexStr:sub(5, 6), 16) / 255
local b = tonumber(hexStr:sub(7, 8), 16) / 255
return { r, g , b , a }
end
---@param lineStyle string
function DrawingHelper.ToLineStyleInteger(lineStyle)
lineStyle = lineStyle:lower()
if lineStyle == "no line" then
return 0
elseif lineStyle == "solid" then
return 1
elseif lineStyle == "dashed" then
return 2
elseif lineStyle == "dotted" then
return 3
elseif lineStyle == "dot dash" then
return 4
elseif lineStyle == "long dash" then
return 5
elseif lineStyle == "two dash" then
return 6
else
return 0
end
end
---@class ARGB
---@field public a number
---@field public r number
---@field public g number
---@field public b number
if not Spearhead then Spearhead = {} end
if not Spearhead.classes then Spearhead.classes = {} end
if not Spearhead.classes.stageClasses then Spearhead.classes.stageClasses = {} end
if not Spearhead.classes.stageClasses.drawings then Spearhead.classes.stageClasses.drawings = {} end
if not Spearhead.classes.stageClasses.drawings.helper then Spearhead.classes.stageClasses.drawings.helper = {} end
Spearhead.classes.stageClasses.drawings.helper.DrawingHelper = DrawingHelper