summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Entities/Player.cpp52
-rw-r--r--src/Entities/Player.h11
-rw-r--r--src/Scoreboard.cpp301
-rw-r--r--src/Scoreboard.h207
-rw-r--r--src/World.h6
5 files changed, 576 insertions, 1 deletions
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index c1f2456eb..4f3c6138b 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -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)
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index bf3ca08e8..52e629dc3 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -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
diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp
new file mode 100644
index 000000000..1d2711ca0
--- /dev/null
+++ b/src/Scoreboard.cpp
@@ -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;
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/src/Scoreboard.h b/src/Scoreboard.h
new file mode 100644
index 000000000..8ab298a07
--- /dev/null
+++ b/src/Scoreboard.h
@@ -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;
+} ;
+
+
+
+
diff --git a/src/World.h b/src/World.h
index 1a7ad0cb1..1dcbac8e4 100644
--- a/src/World.h
+++ b/src/World.h
@@ -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;