1
0
Fork 0

Basic scoreboard implementation

This commit is contained in:
andrew 2014-01-19 14:20:57 +02:00
parent 972585363d
commit 2b94361059
5 changed files with 576 additions and 1 deletions

View File

@ -74,6 +74,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_IsChargingBow(false)
, m_BowCharge(0)
, m_FloaterID(-1)
, m_Team(NULL)
{
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
@ -790,6 +791,20 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
return;
}
}
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
{
cPlayer* Attacker = (cPlayer*) a_TDI.Attacker;
if ((m_Team != NULL) && (m_Team == Attacker->m_Team))
{
if (!m_Team->GetFriendlyFire())
{
// Friendly fire is disabled
return;
}
}
}
super::DoTakeDamage(a_TDI);
@ -836,6 +851,24 @@ void cPlayer::KilledBy(cEntity * a_Killer)
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by a %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), KillerClass.c_str()));
}
class cIncrementCounterCB
: public cObjectiveCallback
{
AString m_Name;
public:
cIncrementCounterCB(const AString & a_Name) : m_Name(a_Name) {}
virtual bool Item(cObjective * a_Objective) override
{
a_Objective->AddScore(m_Name, 1);
}
} IncrementCounter (GetName());
cScoreboard* Scoreboard = m_World->GetScoreBoard();
// Update scoreboard objectives
Scoreboard->ForEachObjectiveWith(E_OBJECTIVE_DEATH_COUNT, IncrementCounter);
}
@ -916,6 +949,25 @@ bool cPlayer::IsGameModeAdventure(void) const
void cPlayer::SetTeam(cTeam* a_Team)
{
if (m_Team)
{
m_Team->RemovePlayer(this);
}
m_Team = a_Team;
if (m_Team)
{
m_Team->AddPlayer(this);
}
}
void cPlayer::OpenWindow(cWindow * a_Window)
{
if (a_Window != m_CurrentWindow)

View File

@ -13,6 +13,7 @@
class cGroup;
class cWindow;
class cClientHandle;
class cTeam;
@ -153,6 +154,12 @@ public:
AString GetIP(void) const { return m_IP; } // tolua_export
/// Returns the associated team, NULL if none
cTeam* GetTeam(void) { return m_Team; } // tolua_export
/// Sets the player team, NULL if none
void SetTeam(cTeam* a_Team);
// tolua_end
void SetIP(const AString & a_IP);
@ -456,6 +463,8 @@ protected:
int m_FloaterID;
cTeam* m_Team;
void ResolvePermissions(void);
@ -463,7 +472,7 @@ protected:
virtual void Destroyed(void);
/// Filters out damage for creative mode
/// Filters out damage for creative mode/friendly fire
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
/// Called in each tick to handle food-related processing

301
src/Scoreboard.cpp Normal file
View File

@ -0,0 +1,301 @@
// Scoreboard.cpp
// Implementation of a scoreboard that keeps track of specified objectives
#include "Globals.h"
#include "Scoreboard.h"
cObjective::cObjective(eObjectiveType a_Type) : m_Type(a_Type)
{}
void cObjective::SetDisplaySlot(eDisplaySlot a_Display)
{
m_Display = a_Display;
}
void cObjective::Reset(void)
{
m_Scores.clear();
}
cObjective::Score cObjective::GetScore(const AString & a_Name) const
{
ScoreMap::const_iterator it = m_Scores.find(a_Name);
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;
}
void cObjective::ResetScore(const AString & a_Name)
{
m_Scores.erase(a_Name);
}
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;
m_Scores[a_Name] = NewScore;
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;
m_Scores[a_Name] = NewScore;
return NewScore;
}
cTeam::cTeam(const AString & a_Name, const AString & a_DisplayName,
const AString & a_Prefix, const AString & a_Suffix)
: m_FriendlyFire(true)
, m_SeeFriendlyInvisible(false)
, m_Name(a_Name)
, m_DisplayName(a_DisplayName)
, m_Prefix(a_Prefix)
, m_Suffix(a_Suffix)
{}
bool cTeam::AddPlayer(cPlayer * a_Player)
{
return m_Players.insert(a_Player).second;
}
bool cTeam::RemovePlayer(cPlayer * a_Player)
{
return m_Players.erase(a_Player) > 0;
}
void cTeam::Reset(void)
{
m_Players.clear();
}
unsigned int cTeam::GetNumPlayers(void) const
{
return m_Players.size();
}
cScoreboard::~cScoreboard()
{
for (ObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
{
delete it->second;
}
for (TeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
{
delete it->second;
}
}
cObjective* cScoreboard::RegisterObjective(const AString & a_Name, eObjectiveType a_Type)
{
cObjective* Objective = new cObjective(a_Type);
bool Status = m_Objectives.insert(NamedObjective(a_Name, Objective)).second;
if (Status)
{
return Objective;
}
else
{
delete Objective;
return NULL;
}
}
bool cScoreboard::RemoveObjective(const AString & a_Name)
{
ObjectiveMap::iterator it = m_Objectives.find(a_Name);
if (it == m_Objectives.end())
{
return false;
}
m_Objectives.erase(it);
return true;
}
cObjective* cScoreboard::GetObjective(const AString & a_Name)
{
ObjectiveMap::iterator it = m_Objectives.find(a_Name);
if (it == m_Objectives.end())
{
return NULL;
}
else
{
return it->second;
}
}
cTeam* cScoreboard::RegisterTeam(const AString & a_Name, const AString & a_DisplayName,
const AString & a_Prefix, const AString & a_Suffix)
{
cTeam* Team = new cTeam(a_Name, a_DisplayName, a_Prefix, a_Suffix);
bool Status = m_Teams.insert(NamedTeam(a_Name, Team)).second;
if (Status)
{
return Team;
}
else
{
delete Team;
return NULL;
}
}
bool cScoreboard::RemoveTeam(const AString & a_Name)
{
TeamMap::iterator it = m_Teams.find(a_Name);
if (it == m_Teams.end())
{
return false;
}
m_Teams.erase(it);
return true;
}
cTeam* cScoreboard::GetTeam(const AString & a_Name)
{
TeamMap::iterator it = m_Teams.find(a_Name);
if (it == m_Teams.end())
{
return NULL;
}
else
{
return it->second;
}
}
void cScoreboard::ForEachObjectiveWith(eObjectiveType a_Type, cObjectiveCallback& a_Callback)
{
for (ObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
{
if (it->second->GetType() == a_Type)
{
// Call callback
if (a_Callback.Item(it->second))
{
return;
}
}
}
}

207
src/Scoreboard.h Normal file
View File

@ -0,0 +1,207 @@
// Scoreboard.h
// Implementation of a scoreboard that keeps track of specified objectives
#pragma once
class cPlayer;
class cObjective;
typedef std::set< cPlayer * > cPlayerSet;
typedef cItemCallback<cObjective> cObjectiveCallback;
enum eObjectiveType
{
E_OBJECTIVE_DUMMY,
E_OBJECTIVE_DEATH_COUNT,
E_OBJECTIVE_PLAYER_KILL_COUNT,
E_OBJECTIVE_TOTAL_KILL_COUNT,
E_OBJECTIVE_HEALTH,
E_OBJECTIVE_ACHIEVEMENT,
E_OBJECTIVE_STAT,
E_OBJECTIVE_STAT_ITEM_CRAFT,
E_OBJECTIVE_STAT_ITEM_USE,
E_OBJECTIVE_STAT_ITEM_BREAK,
E_OBJECTIVE_STAT_BLOCK_MINE,
E_OBJECTIVE_STAT_ENTITY_KILL,
E_OBJECTIVE_STAT_ENTITY_KILLED_BY
};
enum eDisplaySlot
{
E_DISPLAY_SLOT_LIST,
E_DISPLAY_SLOT_SIDEBAR,
E_DISPLAY_SLOT_NAME
};
class cObjective
{
public:
typedef int Score;
public:
cObjective(eObjectiveType a_Type);
eObjectiveType GetType(void) const { return m_Type; }
eDisplaySlot GetDisplaySlot(void) const { return m_Display; }
void SetDisplaySlot(eDisplaySlot a_Display);
/// Resets the objective
void Reset(void);
/// Returns the score of the specified player
Score GetScore(const AString & a_Name) const;
/// Sets the score of the specified player
void SetScore(const AString & a_Name, Score a_Score);
/// Resets the score of the specified player
void ResetScore(const AString & a_Name);
/// Adds a_Delta and returns the new score
Score AddScore(const AString & a_Name, Score a_Delta);
/// Subtracts a_Delta and returns the new score
Score SubScore(const AString & a_Name, Score a_Delta);
private:
typedef std::pair<AString, Score> TrackedPlayer;
typedef std::map<AString, Score> ScoreMap;
ScoreMap m_Scores;
eObjectiveType m_Type;
eDisplaySlot m_Display;
};
class cTeam
{
public:
cTeam(const AString & a_Name, const AString & a_DisplayName,
const AString & a_Prefix, const AString & a_Suffix);
/// Adds a new player to the team
bool AddPlayer(cPlayer * a_Player);
/// Removes a player from the team
bool RemovePlayer(cPlayer * a_Player);
/// Removes all registered players
void Reset(void);
/// Returns the number of registered players
unsigned int GetNumPlayers(void) const;
bool GetFriendlyFire(void) const { return m_FriendlyFire; }
bool GetCanSeeFriendlyInvisible(void) const { return m_SeeFriendlyInvisible; }
const AString & GetDisplayName(void) const { return m_Name; }
const AString & GetName(void) const { return m_DisplayName; }
const AString & GetPrefix(void) const { return m_Prefix; }
const AString & GetSuffix(void) const { return m_Suffix; }
void SetFriendlyFire(bool a_Flag);
void SetCanSeeFriendlyInvisible(bool a_Flag);
void SetDisplayName(const AString & a_Name);
void SetPrefix(const AString & a_Prefix);
void SetSuffix(const AString & a_Suffix);
private:
bool m_FriendlyFire;
bool m_SeeFriendlyInvisible;
AString m_DisplayName;
AString m_Name;
AString m_Prefix;
AString m_Suffix;
// TODO 2014-01-19 xdot: Potential optimization - vector/list
cPlayerSet m_Players;
};
class cScoreboard
{
public:
cScoreboard() {}
virtual ~cScoreboard();
/// Registers a new scoreboard objective, returns the cObjective instance
cObjective* RegisterObjective(const AString & a_Name, eObjectiveType a_Type);
/// Removes a registered objective, returns true if operation was successful
bool RemoveObjective(const AString & a_Name);
/// Retrieves the objective with the specified name, NULL if not found
cObjective* GetObjective(const AString & a_Name);
/// Registers a new team, returns the cTeam instance
cTeam* RegisterTeam(const AString & a_Name, const AString & a_DisplayName,
const AString & a_Prefix, const AString & a_Suffix);
/// Removes a registered team, returns true if operation was successful
bool RemoveTeam(const AString & a_Name);
/// Retrieves the team with the specified name, NULL if not found
cTeam* GetTeam(const AString & a_Name);
/// Execute callback for each objective with the specified type
void ForEachObjectiveWith(eObjectiveType a_Type, cObjectiveCallback& a_Callback);
private:
typedef std::pair<AString, cObjective*> NamedObjective;
typedef std::pair<AString, cTeam*> NamedTeam;
typedef std::map<AString, cObjective*> ObjectiveMap;
typedef std::map<AString, cTeam*> TeamMap;
// TODO 2014-01-19 xdot: Potential optimization - Sort objectives based on type
ObjectiveMap m_Objectives;
TeamMap m_Teams;
} ;

View File

@ -22,6 +22,7 @@
#include "Item.h"
#include "Mobs/Monster.h"
#include "Entities/ProjectileEntity.h"
#include "Scoreboard.h"
@ -513,6 +514,9 @@ public:
/// Returns the name of the world.ini file used by this world
const AString & GetIniFileName(void) const {return m_IniFileName; }
/// Returns the associated scoreboard instance
cScoreboard* GetScoreBoard(void) { return &m_Scoreboard; }
// tolua_end
@ -757,6 +761,8 @@ private:
sSetBlockList m_FastSetBlockQueue;
cChunkGenerator m_Generator;
cScoreboard m_Scoreboard;
/** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
cChunkGeneratorCallbacks m_GeneratorCallbacks;