408 lines
12 KiB
Lua
408 lines
12 KiB
Lua
require("GameManager/TacticalGameClass")
|
|
require("GameManager/SpectatorStruct")
|
|
require("GameManager/TeamStruct")
|
|
|
|
---@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(TacticalGameClass:New(gameMode), SkirmishGameClass)
|
|
|
|
---@cast self SkirmishGameClass
|
|
self:_FindSpectators()
|
|
self.IsLocalSpectator = self:_GetLocalSpectator()
|
|
self:_BuildTeams()
|
|
ScriptMessage("Skirmish Game initialized!")
|
|
|
|
return self
|
|
end
|
|
|
|
---Services the Skirmish Game.
|
|
function SkirmishGameClass:Service()
|
|
-- Service TacticalGame
|
|
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)
|
|
if not self.IsLocalSpectator then
|
|
-- No Text feed for combatants
|
|
return
|
|
end
|
|
|
|
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%d> [%s]: BUILT %s ($ %d)", timeText, team.Number, owner.Faction, unit.DisplayName,
|
|
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)
|
|
-- Right now, we don't really care about seeing killed units in the combat feed
|
|
-- If we want it in the future, uncomment the lines below.
|
|
return
|
|
-- if not self.IsLocalSpectator then
|
|
-- -- No Text feed for combatants
|
|
-- return
|
|
-- end
|
|
|
|
-- 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.DisplayName)
|
|
-- 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
|
|
-- .DisplayName,
|
|
-- 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)
|
|
return self.Spectators[id]
|
|
end
|
|
|
|
---Gets the Team by ID.
|
|
---@param id integer Team ID
|
|
---@return TeamStruct|nil
|
|
function SkirmishGameClass:GetTeam(id)
|
|
return self.Teams[id]
|
|
end
|
|
|
|
---Gets the Team of the Player ID.
|
|
---@param id integer Player ID.
|
|
---@return TeamStruct|nil
|
|
function SkirmishGameClass:GetTeamForPlayer(id)
|
|
local player = self.Players[id]
|
|
|
|
if not player then
|
|
return nil
|
|
end
|
|
|
|
return self.Teams[player.TeamId]
|
|
end
|
|
|
|
---Gets the Players for the Team ID.
|
|
---@param id integer Team ID
|
|
---@return PlayerClass[]
|
|
function SkirmishGameClass:GetPlayersOnTeam(id)
|
|
---@type PlayerClass[]
|
|
local players = {}
|
|
|
|
for playerId, player in pairs(self.Players) do
|
|
if player.TeamId == id then
|
|
players[playerId] = player
|
|
end
|
|
end
|
|
|
|
return players
|
|
end
|
|
|
|
-- ==================================================
|
|
-- Team functions
|
|
-- ==================================================
|
|
|
|
---Calculates the Team ID's current total credits.
|
|
---@param id integer Team ID.
|
|
---@return integer
|
|
function SkirmishGameClass:CalculateTeamTotalCredits(id)
|
|
local players = self:GetPlayersOnTeam(id)
|
|
local totalCredits = 0
|
|
|
|
for playerId, player in pairs(players) do
|
|
totalCredits = totalCredits + player.Resource.Credits
|
|
end
|
|
|
|
return totalCredits
|
|
end
|
|
|
|
---Calculates the Team ID's current total income.
|
|
---@param id integer Team ID.
|
|
---@return integer
|
|
function SkirmishGameClass:CalculateTeamTotalIncome(id)
|
|
local players = self:GetPlayersOnTeam(id)
|
|
local totalIncome = 0
|
|
|
|
for playerId, player in pairs(players) do
|
|
totalIncome = totalIncome + player.Resource.Income
|
|
end
|
|
|
|
return totalIncome
|
|
end
|
|
|
|
--- ==================================================
|
|
--- Stat tables
|
|
--- ==================================================
|
|
|
|
---Updates the Tactical Kill Stats Table with the killed object.
|
|
---@param unit UnitClass The object that was killed.
|
|
---@param killer PlayerObject The player that killed the object.
|
|
function SkirmishGameClass:UpdateTacticalKillStatsTable(unit, killer)
|
|
if not TestValid(killer) then
|
|
return
|
|
end
|
|
|
|
-- Update Frags
|
|
local fragEntry = self.KillStatsTable[FragIndex]
|
|
|
|
if not fragEntry then
|
|
fragEntry = {}
|
|
self.KillStatsTable[FragIndex] = fragEntry
|
|
end
|
|
|
|
local killerId = killer.Get_ID()
|
|
|
|
if self.IsLocalSpectator then
|
|
local killerTeam = self:GetTeamForPlayer(killerId)
|
|
|
|
if killerTeam and killerTeam.Number == 1 then
|
|
-- For the spectator, let's show Team 1's kills on the left side
|
|
killerId = LocalPlayer.Get_ID()
|
|
end
|
|
end
|
|
|
|
local killerEntry = fragEntry[killerId]
|
|
|
|
if not killerEntry then
|
|
killerEntry = {}
|
|
fragEntry[killerId] = killerEntry
|
|
end
|
|
|
|
local killerObjEntry = killerEntry[unit.GameObjectType]
|
|
|
|
if not killerObjEntry then
|
|
killerObjEntry = {
|
|
kills = 1,
|
|
combat_power = unit.CombatRating,
|
|
build_cost = unit.BuildCost,
|
|
score_value = unit.ScoreValue
|
|
}
|
|
killerEntry[unit.GameObjectType] = killerObjEntry
|
|
else
|
|
killerObjEntry.kills = killerObjEntry.kills + 1
|
|
killerObjEntry.combat_power = killerObjEntry.combat_power + unit.CombatRating
|
|
killerObjEntry.build_cost = killerObjEntry.build_cost + unit.BuildCost
|
|
killerObjEntry.score_value = killerObjEntry.score_value + unit.ScoreValue
|
|
end
|
|
|
|
-- Update Deaths
|
|
local deathEntry = self.KillStatsTable[DeathIndex]
|
|
|
|
if not deathEntry then
|
|
deathEntry = {}
|
|
self.KillStatsTable[DeathIndex] = deathEntry
|
|
end
|
|
|
|
local ownerId = unit.OwnerId
|
|
|
|
if self.IsLocalSpectator then
|
|
local ownerTeam = self:GetTeamForPlayer(ownerId)
|
|
|
|
if ownerTeam and ownerTeam.Number == 1 then
|
|
-- For the spectator, let's show Team 1's lost units on the left side
|
|
ownerId = LocalPlayer.Get_ID()
|
|
end
|
|
else
|
|
-- Non-spectator: show all teammate deaths as local player's losses
|
|
local ownerTeam = self:GetTeamForPlayer(ownerId)
|
|
local localTeam = self:GetTeamForPlayer(LocalPlayer.Get_ID())
|
|
|
|
if ownerTeam and localTeam and ownerTeam.Id == localTeam.Id then
|
|
ownerId = LocalPlayer.Get_ID()
|
|
end
|
|
end
|
|
|
|
local ownerEntry = deathEntry[ownerId]
|
|
|
|
if not ownerEntry then
|
|
ownerEntry = {}
|
|
deathEntry[ownerId] = ownerEntry
|
|
end
|
|
|
|
local ownerObjEntry = ownerEntry[unit.GameObjectType]
|
|
|
|
if not ownerObjEntry then
|
|
ownerObjEntry = {
|
|
kills = 1,
|
|
combat_power = unit.CombatRating,
|
|
build_cost = unit.BuildCost,
|
|
score_value = unit.ScoreValue
|
|
}
|
|
ownerEntry[unit.GameObjectType] = ownerObjEntry
|
|
else
|
|
ownerObjEntry.kills = ownerObjEntry.kills + 1
|
|
ownerObjEntry.combat_power = ownerObjEntry.combat_power + unit.CombatRating
|
|
ownerObjEntry.build_cost = ownerObjEntry.build_cost + unit.BuildCost
|
|
ownerObjEntry.score_value = ownerObjEntry.score_value + unit.ScoreValue
|
|
end
|
|
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
|