2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
// Scoreboard.cpp
|
|
|
|
|
|
|
|
// Implementation of a scoreboard that keeps track of specified objectives
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
|
|
|
|
#include "Scoreboard.h"
|
2014-01-21 08:58:17 -05:00
|
|
|
#include "World.h"
|
2014-01-21 12:43:13 -05:00
|
|
|
#include "ClientHandle.h"
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
AString cObjective::TypeToString(eType a_Type)
|
|
|
|
{
|
|
|
|
switch (a_Type)
|
|
|
|
{
|
|
|
|
case E_TYPE_DUMMY: return "dummy";
|
|
|
|
case E_TYPE_DEATH_COUNT: return "deathCount";
|
|
|
|
case E_TYPE_PLAYER_KILL_COUNT: return "playerKillCount";
|
|
|
|
case E_TYPE_TOTAL_KILL_COUNT: return "totalKillCount";
|
|
|
|
case E_TYPE_HEALTH: return "health";
|
|
|
|
case E_TYPE_ACHIEVEMENT: return "achievement";
|
|
|
|
case E_TYPE_STAT: return "stat";
|
|
|
|
case E_TYPE_STAT_ITEM_CRAFT: return "stat.craftItem";
|
|
|
|
case E_TYPE_STAT_ITEM_USE: return "stat.useItem";
|
|
|
|
case E_TYPE_STAT_ITEM_BREAK: return "stat.breakItem";
|
|
|
|
case E_TYPE_STAT_BLOCK_MINE: return "stat.mineBlock";
|
|
|
|
case E_TYPE_STAT_ENTITY_KILL: return "stat.killEntity";
|
|
|
|
case E_TYPE_STAT_ENTITY_KILLED_BY: return "stat.entityKilledBy";
|
|
|
|
|
|
|
|
default: return "";
|
|
|
|
}
|
|
|
|
}
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cObjective::eType cObjective::StringToType(const AString & a_Name)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-20 09:10:39 -05:00
|
|
|
static struct {
|
|
|
|
eType m_Type;
|
|
|
|
const char * m_String;
|
|
|
|
} TypeMap [] =
|
|
|
|
{
|
|
|
|
{E_TYPE_DUMMY, "dummy"},
|
|
|
|
{E_TYPE_DEATH_COUNT, "deathCount"},
|
|
|
|
{E_TYPE_PLAYER_KILL_COUNT, "playerKillCount"},
|
|
|
|
{E_TYPE_TOTAL_KILL_COUNT, "totalKillCount"},
|
|
|
|
{E_TYPE_HEALTH, "health"},
|
|
|
|
{E_TYPE_ACHIEVEMENT, "achievement"},
|
|
|
|
{E_TYPE_STAT, "stat"},
|
|
|
|
{E_TYPE_STAT_ITEM_CRAFT, "stat.craftItem"},
|
|
|
|
{E_TYPE_STAT_ITEM_USE, "stat.useItem"},
|
|
|
|
{E_TYPE_STAT_ITEM_BREAK, "stat.breakItem"},
|
|
|
|
{E_TYPE_STAT_BLOCK_MINE, "stat.mineBlock"},
|
|
|
|
{E_TYPE_STAT_ENTITY_KILL, "stat.killEntity"},
|
|
|
|
{E_TYPE_STAT_ENTITY_KILLED_BY, "stat.entityKilledBy"}
|
|
|
|
};
|
|
|
|
for (size_t i = 0; i < ARRAYCOUNT(TypeMap); i++)
|
|
|
|
{
|
|
|
|
if (NoCaseCompare(TypeMap[i].m_String, a_Name) == 0)
|
|
|
|
{
|
|
|
|
return TypeMap[i].m_Type;
|
|
|
|
}
|
|
|
|
} // for i - TypeMap[]
|
|
|
|
return E_TYPE_DUMMY;
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-21 08:58:17 -05:00
|
|
|
cObjective::cObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type, cWorld * a_World)
|
2014-01-20 09:45:40 -05:00
|
|
|
: m_DisplayName(a_DisplayName)
|
|
|
|
, m_Name(a_Name)
|
|
|
|
, m_Type(a_Type)
|
2014-01-21 08:58:17 -05:00
|
|
|
, m_World(a_World)
|
|
|
|
{
|
|
|
|
}
|
2014-01-20 09:10:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-19 07:20:57 -05:00
|
|
|
void cObjective::Reset(void)
|
|
|
|
{
|
2014-01-21 08:58:17 -05:00
|
|
|
for (cScoreMap::iterator it = m_Scores.begin(); it != m_Scores.end(); ++it)
|
|
|
|
{
|
|
|
|
m_World->BroadcastScoreUpdate(m_Name, it->first, 0, 1);
|
|
|
|
}
|
|
|
|
|
2014-01-19 07:20:57 -05:00
|
|
|
m_Scores.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cObjective::Score cObjective::GetScore(const AString & a_Name) const
|
|
|
|
{
|
2014-01-20 09:45:40 -05:00
|
|
|
cScoreMap::const_iterator it = m_Scores.find(a_Name);
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
if (it == m_Scores.end())
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cObjective::SetScore(const AString & a_Name, cObjective::Score a_Score)
|
|
|
|
{
|
|
|
|
m_Scores[a_Name] = a_Score;
|
2014-01-21 08:58:17 -05:00
|
|
|
|
|
|
|
m_World->BroadcastScoreUpdate(m_Name, a_Name, a_Score, 0);
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cObjective::ResetScore(const AString & a_Name)
|
|
|
|
{
|
|
|
|
m_Scores.erase(a_Name);
|
2014-01-21 08:58:17 -05:00
|
|
|
|
|
|
|
m_World->BroadcastScoreUpdate(m_Name, a_Name, 0, 1);
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cObjective::Score cObjective::AddScore(const AString & a_Name, cObjective::Score a_Delta)
|
|
|
|
{
|
|
|
|
// TODO 2014-01-19 xdot: Potential optimization - Reuse iterator
|
|
|
|
Score NewScore = m_Scores[a_Name] + a_Delta;
|
|
|
|
|
2014-01-21 08:58:17 -05:00
|
|
|
SetScore(a_Name, NewScore);
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
return NewScore;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cObjective::Score cObjective::SubScore(const AString & a_Name, cObjective::Score a_Delta)
|
|
|
|
{
|
|
|
|
// TODO 2014-01-19 xdot: Potential optimization - Reuse iterator
|
|
|
|
Score NewScore = m_Scores[a_Name] - a_Delta;
|
|
|
|
|
2014-01-21 08:58:17 -05:00
|
|
|
SetScore(a_Name, NewScore);
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
return NewScore;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-21 08:58:17 -05:00
|
|
|
void cObjective::SetDisplayName(const AString & a_Name)
|
|
|
|
{
|
|
|
|
m_DisplayName = a_Name;
|
|
|
|
|
|
|
|
m_World->BroadcastScoreboardObjective(m_Name, m_DisplayName, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-21 12:43:13 -05:00
|
|
|
void cObjective::SendTo(cClientHandle & a_Client)
|
|
|
|
{
|
|
|
|
a_Client.SendScoreboardObjective(m_Name, m_DisplayName, 0);
|
|
|
|
|
|
|
|
for (cScoreMap::const_iterator it = m_Scores.begin(); it != m_Scores.end(); ++it)
|
|
|
|
{
|
|
|
|
a_Client.SendScoreUpdate(m_Name, it->first, it->second, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-19 07:20:57 -05:00
|
|
|
cTeam::cTeam(const AString & a_Name, const AString & a_DisplayName,
|
|
|
|
const AString & a_Prefix, const AString & a_Suffix)
|
2014-01-19 09:02:37 -05:00
|
|
|
: m_AllowsFriendlyFire(true)
|
|
|
|
, m_CanSeeFriendlyInvisible(false)
|
2014-01-19 07:20:57 -05:00
|
|
|
, m_DisplayName(a_DisplayName)
|
2014-02-05 12:43:49 -05:00
|
|
|
, m_Name(a_Name)
|
2014-01-19 07:20:57 -05:00
|
|
|
, m_Prefix(a_Prefix)
|
|
|
|
, m_Suffix(a_Suffix)
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-19 09:02:37 -05:00
|
|
|
bool cTeam::AddPlayer(const AString & a_Name)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-19 09:02:37 -05:00
|
|
|
return m_Players.insert(a_Name).second;
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-19 09:02:37 -05:00
|
|
|
bool cTeam::RemovePlayer(const AString & a_Name)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-19 09:02:37 -05:00
|
|
|
return m_Players.erase(a_Name) > 0;
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
bool cTeam::HasPlayer(const AString & a_Name) const
|
|
|
|
{
|
|
|
|
cPlayerNameSet::const_iterator it = m_Players.find(a_Name);
|
|
|
|
|
|
|
|
return it != m_Players.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-19 07:20:57 -05:00
|
|
|
void cTeam::Reset(void)
|
|
|
|
{
|
2014-01-22 08:49:21 -05:00
|
|
|
// TODO 2014-01-22 xdot: Inform online players
|
|
|
|
|
2014-01-19 07:20:57 -05:00
|
|
|
m_Players.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int cTeam::GetNumPlayers(void) const
|
|
|
|
{
|
|
|
|
return m_Players.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-21 08:58:17 -05:00
|
|
|
cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-20 09:10:39 -05:00
|
|
|
for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i)
|
|
|
|
{
|
|
|
|
m_Display[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-19 07:20:57 -05:00
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
|
|
|
|
cObjective* cScoreboard::RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type)
|
|
|
|
{
|
2014-01-21 08:58:17 -05:00
|
|
|
cObjective Objective(a_Name, a_DisplayName, a_Type, m_World);
|
2014-01-20 09:10:39 -05:00
|
|
|
|
|
|
|
std::pair<cObjectiveMap::iterator, bool> Status = m_Objectives.insert(cNamedObjective(a_Name, Objective));
|
2014-01-19 07:20:57 -05:00
|
|
|
|
2014-01-21 08:58:17 -05:00
|
|
|
if (Status.second)
|
|
|
|
{
|
|
|
|
ASSERT(m_World != NULL);
|
|
|
|
m_World->BroadcastScoreboardObjective(a_Name, a_DisplayName, 0);
|
|
|
|
|
|
|
|
return &Status.first->second;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cScoreboard::RemoveObjective(const AString & a_Name)
|
|
|
|
{
|
2014-01-21 08:58:17 -05:00
|
|
|
cCSLock Lock(m_CSObjectives);
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cObjectiveMap::iterator it = m_Objectives.find(a_Name);
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
if (it == m_Objectives.end())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Objectives.erase(it);
|
|
|
|
|
2014-01-21 08:58:17 -05:00
|
|
|
ASSERT(m_World != NULL);
|
|
|
|
m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1);
|
|
|
|
|
2014-01-19 07:20:57 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cObjective * cScoreboard::GetObjective(const AString & a_Name)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-21 08:58:17 -05:00
|
|
|
cCSLock Lock(m_CSObjectives);
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cObjectiveMap::iterator it = m_Objectives.find(a_Name);
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
if (it == m_Objectives.end())
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-01-19 09:02:37 -05:00
|
|
|
return &it->second;
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cTeam * cScoreboard::RegisterTeam(
|
2014-01-19 09:02:37 -05:00
|
|
|
const AString & a_Name, const AString & a_DisplayName,
|
|
|
|
const AString & a_Prefix, const AString & a_Suffix
|
|
|
|
)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-19 09:02:37 -05:00
|
|
|
cTeam Team(a_Name, a_DisplayName, a_Prefix, a_Suffix);
|
2014-01-19 07:20:57 -05:00
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
std::pair<cTeamMap::iterator, bool> Status = m_Teams.insert(cNamedTeam(a_Name, Team));
|
2014-01-19 07:20:57 -05:00
|
|
|
|
2014-01-19 09:02:37 -05:00
|
|
|
return Status.second ? &Status.first->second : NULL;
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cScoreboard::RemoveTeam(const AString & a_Name)
|
|
|
|
{
|
2014-01-21 08:58:17 -05:00
|
|
|
cCSLock Lock(m_CSTeams);
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cTeamMap::iterator it = m_Teams.find(a_Name);
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
if (it == m_Teams.end())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Teams.erase(it);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cTeam * cScoreboard::GetTeam(const AString & a_Name)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-21 08:58:17 -05:00
|
|
|
cCSLock Lock(m_CSTeams);
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cTeamMap::iterator it = m_Teams.find(a_Name);
|
2014-01-19 07:20:57 -05:00
|
|
|
|
|
|
|
if (it == m_Teams.end())
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-01-19 09:02:37 -05:00
|
|
|
return &it->second;
|
2014-01-19 07:20:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
cTeam * cScoreboard::QueryPlayerTeam(const AString & a_Name)
|
|
|
|
{
|
2014-01-21 08:58:17 -05:00
|
|
|
cCSLock Lock(m_CSTeams);
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it->second.HasPlayer(a_Name))
|
|
|
|
{
|
|
|
|
return &it->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot)
|
|
|
|
{
|
|
|
|
ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT);
|
|
|
|
|
|
|
|
cObjective * Objective = GetObjective(a_Objective);
|
|
|
|
|
2014-01-21 12:43:13 -05:00
|
|
|
SetDisplay(Objective, a_Slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cScoreboard::SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot)
|
|
|
|
{
|
|
|
|
m_Display[a_Slot] = a_Objective;
|
2014-01-21 08:58:17 -05:00
|
|
|
|
|
|
|
ASSERT(m_World != NULL);
|
2014-01-21 12:43:13 -05:00
|
|
|
m_World->BroadcastDisplayObjective(a_Objective ? a_Objective->GetName() : "", a_Slot);
|
2014-01-20 09:10:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:45:40 -05:00
|
|
|
cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot)
|
2014-01-20 09:10:39 -05:00
|
|
|
{
|
|
|
|
ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT);
|
|
|
|
|
|
|
|
return m_Display[a_Slot];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-19 09:02:37 -05:00
|
|
|
void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-21 08:58:17 -05:00
|
|
|
cCSLock Lock(m_CSObjectives);
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
2014-01-19 09:02:37 -05:00
|
|
|
if (it->second.GetType() == a_Type)
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
|
|
|
// Call callback
|
2014-01-19 09:02:37 -05:00
|
|
|
if (a_Callback.Item(&it->second))
|
2014-01-19 07:20:57 -05:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
|
2014-01-21 12:43:13 -05:00
|
|
|
void cScoreboard::SendTo(cClientHandle & a_Client)
|
|
|
|
{
|
|
|
|
cCSLock Lock(m_CSObjectives);
|
|
|
|
|
|
|
|
for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
|
|
|
|
{
|
|
|
|
it->second.SendTo(a_Client);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i)
|
|
|
|
{
|
|
|
|
// Avoid race conditions
|
|
|
|
cObjective * Objective = m_Display[i];
|
|
|
|
|
|
|
|
if (Objective)
|
|
|
|
{
|
|
|
|
a_Client.SendDisplayObjective(Objective->GetName(), (eDisplaySlot) i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-20 09:10:39 -05:00
|
|
|
unsigned int cScoreboard::GetNumObjectives(void) const
|
|
|
|
{
|
|
|
|
return m_Objectives.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int cScoreboard::GetNumTeams(void) const
|
|
|
|
{
|
|
|
|
return m_Teams.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-01-22 08:49:21 -05:00
|
|
|
|