Major refactor to include tactical combat feed
This commit is contained in:
@@ -1,4 +1,22 @@
|
||||
require("GameManager/FactionStruct")
|
||||
require("GameManager/GUIManager")
|
||||
require("GameManager/TutorialTextManager")
|
||||
|
||||
-- ==================================================
|
||||
-- Define Manager constants
|
||||
-- ==================================================
|
||||
|
||||
---The singleton GUI Manager.
|
||||
---@type GUIManager
|
||||
GUIManager = GUIManager:New()
|
||||
|
||||
---The singleton Tutorial Text Manager.
|
||||
---@type TutorialTextManager
|
||||
TextManager = TutorialTextManager:New()
|
||||
|
||||
---The local player.
|
||||
---@type PlayerObject|nil
|
||||
LocalPlayer = nil
|
||||
|
||||
-- ==================================================
|
||||
-- Define Faction constants
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
require("PGBase")
|
||||
require("GameManager/Constants")
|
||||
require("GameManager/Utilities")
|
||||
|
||||
---@class GUIManager
|
||||
---@field TacticalGame TacticalGameClass|nil The local Tactical Game state.
|
||||
---@field SkirmishGame SkirmishGameClass|nil The local Skirmish Game state.
|
||||
---@field ShowTeamId integer The Team ID units to display.
|
||||
GUIManager = {}
|
||||
GUIManager.__index = GUIManager
|
||||
|
||||
@@ -13,22 +10,15 @@ GUIManager.__index = GUIManager
|
||||
function GUIManager:New()
|
||||
local self = setmetatable({}, GUIManager)
|
||||
|
||||
self.TacticalGame = nil
|
||||
self.SkirmishGame = nil
|
||||
self.ShowTeamId = 0
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
---Initializes the GUI Manager for Skirmish mode.
|
||||
---@param game SkirmishGameClass The Skirmish Game state.
|
||||
function GUIManager:InitSkirmish(game)
|
||||
self.SkirmishGame = game
|
||||
self.TacticalGame = game.TacticalGame
|
||||
---@param isSpectator boolean Whether to initialize in spectator mode.
|
||||
function GUIManager:InitSkirmish(isSpectator)
|
||||
self:InitTactical()
|
||||
|
||||
GUI_Component_Visibility(UI_GameTime, true)
|
||||
|
||||
if self.SkirmishGame.IsLocalSpectator then
|
||||
if isSpectator then
|
||||
GUI_Component_Visibility(UI_CreditsT1, true)
|
||||
GUI_Component_Visibility(UI_IconT1, true)
|
||||
|
||||
@@ -41,18 +31,12 @@ function GUIManager:InitSkirmish(game)
|
||||
end
|
||||
|
||||
---Initializes the GUI Manager for Tactical mode.
|
||||
---@param game TacticalGameClass The Tactical Game state.
|
||||
function GUIManager:InitTactical(game)
|
||||
self.TacticalGame = game
|
||||
|
||||
function GUIManager:InitTactical()
|
||||
GUI_Component_Visibility(UI_GameTime, true)
|
||||
end
|
||||
|
||||
---Resets the GUI Manager.
|
||||
function GUIManager:Reset()
|
||||
self.SkirmishGame = nil
|
||||
self.TacticalGame = nil
|
||||
|
||||
GUI_Component_Text(UI_GameTime, "")
|
||||
GUI_Text_Color(UI_GameTime, 1, 1, 1, 1)
|
||||
GUI_Component_Visibility(UI_GameTime, false)
|
||||
@@ -75,129 +59,43 @@ function GUIManager:Reset()
|
||||
GUI_Component_Visibility(UI_CreditsTactical, true)
|
||||
end
|
||||
|
||||
---Services the GUI Manager.
|
||||
function GUIManager:Service()
|
||||
if not self.TacticalGame then
|
||||
-- Nothing to service
|
||||
return
|
||||
end
|
||||
|
||||
ScriptMessage("Servicing GUI Updates...")
|
||||
ServiceGameTime(self.TacticalGame)
|
||||
ServiceTeamCredits(self.SkirmishGame)
|
||||
--ServiceUnitDisplay(self.SkirmishGame, self.ShowTeamId)
|
||||
ServiceScreenText(self.SkirmishGame)
|
||||
end
|
||||
|
||||
---Services Game Time display.
|
||||
---@param tacticalGame TacticalGameClass The current Tactical Game state
|
||||
function ServiceGameTime(tacticalGame)
|
||||
if not tacticalGame then
|
||||
return
|
||||
end
|
||||
|
||||
local gameTime = Dirty_Floor(GetCurrentTime()) - tacticalGame.StartTime
|
||||
local minutes = Dirty_Floor(gameTime / 60)
|
||||
local minutesText = tostring(minutes)
|
||||
|
||||
if tonumber(minutes) < 10 then
|
||||
minutesText = "0" .. minutesText
|
||||
end
|
||||
|
||||
local seconds = gameTime - (minutes * 60)
|
||||
local secondsText = tostring(seconds)
|
||||
|
||||
if tonumber(seconds) < 10 then
|
||||
secondsText = "0" .. secondsText
|
||||
end
|
||||
|
||||
local text = string.format("Time: %s:%s", minutesText, secondsText)
|
||||
---@param gameTime number The current game time.
|
||||
function GUIManager:DisplayGameTime(gameTime)
|
||||
local timeText = FormatTime(gameTime)
|
||||
local text = string.format("Time: %s", timeText)
|
||||
|
||||
GUI_Component_Text(UI_GameTime, text)
|
||||
end
|
||||
|
||||
---Services Team Credits display.
|
||||
---@param skirmishGame SkirmishGameClass The current Skirmish Game state.
|
||||
function ServiceTeamCredits(skirmishGame)
|
||||
if not skirmishGame then
|
||||
---Displays credits for the specified team
|
||||
---@param team TeamStruct The team.
|
||||
---@param credits number The team credits.
|
||||
---@param income number The team income.
|
||||
function GUIManager:DisplayTeamCredits(team, credits, income)
|
||||
local uiText, uiIcon = "", ""
|
||||
|
||||
if team.Number == 1 then
|
||||
uiText = UI_CreditsT1
|
||||
uiIcon = UI_IconT1
|
||||
elseif team.Number == 2 then
|
||||
uiText = UI_CreditsT2
|
||||
uiIcon = UI_IconT2
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
if not skirmishGame.IsLocalSpectator then
|
||||
return
|
||||
local positiveText = "+"
|
||||
|
||||
if income < 0 then
|
||||
positiveText = ""
|
||||
end
|
||||
|
||||
---Displays credits for the specified team
|
||||
---@param team TeamStruct The team to service.
|
||||
---@param uiText string The name of the UI Component to display Team credits in.
|
||||
---@param uiIcon string The name of the UI Component to display the Faction icon in.
|
||||
local function DisplayTeamCredits(team, uiText, uiIcon)
|
||||
local teamCredits = skirmishGame:CalculateTeamTotalCredits(team.Id)
|
||||
local teamIncome = skirmishGame:CalculateTeamTotalIncome(team.Id)
|
||||
local positiveText = "+"
|
||||
local text = string.format("Team %d: $%d (%s%d)", team.Number, credits, positiveText, income)
|
||||
local icon = team.Faction.Icon
|
||||
local color = team.Faction.Color
|
||||
|
||||
if teamIncome < 0 then
|
||||
positiveText = ""
|
||||
end
|
||||
|
||||
local text = string.format("Team %d: $%d (%s%d)", team.Number, teamCredits, positiveText, teamIncome)
|
||||
local icon = team.Faction.Icon
|
||||
local color = team.Faction.Color
|
||||
|
||||
GUI_Button_Icon(uiIcon, icon, color.R, color.G, color.B, 1)
|
||||
GUI_Component_Text(uiText, text)
|
||||
GUI_Text_Color(uiText, color.R, color.G, color.B, 1)
|
||||
end
|
||||
|
||||
for _, team in pairs(skirmishGame.Teams) do
|
||||
if team.Number == 1 then
|
||||
DisplayTeamCredits(team, UI_CreditsT1, UI_IconT1)
|
||||
elseif team.Number == 2 then
|
||||
DisplayTeamCredits(team, UI_CreditsT2, UI_IconT2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Services Team Units display.
|
||||
---@param skirmishGame SkirmishGameClass The current Skirmish Game state.
|
||||
---@param teamId integer The Team ID's units to display.
|
||||
function ServiceUnitDisplay(skirmishGame, teamId)
|
||||
if not skirmishGame then
|
||||
return
|
||||
end
|
||||
|
||||
if not skirmishGame.IsLocalSpectator then
|
||||
return
|
||||
end
|
||||
|
||||
local localPlayer = Find_Player("local")
|
||||
|
||||
if not localPlayer then
|
||||
return
|
||||
end
|
||||
|
||||
local function DisplayTeamUnit(unit, uiComponent)
|
||||
|
||||
end
|
||||
|
||||
local players = skirmishGame:GetPlayersOnTeam(teamId)
|
||||
---@type table<string, integer> Units Table by name with alive count.
|
||||
local units = {}
|
||||
|
||||
for _, player in pairs(players) do
|
||||
local playerUnits = player:GetAliveUnits()
|
||||
|
||||
for _, playerUnit in pairs(playerUnits) do
|
||||
localPlayer.Select_Object(playerUnit.GameObjectWrapper)
|
||||
|
||||
if not units[playerUnit.Name] then
|
||||
units[playerUnit.Name] = 1
|
||||
else
|
||||
units[playerUnit.Name] = units[playerUnit.Name] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ServiceScreenText(skirmishGame)
|
||||
GUI_Button_Icon(uiIcon, icon, color.R, color.G, color.B, 1)
|
||||
GUI_Component_Text(uiText, text)
|
||||
GUI_Text_Color(uiText, color.R, color.G, color.B, 1)
|
||||
end
|
||||
|
||||
@@ -65,9 +65,9 @@ end
|
||||
---@param player table The FoC PlayerWrapper object that owns the new Unit.
|
||||
function GalacticGameClass:UnitBuilt(objectType, player)
|
||||
local playerId = player.Get_ID()
|
||||
local player = self.Players[playerId]
|
||||
local playerEntry = self.Players[playerId]
|
||||
|
||||
if player then
|
||||
player:AddUnit(objectType)
|
||||
if playerEntry then
|
||||
playerEntry:AddUnit(objectType)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,10 +45,10 @@ function PlayerClass:Service()
|
||||
|
||||
-- Pass 1: Collect assigned game object wrappers from alive units
|
||||
for _, unit in pairs(self:GetAliveUnits()) do
|
||||
if TestValid(unit.GameObjectWrapper) then
|
||||
assignedUnits[unit.GameObjectWrapper] = true
|
||||
if TestValid(unit.GameObject) then
|
||||
assignedUnits[unit.GameObject] = true
|
||||
else
|
||||
unit:SetDead()
|
||||
unit:SetDead(-1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -81,11 +81,14 @@ end
|
||||
|
||||
---Adds a Unit type to the Player's reinforcement list.
|
||||
---@param objectType table FoC GameObjectTypeWrapper object that was built.
|
||||
---@return UnitClass
|
||||
function PlayerClass:AddUnit(objectType)
|
||||
local unit = UnitClass:New(objectType, self.Id)
|
||||
|
||||
table.insert(self.Units, unit)
|
||||
ScriptMessage("Unit Added: %s", unit:Debug())
|
||||
|
||||
return unit
|
||||
end
|
||||
|
||||
---Gets all Reinforcement Units for this Player.
|
||||
|
||||
@@ -20,7 +20,6 @@ end
|
||||
---@param credits number
|
||||
function ResourceClass:SetCredits(credits)
|
||||
self.LastCredits = self.Credits
|
||||
self.Credits = credits
|
||||
|
||||
if credits < 0 then
|
||||
self.Credits = 0
|
||||
|
||||
@@ -1,110 +1,26 @@
|
||||
require("PGBase")
|
||||
require("GameManager/Constants")
|
||||
require("GameManager/TacticalGameClass")
|
||||
require("GameManager/SpectatorStruct")
|
||||
require("GameManager/TeamStruct")
|
||||
|
||||
---@class SkirmishGameClass
|
||||
---@field TacticalGame TacticalGameClass The underlying Tactical Game context.
|
||||
---@class SkirmishGameClass : TacticalGameClass
|
||||
---@field Spectators SpectatorStruct[] The spectator players in this game.
|
||||
---@field IsLocalSpectator boolean Whether the local player is a spectator.
|
||||
---@field Teams TeamStruct[] The teams in this game.
|
||||
SkirmishGameClass = {}
|
||||
SkirmishGameClass.__index = SkirmishGameClass
|
||||
setmetatable(SkirmishGameClass, { __index = TacticalGameClass })
|
||||
|
||||
---Creates a new Skirmish Game context.
|
||||
---@param gameMode string The game mode.
|
||||
---@return SkirmishGameClass
|
||||
function SkirmishGameClass:New(gameMode)
|
||||
ScriptMessage("Initializing Skirmish game...")
|
||||
local self = setmetatable({}, SkirmishGameClass)
|
||||
local self = setmetatable(TacticalGameClass:New(gameMode), SkirmishGameClass)
|
||||
|
||||
---Finds all spectators in the game.
|
||||
---@return SpectatorStruct[]
|
||||
local function FindSpectators()
|
||||
---@type SpectatorStruct[]
|
||||
local spectators = {}
|
||||
---@type string
|
||||
local spectatorMarker = nil
|
||||
|
||||
if StringCompare(gameMode, "Space") then
|
||||
spectatorMarker = Spectator_Marker_Space
|
||||
elseif StringCompare(gameMode, "Land") then
|
||||
spectatorMarker = Spectator_Marker_Land
|
||||
end
|
||||
|
||||
if spectatorMarker then
|
||||
for k, marker in pairs(Find_All_Objects_Of_Type(spectatorMarker)) do
|
||||
local playerWrapper = marker.Get_Owner()
|
||||
local playerId = playerWrapper.Get_ID()
|
||||
|
||||
if not spectators[playerId] then
|
||||
local spectator = SpectatorStruct:New(playerWrapper)
|
||||
|
||||
spectators[playerId] = spectator
|
||||
ScriptMessage("Found Spectator: %s", spectator:Debug())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return spectators
|
||||
end
|
||||
|
||||
self.TacticalGame = TacticalGameClass:New(gameMode)
|
||||
self.Spectators = FindSpectators()
|
||||
|
||||
---Gets whether the local player is a spectator.
|
||||
---@returns boolean
|
||||
local function GetLocalSpectator()
|
||||
local localPlayer = Find_Player("local")
|
||||
|
||||
if not localPlayer then
|
||||
return false
|
||||
end
|
||||
|
||||
return self:GetSpectator(localPlayer.Get_ID()) ~= nil
|
||||
end
|
||||
|
||||
self.IsLocalSpectator = GetLocalSpectator()
|
||||
|
||||
---Builds all teams in the game.
|
||||
---@return TeamStruct[]
|
||||
local function BuildTeams()
|
||||
---@type TeamStruct[]
|
||||
local teams = {}
|
||||
|
||||
-- Build combatant player teams
|
||||
for playerId, player in pairs(self.TacticalGame.Players) do
|
||||
local teamId = player.TeamId
|
||||
|
||||
if teamId >= 0 then
|
||||
if teams[teamId] == nil then
|
||||
teams[teamId] = TeamStruct:New(teamId, player.Faction, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Build spectator player teams
|
||||
for playerId, spectator in pairs(self.Spectators) do
|
||||
local teamId = spectator.TeamId
|
||||
|
||||
if teamId >= 0 then
|
||||
local team = teams[teamId]
|
||||
|
||||
if team == nil then
|
||||
team = TeamStruct:New(teamId, spectator.Faction, true)
|
||||
teams[teamId] = team
|
||||
ScriptMessage("Found Team: %s", team:Debug())
|
||||
else
|
||||
team.IsSpectator = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return teams
|
||||
end
|
||||
|
||||
self.Teams = BuildTeams()
|
||||
---@cast self SkirmishGameClass
|
||||
self:_FindSpectators()
|
||||
self.IsLocalSpectator = self:_GetLocalSpectator()
|
||||
self:_BuildTeams()
|
||||
ScriptMessage("Skirmish Game initialized!")
|
||||
|
||||
return self
|
||||
@@ -112,31 +28,116 @@ end
|
||||
|
||||
---Services the Skirmish Game.
|
||||
function SkirmishGameClass:Service()
|
||||
ScriptMessage("Servicing Skirmish Game...")
|
||||
-- Service TacticalGame
|
||||
self.TacticalGame:Service()
|
||||
TacticalGameClass.Service(self)
|
||||
ScriptMessage("Servicing Skirmish Game...")
|
||||
|
||||
for _, team in pairs(self.Teams) do
|
||||
local credits = self:CalculateTeamTotalCredits(team.Id)
|
||||
local income = self:CalculateTeamTotalIncome(team.Id)
|
||||
|
||||
GUIManager:DisplayTeamCredits(team, credits, income)
|
||||
end
|
||||
end
|
||||
|
||||
-- ==================================================
|
||||
-- Unit event handlers
|
||||
-- ==================================================
|
||||
|
||||
---Displays unit built combat text.
|
||||
---@param unit UnitClass The built unit.
|
||||
function SkirmishGameClass:CombatTextUnitBuilt(unit)
|
||||
local owner = self.Players[unit.OwnerId]
|
||||
|
||||
if not owner then
|
||||
return
|
||||
end
|
||||
|
||||
local team = self.Teams[owner.TeamId]
|
||||
|
||||
if not team then
|
||||
return
|
||||
end
|
||||
|
||||
local timeText = FormatTime(unit.BuildTime)
|
||||
local text = string.format("%s\t<T%d> [%s]: BUILT %s ($%d)", timeText, team.Number, owner.Name, unit.Name,
|
||||
unit.BuildCost)
|
||||
local faction = Factions[owner.Faction]
|
||||
---@type ColorStruct
|
||||
local color
|
||||
|
||||
if faction then
|
||||
color = faction.Color
|
||||
else
|
||||
color = ColorStruct:New(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
self.CombatFeed:Append(text, -1, color)
|
||||
TextManager:SetCurrentView("combat_feed")
|
||||
end
|
||||
|
||||
---Displays killed unit combat text.
|
||||
---@param unit UnitClass The killed unit.
|
||||
function SkirmishGameClass:CombatTextUnitKilled(unit)
|
||||
local owner = self.Players[unit.OwnerId]
|
||||
|
||||
if not owner then
|
||||
return
|
||||
end
|
||||
|
||||
local killer = self.Players[unit.KillerId]
|
||||
local timeText = FormatTime(unit.DeathTime)
|
||||
|
||||
if not killer then
|
||||
local team = self.Teams[owner.TeamId]
|
||||
|
||||
if not team then
|
||||
return
|
||||
end
|
||||
|
||||
local text = string.format("%s\t<T%d> [%s]: MISTAKES WERE MADE %s", timeText, team.Number, owner.Name, unit.Name)
|
||||
local color = ColorStruct:New(0.8, 0.8, 0.8, 1)
|
||||
|
||||
self.CombatFeed:Append(text, -1, color)
|
||||
else
|
||||
local team = self.Teams[killer.TeamId]
|
||||
|
||||
if not team then
|
||||
return
|
||||
end
|
||||
|
||||
local text = string.format("%s\t<T%d> [%s]: KILLED %s (%s)", timeText, team.Number, killer.Name, unit.Name,
|
||||
owner.Name)
|
||||
local faction = Factions[killer.Faction]
|
||||
---@type ColorStruct
|
||||
local color = nil
|
||||
|
||||
if faction then
|
||||
color = faction.Color
|
||||
else
|
||||
color = ColorStruct:New(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
self.CombatFeed:Append(text, -1, color)
|
||||
end
|
||||
end
|
||||
|
||||
-- ==================================================
|
||||
-- Player functions
|
||||
-- ==================================================
|
||||
|
||||
---Gets the Spectator by Player ID.
|
||||
---@param id integer Player ID
|
||||
---@return SpectatorStruct|nil
|
||||
function SkirmishGameClass:GetSpectator(id)
|
||||
for playerId, spectator in pairs(self.Spectators) do
|
||||
if playerId == id then
|
||||
return spectator
|
||||
end
|
||||
end
|
||||
return self.Spectators[id]
|
||||
end
|
||||
|
||||
---Gets the Team by ID.
|
||||
---@param id integer Team ID
|
||||
---@return TeamStruct|nil
|
||||
function SkirmishGameClass:GetTeam(id)
|
||||
for teamId, team in pairs(self.Teams) do
|
||||
if teamId == id then
|
||||
return team
|
||||
end
|
||||
end
|
||||
return self.Teams[id]
|
||||
end
|
||||
|
||||
---Gets the Players for the Team ID.
|
||||
@@ -146,7 +147,7 @@ function SkirmishGameClass:GetPlayersOnTeam(id)
|
||||
---@type PlayerClass[]
|
||||
local players = {}
|
||||
|
||||
for playerId, player in pairs(self.TacticalGame.Players) do
|
||||
for playerId, player in pairs(self.Players) do
|
||||
if player.TeamId == id then
|
||||
players[playerId] = player
|
||||
end
|
||||
@@ -155,6 +156,10 @@ function SkirmishGameClass:GetPlayersOnTeam(id)
|
||||
return players
|
||||
end
|
||||
|
||||
-- ==================================================
|
||||
-- Team functions
|
||||
-- ==================================================
|
||||
|
||||
---Calculates the Team ID's current total credits.
|
||||
---@param id integer Team ID.
|
||||
---@return integer
|
||||
@@ -182,3 +187,86 @@ function SkirmishGameClass:CalculateTeamTotalIncome(id)
|
||||
|
||||
return totalIncome
|
||||
end
|
||||
|
||||
-- ==================================================
|
||||
-- Private functions
|
||||
-- ==================================================
|
||||
|
||||
---@private
|
||||
---Finds all spectators in the game.
|
||||
function SkirmishGameClass:_FindSpectators()
|
||||
---@type SpectatorStruct[]
|
||||
local spectators = {}
|
||||
---@type string
|
||||
local spectatorMarker = nil
|
||||
|
||||
if StringCompare(self.GameMode, "Space") then
|
||||
spectatorMarker = Spectator_Marker_Space
|
||||
elseif StringCompare(self.GameMode, "Land") then
|
||||
spectatorMarker = Spectator_Marker_Land
|
||||
end
|
||||
|
||||
if spectatorMarker then
|
||||
for k, marker in pairs(Find_All_Objects_Of_Type(spectatorMarker)) do
|
||||
local playerWrapper = marker.Get_Owner()
|
||||
local playerId = playerWrapper.Get_ID()
|
||||
|
||||
if not spectators[playerId] then
|
||||
local spectator = SpectatorStruct:New(playerWrapper)
|
||||
|
||||
spectators[playerId] = spectator
|
||||
ScriptMessage("Found Spectator: %s", spectator:Debug())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.Spectators = spectators
|
||||
end
|
||||
|
||||
---@private
|
||||
---Gets whether the local player is a spectator.
|
||||
---@returns boolean
|
||||
function SkirmishGameClass:_GetLocalSpectator()
|
||||
if not LocalPlayer then
|
||||
return false
|
||||
end
|
||||
|
||||
return self:GetSpectator(LocalPlayer.Get_ID()) ~= nil
|
||||
end
|
||||
|
||||
---@private
|
||||
---Builds all teams in the game.
|
||||
function SkirmishGameClass:_BuildTeams()
|
||||
---@type TeamStruct[]
|
||||
local teams = {}
|
||||
|
||||
-- Build combatant player teams
|
||||
for playerId, player in pairs(self.Players) do
|
||||
local teamId = player.TeamId
|
||||
|
||||
if teamId >= 0 then
|
||||
if teams[teamId] == nil then
|
||||
teams[teamId] = TeamStruct:New(teamId, player.Faction, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Build spectator player teams
|
||||
for playerId, spectator in pairs(self.Spectators) do
|
||||
local teamId = spectator.TeamId
|
||||
|
||||
if teamId >= 0 then
|
||||
local team = teams[teamId]
|
||||
|
||||
if team == nil then
|
||||
team = TeamStruct:New(teamId, spectator.Faction, true)
|
||||
teams[teamId] = team
|
||||
ScriptMessage("Found Team: %s", team:Debug())
|
||||
else
|
||||
team.IsSpectator = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.Teams = teams
|
||||
end
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
require("PGBase")
|
||||
require("GameManager/Constants")
|
||||
require("GameManager/PlayerClass")
|
||||
require("GameManager/TutorialTextFeed")
|
||||
|
||||
---@class TacticalGameClass
|
||||
---@field GameMode string The tactical game mode.
|
||||
---@field StartTime integer The start time.
|
||||
---@field Players PlayerClass[] The combatant players in this game.
|
||||
---@field ReinforcementUnitCount table<string, integer> Key: Unit Type, Value: Count
|
||||
---@field AliveUnitCount table<string, integer> Key: Unit Type, Value: Count
|
||||
---@field DeadUnitCount table<string, integer> Key: Unit Type, Value: Count
|
||||
---@field CombatFeed TutorialTextFeed Text feed for unit builds and kills.
|
||||
TacticalGameClass = {}
|
||||
TacticalGameClass.__index = TacticalGameClass
|
||||
|
||||
@@ -18,42 +18,10 @@ function TacticalGameClass:New(gameMode)
|
||||
ScriptMessage("Initializing Tactical game...")
|
||||
local self = setmetatable({}, TacticalGameClass)
|
||||
|
||||
---Finds all combatant players in the game.
|
||||
---@return PlayerClass[]
|
||||
local function FindPlayers()
|
||||
---@type PlayerClass[]
|
||||
local players = {}
|
||||
|
||||
for k, faction in pairs(Factions) do
|
||||
local startingUnit = nil
|
||||
|
||||
if StringCompare(gameMode, "Land") then
|
||||
startingUnit = faction.LandStartUnitName
|
||||
elseif StringCompare(gameMode, "Space") then
|
||||
startingUnit = faction.SpaceStartUnitName
|
||||
end
|
||||
|
||||
if startingUnit then
|
||||
for i, unit in pairs(Find_All_Objects_Of_Type(startingUnit)) do
|
||||
local playerWrapper = unit.Get_Owner()
|
||||
local playerId = playerWrapper.Get_ID()
|
||||
|
||||
if players[playerId] == nil then
|
||||
local player = PlayerClass:New(playerWrapper)
|
||||
|
||||
players[playerId] = player
|
||||
ScriptMessage("Found Player: %s", player:Debug())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return players
|
||||
end
|
||||
|
||||
self.GameMode = gameMode
|
||||
self.StartTime = GetCurrentTime()
|
||||
self.Players = FindPlayers()
|
||||
self.Players = self:_FindPlayers(gameMode)
|
||||
self.CombatFeed = TutorialTextFeed:New("combat_feed", 6)
|
||||
ScriptMessage("Tactical Game initialized!")
|
||||
|
||||
return self
|
||||
@@ -67,8 +35,16 @@ function TacticalGameClass:Service()
|
||||
for _, player in pairs(self.Players) do
|
||||
player:Service()
|
||||
end
|
||||
|
||||
local gameTime = GetCurrentTime() - self.StartTime
|
||||
|
||||
GUIManager:DisplayGameTime(gameTime)
|
||||
end
|
||||
|
||||
-- ==================================================
|
||||
-- State functions
|
||||
-- ==================================================
|
||||
|
||||
---Whether this Tactical game is in space mode.
|
||||
---@return boolean
|
||||
function TacticalGameClass:IsSpaceMode()
|
||||
@@ -80,41 +56,163 @@ function TacticalGameClass:IsLandMode()
|
||||
return StringCompare(self.GameMode, "Land")
|
||||
end
|
||||
|
||||
-- ==================================================
|
||||
-- Player functions
|
||||
-- ==================================================
|
||||
|
||||
---Gets the Player by ID.
|
||||
---@param id integer Player ID
|
||||
---@return PlayerClass|nil
|
||||
function TacticalGameClass:GetPlayer(id)
|
||||
for playerId, player in pairs(self.Players) do
|
||||
if playerId == id then
|
||||
return player
|
||||
end
|
||||
end
|
||||
return self.Players[id]
|
||||
end
|
||||
|
||||
---Records the Player ID as having quit at the current time.
|
||||
---@param id integer Player ID.
|
||||
function TacticalGameClass:PlayerQuit(id)
|
||||
for playerId, player in pairs(self.Players) do
|
||||
if playerId == id then
|
||||
player:Quit()
|
||||
end
|
||||
local player = self.Players[id]
|
||||
|
||||
if player then
|
||||
player:Quit()
|
||||
end
|
||||
end
|
||||
|
||||
-- ==================================================
|
||||
-- Unit event handlers
|
||||
-- ==================================================
|
||||
|
||||
---Adds a built unit to the Unit table.
|
||||
---@param objectType table The FoC GameObjectTypeWrapper object type that was built.
|
||||
---@param player table The FoC PlayerWrapper object that owns the new Unit.
|
||||
---@param objectType GameObjectType The FoC GameObjectTypeWrapper object type that was built.
|
||||
---@param player PlayerObject The FoC PlayerWrapper object that owns the new Unit.
|
||||
function TacticalGameClass:UnitBuilt(objectType, player)
|
||||
local playerId = player.Get_ID()
|
||||
local player = self.Players[playerId]
|
||||
local playerEntry = self.Players[playerId]
|
||||
|
||||
if player then
|
||||
player:AddUnit(objectType)
|
||||
if playerEntry then
|
||||
local unit = playerEntry:AddUnit(objectType)
|
||||
|
||||
self:CombatTextUnitBuilt(unit)
|
||||
end
|
||||
end
|
||||
|
||||
---Displays unit built combat text.
|
||||
---@param unit UnitClass The built unit.
|
||||
function TacticalGameClass:CombatTextUnitBuilt(unit)
|
||||
local owner = self.Players[unit.OwnerId]
|
||||
|
||||
if not owner then
|
||||
return
|
||||
end
|
||||
|
||||
local timeText = FormatTime(unit.BuildTime)
|
||||
local text = string.format("%s\t[%s]: BUILT %s ($%d)", timeText, owner.Name, unit.Name, unit.BuildCost)
|
||||
local faction = Factions[owner.Faction]
|
||||
---@type ColorStruct
|
||||
local color
|
||||
|
||||
if faction then
|
||||
color = faction.Color
|
||||
else
|
||||
color = ColorStruct:New(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
self.CombatFeed:Append(text, -1, color)
|
||||
end
|
||||
|
||||
---Sets a unit as killed.
|
||||
---@param gameObject table The FoC GameObjectWrapper object that was killed.
|
||||
function TacticalGameClass:UnitKilled(gameObject)
|
||||
-- Find a way to set the unit as killed
|
||||
---@param gameObject GameObject The FoC GameObjectWrapper object that was killed.
|
||||
---@param killer PlayerObject The FoC PlayerWrapper object that killed the Unit.
|
||||
function TacticalGameClass:UnitKilled(gameObject, killer)
|
||||
local ownerId = gameObject.Get_Owner().Get_ID()
|
||||
local owner = self.Players[ownerId]
|
||||
|
||||
if not owner then
|
||||
return
|
||||
end
|
||||
|
||||
---@type UnitClass|nil
|
||||
local killedUnit = nil
|
||||
|
||||
for _, unit in pairs(owner.Units) do
|
||||
if unit.GameObject == gameObject then
|
||||
killedUnit = unit
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if killedUnit then
|
||||
killedUnit:SetDead(killer.Get_ID())
|
||||
self:CombatTextUnitKilled(killedUnit)
|
||||
end
|
||||
end
|
||||
|
||||
---Displays killed unit combat text.
|
||||
---@param unit UnitClass The killed unit.
|
||||
function TacticalGameClass:CombatTextUnitKilled(unit)
|
||||
local owner = self.Players[unit.OwnerId]
|
||||
|
||||
if not owner then
|
||||
return
|
||||
end
|
||||
|
||||
local killer = self.Players[unit.KillerId]
|
||||
local timeText = FormatTime(unit.DeathTime)
|
||||
|
||||
if not killer then
|
||||
local text = string.format("%s\t[%s]: MISTAKES WERE MADE %s", timeText, owner.Name, unit.Name)
|
||||
local color = ColorStruct:New(0.8, 0.8, 0.8, 1)
|
||||
|
||||
self.CombatFeed:Append(text, -1, color)
|
||||
else
|
||||
local text = string.format("%s\t[%s]: KILLED %s (%s)", timeText, killer.Name, unit.Name, owner.Name)
|
||||
local faction = Factions[killer.Faction]
|
||||
---@type ColorStruct
|
||||
local color = nil
|
||||
|
||||
if faction then
|
||||
color = faction.Color
|
||||
else
|
||||
color = ColorStruct:New(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
self.CombatFeed:Append(text, -1, color)
|
||||
end
|
||||
end
|
||||
|
||||
-- ==================================================
|
||||
-- Private functions
|
||||
-- ==================================================
|
||||
|
||||
---@private
|
||||
---@param gameMode string The current game mode.
|
||||
---@return PlayerClass[]
|
||||
function TacticalGameClass:_FindPlayers(gameMode)
|
||||
---@type PlayerClass[]
|
||||
local players = {}
|
||||
|
||||
for k, faction in pairs(Factions) do
|
||||
local startingUnit = nil
|
||||
|
||||
if StringCompare(gameMode, "Land") then
|
||||
startingUnit = faction.LandStartUnitName
|
||||
elseif StringCompare(gameMode, "Space") then
|
||||
startingUnit = faction.SpaceStartUnitName
|
||||
end
|
||||
|
||||
if startingUnit then
|
||||
for i, unit in pairs(Find_All_Objects_Of_Type(startingUnit)) do
|
||||
local playerWrapper = unit.Get_Owner()
|
||||
local playerId = playerWrapper.Get_ID()
|
||||
|
||||
if players[playerId] == nil then
|
||||
local player = PlayerClass:New(playerWrapper)
|
||||
|
||||
players[playerId] = player
|
||||
ScriptMessage("Found Player: %s", player:Debug())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return players
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ require("GameManager/TutorialTextView")
|
||||
---@field MaxLines integer Maximum number of lines to display at once.
|
||||
---@field _KeyOrder string[] Insertion-ordered list of active entry keys (oldest first).
|
||||
---@field _NextId integer Counter used to generate unique entry keys.
|
||||
TutorialTextFeed = setmetatable({}, {__index = TutorialTextView})
|
||||
TutorialTextFeed = setmetatable({}, { __index = TutorialTextView })
|
||||
TutorialTextFeed.__index = TutorialTextFeed
|
||||
|
||||
---Creates a new Tutorial Text Feed.
|
||||
@@ -16,9 +16,9 @@ TutorialTextFeed.__index = TutorialTextFeed
|
||||
---@param maxLines integer Maximum number of lines to display at once.
|
||||
---@return TutorialTextFeed
|
||||
function TutorialTextFeed:New(name, maxLines)
|
||||
local self = TutorialTextView.New(TutorialTextView, name)
|
||||
setmetatable(self, TutorialTextFeed)
|
||||
local self = setmetatable(TutorialTextView:New(name), TutorialTextFeed)
|
||||
|
||||
---@cast self TutorialTextFeed
|
||||
self.MaxLines = maxLines
|
||||
self._KeyOrder = {}
|
||||
self._NextId = 0
|
||||
@@ -33,7 +33,8 @@ end
|
||||
---@param duration number|nil Duration in seconds, defaults to -1 (infinite).
|
||||
---@param color ColorStruct|nil The text color, defaults to white.
|
||||
function TutorialTextFeed:Append(text, duration, color)
|
||||
if #self._KeyOrder >= self.MaxLines then
|
||||
---@diagnostic disable-next-line
|
||||
if table.getn(self._KeyOrder) >= self.MaxLines then
|
||||
local oldestKey = table.remove(self._KeyOrder, 1)
|
||||
self.Entries[oldestKey] = nil
|
||||
if self.IsActive then
|
||||
@@ -68,5 +69,6 @@ end
|
||||
|
||||
function TutorialTextFeed:Debug()
|
||||
return string.format("TutorialTextFeed '%s' (%d/%d lines)",
|
||||
self.Name, #self._KeyOrder, self.MaxLines)
|
||||
---@diagnostic disable-next-line
|
||||
self.Name, table.getn(self._KeyOrder), self.MaxLines)
|
||||
end
|
||||
|
||||
@@ -8,9 +8,9 @@ require("PGBase")
|
||||
---@field BuildTime number Game time that this unit was built.
|
||||
---@field AliveTime number Game time that this unit became "alive".
|
||||
---@field DeathTime number Game time that this unit was killed.
|
||||
---@field GameObjectWrapper table|nil The FoC GameObjectWrapper object.
|
||||
---@field GameObjectTypeWrapper table The FoC GameObjectTypeWrapper object.
|
||||
---@field Icon string Name of the icon for this object.
|
||||
---@field KillerId integer|nil The Player ID that killed this unit.
|
||||
---@field GameObject GameObject|nil The FoC GameObjectWrapper object.
|
||||
---@field GameObjectType GameObjectType The FoC GameObjectTypeWrapper object.
|
||||
UnitClass = {}
|
||||
UnitClass.__index = UnitClass
|
||||
|
||||
@@ -27,9 +27,9 @@ function UnitClass:New(objectType, playerId)
|
||||
self.BuildTime = GetCurrentTime()
|
||||
self.AliveTime = -1
|
||||
self.DeathTime = -1
|
||||
self.GameObjectWrapper = nil
|
||||
self.GameObjectTypeWrapper = objectType
|
||||
self.Icon = "I_BUTTON_COMMAND_BAR_PIRATE_SYMBOL.TGA"
|
||||
self.KillerId = nil
|
||||
self.GameObject = nil
|
||||
self.GameObjectType = objectType
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -61,18 +61,20 @@ function UnitClass:SetAlive(object)
|
||||
end
|
||||
|
||||
self.AliveTime = GetCurrentTime()
|
||||
self.GameObjectWrapper = object
|
||||
self.GameObject = object
|
||||
ScriptMessage("Unit Spawned: %s", self:Debug())
|
||||
end
|
||||
|
||||
---Sets the unit as dead.
|
||||
function UnitClass:SetDead()
|
||||
---@param killerId integer The Player ID that killed this unit.
|
||||
function UnitClass:SetDead(killerId)
|
||||
if self.DeathTime >= 0 then
|
||||
-- Do not override once set
|
||||
return
|
||||
end
|
||||
|
||||
self.DeathTime = GetCurrentTime()
|
||||
self.KillerId = killerId
|
||||
ScriptMessage("Unit Killed: %s", self:Debug())
|
||||
end
|
||||
|
||||
|
||||
20
Data/Scripts/Miscellaneous/GameManager/Utilities.lua
Normal file
20
Data/Scripts/Miscellaneous/GameManager/Utilities.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
---Formats the game time in seconds to MM:SS.
|
||||
---@param gameTime number The game time in seconds.
|
||||
---@return string
|
||||
function FormatTime(gameTime)
|
||||
local minutes = Dirty_Floor(gameTime / 60)
|
||||
local minutesText = tostring(minutes)
|
||||
|
||||
if tonumber(minutes) < 10 then
|
||||
minutesText = "0" .. minutesText
|
||||
end
|
||||
|
||||
local seconds = Dirty_Floor(gameTime - (minutes * 60))
|
||||
local secondsText = tostring(seconds)
|
||||
|
||||
if tonumber(seconds) < 10 then
|
||||
secondsText = "0" .. secondsText
|
||||
end
|
||||
|
||||
return string.format("%s:%s", minutesText, secondsText)
|
||||
end
|
||||
Reference in New Issue
Block a user