custom drawings and animations for video
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user