Files
spearhead/stageClasses/Stage.lua
T
2024-09-26 00:02:05 +02:00

443 lines
17 KiB
Lua

local Stage = {}
do --init STAGE DIRECTOR
local stageDrawingId = 0
---comment
---@param stagezone_name string
---@param database table
---@param logger table
---@return table?
function Stage:new(stagezone_name, database, logger, stageConfig)
local o = {}
setmetatable(o, { __index = self })
o.zoneName = stagezone_name
local split = Spearhead.Util.split_string(stagezone_name, "_")
if Spearhead.Util.tableLength(split) < 2 then
Spearhead.AddMissionEditorWarning("Stage zone with name " .. stagezone_name .. " does not have a order number or valid format")
return nil
end
local orderNumber = tonumber(split[2])
if orderNumber == nil then
Spearhead.AddMissionEditorWarning("Stage zone with name " .. stagezone_name .. " does not have a valid order number : " .. split[2])
return nil
end
o.stageNumber = orderNumber
o.database = database
o.logger = logger
o.db = {}
o.db.missionsByCode = {}
o.db.missions = {}
o.db.sams = {}
o.db.redAirbasegroups = {}
o.db.blueAirbasegroups = {}
o.db.airbaseIds = {}
o.db.farps = {}
o.activeStage = 0
o.preActivated = false
o.stageConfig = stageConfig or {}
o.stageDrawingId = stageDrawingId + 1
stageDrawingId = stageDrawingId + 1
do --Init Stage
logger:info("Initiating new Stage with name: " .. stagezone_name)
local missionZones = database:getMissionsForStage(stagezone_name)
for _, missionZone in pairs(missionZones) do
local mission = Spearhead.internal.Mission:new(missionZone, database, logger)
if mission then
o.db.missionsByCode[mission.code] = mission
if mission.missionType == Spearhead.internal.Mission.MissionType.SAM then
table.insert(o.db.sams, mission)
else
table.insert(o.db.missions, mission)
end
end
end
local randomMissionNames = database:getRandomMissionsForStage(stagezone_name)
local randomMissionByName = {}
for _, missionZoneName in pairs(randomMissionNames) do
local mission = Spearhead.internal.Mission:new(missionZoneName, database, logger)
if mission then
if randomMissionByName[mission.name] == nil then
randomMissionByName[mission.name] = {}
end
table.insert(randomMissionByName[mission.name], mission)
end
end
for _, missions in pairs(randomMissionByName) do
local mission = Spearhead.Util.randomFromList(missions)
if mission then
o.db.missionsByCode[mission.code] = mission
if mission.missionType == Spearhead.internal.Mission.MissionType.SAM then
table.insert(o.db.sams, mission)
else
table.insert(o.db.missions, mission)
end
end
end
local airbaseIds = database:getAirbaseIdsInStage(o.zoneName)
if airbaseIds ~= nil and type(airbaseIds) == "table" then
o.db.airbaseIds = airbaseIds
for _, airbaseId in pairs(airbaseIds) do
for _, groupName in pairs(database:getRedGroupsAtAirbase(airbaseId)) do
table.insert(o.db.redAirbasegroups, groupName)
end
for _, groupName in pairs(database:getBlueGroupsAtAirbase(airbaseId)) do
table.insert(o.db.blueAirbasegroups, groupName)
end
end
end
local farps = database:getFarpZonesInStage(o.zoneName)
if farps ~= nil and type(farps) == "table" then o.db.farps = farps end
end
o.IsComplete = function(self)
for i, mission in pairs(self.db.missions) do
local state = mission:GetState()
if state == Spearhead.Mission.MissionState.ACTIVE or state == Spearhead.Mission.MissionState.NEW then
return false
end
end
return true
end
---Activates all SAMS, Airbase units etc all at once.
---@param self table
o.PreActivate = function(self)
if self.preActivated == false then
self.preActivated = true
for key, mission in pairs(self.db.sams) do
if mission and mission.Activate then
mission:Activate()
end
end
self.logger:debug("Pre-activating stage with airbase groups amount: " .. Spearhead.Util.tableLength(self.db.redAirbasegroups))
for _ , groupName in pairs(self.db.redAirbasegroups) do
Spearhead.DcsUtil.SpawnGroupTemplate(groupName)
end
end
if self.activeStage == self.stageNumber then
for _, mission in pairs(self.db.sams) do
self:AddCommmandsForMissionToAllPlayers(mission)
end
end
end
local activateMissionsIfApplicableAsync = function(self)
self:ActivateMissionsIfApplicable(self)
end
o.MarkStage = function(self, blue)
local fillColor = {1, 0, 0, 0.1}
local line ={ 1, 0,0, 1 }
if blue == true then
fillColor = {0, 0, 1, 0.1}
line ={ 0, 0,1, 1 }
end
local zone = Spearhead.DcsUtil.getZoneByName(self.zoneName)
if zone then
self.logger:debug("drawing stage")
if zone.zone_type == Spearhead.DcsUtil.ZoneType.Cilinder then
trigger.action.circleToAll(-1, self.stageDrawingId, {x = zone.x, y = 0 , z = zone.z}, zone.radius, {0,0,0,0}, {0,0,0,0},4, true)
else
--trigger.action.circleToAll(-1, self.stageDrawingId, {x = zone.x, y = 0 , z = zone.z}, zone.radius, { 1, 0,0, 1 }, {1,0,0,1},4, true)
trigger.action.quadToAll( -1, self.stageDrawingId, zone.verts[2], zone.verts[1], zone.verts[4], zone.verts[3], {0,0,0,0}, {0,0,0,0}, 4, true)
end
trigger.action.setMarkupColorFill(self.stageDrawingId, fillColor)
trigger.action.setMarkupColor(self.stageDrawingId, line)
end
end
o.ActivateStage = function(self)
pcall(function()
self:MarkStage()
end)
self:PreActivate()
local miscGroups = self.database:getMiscGroupsAtStage(self.zoneName)
self.logger:debug("Activating Misc groups for zone: " .. Spearhead.Util.tableLength(miscGroups))
for _, groupName in pairs(miscGroups) do
Spearhead.DcsUtil.SpawnGroupTemplate(groupName)
end
for _, mission in pairs(self.db.missions) do
if mission.missionType == Spearhead.internal.Mission.MissionType.DEAD then
mission:Activate()
self:AddCommmandsForMissionToAllPlayers(mission)
end
end
timer.scheduleFunction(activateMissionsIfApplicableAsync, self, timer.getTime() + 5)
end
o.ActivateMissionsIfApplicable = function (self)
local activeCount = 0
local availableMissions = {}
for _, mission in pairs(self.db.missionsByCode) do
if mission.missionState == Spearhead.internal.Mission.MissionState.ACTIVE then
activeCount = activeCount + 1
end
if mission.missionState == Spearhead.internal.Mission.MissionState.NEW then
table.insert(availableMissions, mission)
end
end
local max = self.stageConfig.maxMissionsInStage or 10
local availableMissionsCount = Spearhead.Util.tableLength(availableMissions)
if activeCount < max and availableMissionsCount > 0 then
for i = activeCount+1, max do
if availableMissionsCount == 0 then
i = max+1 --exits this loop
else
local index = math.random(1, availableMissionsCount)
local mission = table.remove(availableMissions, index)
if mission then
mission:Activate()
self:AddCommmandsForMissionToAllPlayers(mission)
end
availableMissionsCount = availableMissionsCount - 1
end
end
end
end
---Cleans up all missions
---@param self table
o.Clean = function(self)
for key, mission in pairs(self.db.missions) do
mission:Cleanup()
end
for key, samMission in pairs(self.db.sams) do
samMission:Cleanup()
end
for _, airbase in pairs(self.db.airbases) do
for _, redGroupName in pairs(airbase.redAirbaseGroupNames) do
Spearhead.DcsUtil.DcsUtil.DestroyGroup(redGroupName)
end
end
logger:debug("'" .. Spearhead.Util.toString(self.zoneName) .. "' cleaned")
end
local ActivateBlueAsync = function(self)
pcall(function()
self:MarkStage(true)
end)
for key, airbaseId in pairs(self.db.airbaseIds) do
local airbase = Spearhead.DcsUtil.getAirbaseById(airbaseId)
if airbase then
local startingCoalition = Spearhead.DcsUtil.getStartingCoalition(airbaseId)
if startingCoalition == coalition.side.BLUE then
airbase:setCoalition(2)
for _, blueGroupName in pairs(self.db.blueAirbasegroups) do
Spearhead.DcsUtil.SpawnGroupTemplate(blueGroupName)
end
else
airbase:setCoalition(0)
end
end
end
end
---Sets airfields to blue and spawns friendly farps
o.ActivateBlueStage = function(self)
logger:debug("Setting stage '" .. Spearhead.Util.toString(self.zoneName) .. "' to blue")
for _, groupName in pairs(self.db.redAirbasegroups) do
Spearhead.DcsUtil.DestroyGroup(groupName)
end
for _, mission in pairs(self.db.missions) do
mission:Cleanup()
end
for _, mission in pairs(self.db.sams) do
mission:Cleanup()
end
timer.scheduleFunction(ActivateBlueAsync, self, timer.getTime() + 3)
-- for key, farp in pairs(self.db.farps) do
-- if farp.helipadnames then
-- for _, helipadName in pairs(farp.helipadnames) do
-- local helipad = Airbase.getByName(helipadName)
-- if helipad then
-- logger:debug("Enabling: '" .. helipad:getName() .. "'")
-- helipad:setCoalition(2)
-- else
-- logger:warn(helipadName .. " not found when spawning farps")
-- end
-- end
-- end
-- if farp.group_names then
-- for _, groupName in pairs(farp.group_names) do
-- Spearhead.DcsUtil.SpawnGroupTemplate(groupName)
-- end
-- end
-- end
end
o.OnStatusRequestReceived = function(self, groupId)
if self.activeStage ~= self.stageNumber then
return
end
trigger.action.outTextForGroup(groupId, "Status Update incoming... ", 3)
local text = "Mission Status: \n"
local totalmissions = 0
local completedMissions = 0
for _, mission in pairs(self.db.missionsByCode) do
totalmissions = totalmissions + 1
if mission.missionState == Spearhead.internal.Mission.MissionState.ACTIVE then
text = text .. "\n [" .. mission.code .. "] " .. mission.name ..
" (" .. mission.missionTypeDisplayName .. ") \n"
end
if mission.missionState == Spearhead.internal.Mission.MissionState.COMPLETED then
completedMissions = completedMissions + 1
end
end
local completionPercentage = math.floor((completedMissions / totalmissions) * 100)
text = text .. " \n Missions Complete: " .. completionPercentage .. "%"
self.logger:debug(text)
trigger.action.outTextForGroup(groupId, text, 20)
end
o.OnStageNumberChanged = function (self, number)
if self.activeStage == number then --only activate once for a stage
return
end
local previousActive = self.activeStage
self.activeStage = number
if Spearhead.capInfo.IsCapActiveWhenZoneIsActive(self.zoneName, number) == true then
self:PreActivate()
end
if number == self.stageNumber then
self:ActivateStage()
end
if previousActive <= self.stageNumber then
if number > self.stageNumber then
self:ActivateBlueStage()
self:RemoveAllMissionCommands()
end
end
end
--- input = { self, groupId, missionCode }
local ShowBriefingClicked = function (input)
local self = input.self
local groupId = input.groupId
local missionCode = input.missionCode
local mission = self.db.missionsByCode[missionCode]
if mission then
mission:ShowBriefing(groupId)
end
end
o.RemoveMissionCommands = function (self, mission)
self.logger:debug("Removing commands for: " .. mission.name)
local folderName = mission.name .. "(" .. mission.missionTypeDisplayName .. ")"
for i = 0, 2 do
local players = coalition.getPlayers(i)
for _, playerUnit in pairs(players) do
local groupId = playerUnit:getGroup():getID()
missionCommands.removeItemForGroup(groupId, { "Missions", folderName })
end
end
end
o.RemoveAllMissionCommands = function (self)
for _, mission in pairs(self.db.missionsByCode) do
self:RemoveMissionCommands(mission)
end
end
o.AddCommandsForMissionToGroup = function (self, groupId, mission)
local folderName = mission.name .. "(" .. mission.missionTypeDisplayName .. ")"
missionCommands.addSubMenuForGroup(groupId, folderName, { "Missions"} )
missionCommands.addCommandForGroup(groupId, "Show Briefing", { "Missions", folderName }, ShowBriefingClicked, { self = self, groupId = groupId, missionCode = mission.code })
end
o.AddCommmandsForMissionToAllPlayers = function(self, mission)
for i = 0, 2 do
local players = coalition.getPlayers(i)
for _, playerUnit in pairs(players) do
local groupId = playerUnit:getGroup():getID()
self:AddCommandsForMissionToGroup(groupId, mission)
end
end
end
o.OnPlayerEntersUnit = function (self, unit)
if self.activeStage == self.stageNumber then
local groupId = unit:getGroup():getID()
for _, mission in pairs(self.db.missionsByCode) do
if mission.missionState == Spearhead.internal.Mission.MissionState.ACTIVE then
self:AddCommandsForMissionToGroup(groupId, mission)
end
end
end
end
local removeMissionCommandsDelayed = function(input)
local self = input.self
local mission = input.mission
self:RemoveMissionCommands(mission)
end
o.OnMissionComplete = function(self, mission)
timer.scheduleFunction(removeMissionCommandsDelayed, { self = self, mission = mission}, timer.getTime() + 20)
timer.scheduleFunction(activateMissionsIfApplicableAsync, self, timer.getTime() + 10)
end
for _, mission in pairs(o.db.missionsByCode) do
mission:AddMissionCompleteListener(o)
end
Spearhead.Events.AddOnStatusRequestReceivedListener(o)
Spearhead.Events.AddStageNumberChangedListener(o)
return o
end
end
Spearhead.internal.Stage = Stage