about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/base/math.h7
-rw-r--r--src/engine/server.h7
-rw-r--r--src/engine/server/server.cpp186
-rw-r--r--src/engine/server/server.h31
-rw-r--r--src/game/server/entities/character.cpp5
-rw-r--r--src/game/server/entities/character.h3
-rw-r--r--src/game/server/gamecontext.cpp55
-rw-r--r--src/game/server/gamemodes/zcatch.cpp80
-rw-r--r--src/game/server/player.h2
9 files changed, 346 insertions, 30 deletions
diff --git a/src/base/math.h b/src/base/math.h
index d58dbf10..1728870b 100644
--- a/src/base/math.h
+++ b/src/base/math.h
@@ -67,4 +67,11 @@ template <typename T> inline T min(T a, T b) { return a<b?a:b; }
 template <typename T> inline T max(T a, T b) { return a>b?a:b; }
 template <typename T> inline T absolute(T a) { return a<T(0)?-a:a; }
 
+inline int lcm(int a, int b)
+{
+	if(a == 0 || b == 0)
+		return -1;
+	return absolute(a * (b / gcd(a, b)));
+}
+
 #endif // BASE_MATH_H
diff --git a/src/engine/server.h b/src/engine/server.h
index 8fe50886..e250df88 100644
--- a/src/engine/server.h
+++ b/src/engine/server.h
@@ -6,6 +6,8 @@
 #include "kernel.h"
 #include "message.h"
 
+#include <string>
+
 class IServer : public IInterface
 {
 	MACRO_INTERFACE("server", 0)
@@ -71,6 +73,11 @@ public:
 	//zCatch
 	virtual void MapReload() = 0;
 	
+	virtual int GetInfoTextIntervalPause() = 0;
+	virtual int GetInfoTextMsgInterval() = 0;
+	virtual int GetInfoTextInterval() = 0;
+	virtual std::string GetNextInfoText() = 0;
+	
 	virtual int GetNumLoggedInAdmins() = 0;
 };
 
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index 65affc64..8958a405 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -361,6 +361,8 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta)
 	m_numLoggedInAdmins = 0;
 	
 	m_Votebans = NULL;
+	m_InfoTexts = NULL;
+	m_InfoTextInterval = -1;
 	
 	Init();
 }
@@ -374,9 +376,34 @@ CServer::~CServer()
 		delete m_Votebans;
 		m_Votebans = tmp;
 	}
+	
+	// delte info texts
+	while(m_InfoTexts != NULL)
+	{
+		CInfoText *tmp = m_InfoTexts->m_Next;
+		delete m_InfoTexts;
+		m_InfoTexts = tmp;
+	}
 }
 
 
+void CServer::UpdateLoggedInAdmins()
+{
+	bool gotAny = (m_numLoggedInAdmins > 0);
+	m_numLoggedInAdmins = 0;
+	for(int i = 0; i < MAX_CLIENTS; ++i)
+	{
+		if(m_aClients[i].m_State == CClient::STATE_INGAME && m_aClients[i].m_Authed >= AUTHED_SUBADMIN)
+		{
+			++m_numLoggedInAdmins;
+		}
+	}
+	if(gotAny != (m_numLoggedInAdmins > 0))
+	{
+		UpdateServerInfo();
+	}
+}
+
 int CServer::TrySetClientName(int ClientID, const char *pName)
 {
 	char aTrimmedName[64];
@@ -794,11 +821,6 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
 	// notify the mod about the drop
 	if(pThis->m_aClients[ClientID].m_State >= CClient::STATE_READY)
 		pThis->GameServer()->OnClientDrop(ClientID, pReason);
-	
-	// check if dropped player is admin
-	if (pThis->IsAuthed(ClientID)) {
-		pThis->DecreaseLoggedInAdmins();
-	}
 
 	pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY;
 	pThis->m_aClients[ClientID].m_aName[0] = 0;
@@ -808,6 +830,10 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
 	pThis->m_aClients[ClientID].m_AuthTries = 0;
 	pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
 	pThis->m_aClients[ClientID].m_Snapshots.PurgeAll();
+	
+	// could have been an admin
+	pThis->UpdateLoggedInAdmins();
+	
 	return 0;
 }
 
@@ -1125,7 +1151,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 					char aBuf[256];
 					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID);
 					Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
-					IncreaseLoggedInAdmins();
+					UpdateLoggedInAdmins();
 				}
 				else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0)
 				{
@@ -1165,7 +1191,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 					char aBuf[256];
 					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (subadmin:%s)", ClientID, loginit->first.c_str());
 					Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
-					IncreaseLoggedInAdmins();
+					UpdateLoggedInAdmins();
 				}
 				else if(g_Config.m_SvRconMaxTries)
 				{
@@ -1820,6 +1846,145 @@ void CServer::ConRemoveLogin(IConsole::IResult *pResult, void *pUser)
 	}
 }
 
+void CServer::ConAddInfo(IConsole::IResult *pResult, void *pUser)
+{
+	CServer* pThis = static_cast<CServer *>(pUser);
+	int interval = pResult->GetInteger(0);
+	if(interval < 1 || interval > 1440)
+	{
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Interval must be between 1 and 1440.");
+		return;
+	}
+	
+	// add info text
+	CInfoText *t = new CInfoText;
+	t->m_Interval = interval;
+	t->m_Text = std::string(pResult->GetString(1));
+	// insert front
+	t->m_Next = pThis->m_InfoTexts;
+	pThis->m_InfoTexts = t;
+	
+	pThis->UpdateInfoTexts();
+	
+	// message to console
+	char aBuf[128];
+	str_format(aBuf, sizeof(aBuf), "Added the following info text: %s", t->m_Text.c_str());
+	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
+}
+
+void CServer::ConRemoveInfo(IConsole::IResult *pResult, void *pUser)
+{
+	CServer* pThis = static_cast<CServer *>(pUser);
+	int i = pResult->GetInteger(0);
+	int count = 0;
+	bool removed = false;
+	
+	CInfoText **t = &(pThis->m_InfoTexts);
+	while(*t != NULL)
+	{
+		if(count++ == i)
+		{
+			// remove
+			CInfoText *next = (*t)->m_Next;
+			delete *t;
+			*t = next;
+			removed = true;
+			break;
+		}
+		t = &((*t)->m_Next);
+	}
+	
+	pThis->UpdateInfoTexts();
+	
+	if(removed)
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text removed");
+	else
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text not found");
+}
+
+void CServer::ConListInfo(IConsole::IResult *pResult, void *pUser)
+{
+	CServer* pThis = static_cast<CServer *>(pUser);
+	char aBuf[128];
+	int count = 0;
+	
+	CInfoText *t = pThis->m_InfoTexts;
+	while(t != NULL)
+	{
+		str_format(aBuf, sizeof(aBuf), "#%d interval=%d min text='%s'", count++, t->m_Interval, t->m_Text.c_str());
+		pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
+		t = t->m_Next;
+	}
+	
+	str_format(aBuf, sizeof(aBuf), "%d info text(s)", count);
+	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
+}
+
+void CServer::UpdateInfoTexts()
+{
+	// in case that there are no info texts
+	if(m_InfoTexts == NULL)
+	{
+		m_InfoTextInterval = -1; // no interval
+		return;
+	}
+	
+	// need some random numbers later
+	init_rand();
+	
+	// update interval, set it to LCM(all text intervals)
+	m_InfoTextInterval = 1; // lowest possible interval
+	CInfoText *t = m_InfoTexts;
+	while(t != NULL)
+	{
+		m_InfoTextInterval = lcm(m_InfoTextInterval, t->m_Interval);
+		t->m_IntervalTicks = TickSpeed() * 60 * t->m_Interval; // min to ticks
+		t->m_NextTick = rand() % t->m_IntervalTicks; // variance
+		t = t->m_Next;
+	}
+	m_InfoTextInterval *= TickSpeed() * 60; // min to ticks
+	
+	// count total number of messages per interval
+	int numMsg = 0;
+	t = m_InfoTexts;
+	while(t != NULL)
+	{
+		numMsg += m_InfoTextInterval / t->m_IntervalTicks;
+		t = t->m_Next;
+	}
+	
+	// interval between messages
+	m_InfoTextMsgInterval = m_InfoTextInterval / numMsg;
+	// additional pause to sync interval and msg interval
+	m_InfoTextIntervalPause = m_InfoTextInterval % numMsg;
+}
+
+std::string CServer::GetNextInfoText()
+{
+	CInfoText *selectedText = NULL,
+		*t = m_InfoTexts;
+	// the counter r keeps track of how many equally due texts there are and actually helps so that every text has the same chance even though there are r-1 random decisions
+	int r = 1;
+	while(t != NULL)
+	{
+		// use this text if none is selected or this one is more due than the previously selected
+		// in the case that both are equally due, select one random
+		if(selectedText == NULL
+			|| t->m_NextTick < selectedText->m_NextTick
+			|| (t->m_NextTick == selectedText->m_NextTick && (rand() % ++r) == 0))
+			selectedText = t;
+		t = t->m_Next;
+	}
+	
+	// return empty string if no text applies
+	if(selectedText == NULL)
+		return std::string();
+	
+	// update tick and return string
+	selectedText->m_NextTick += selectedText->m_IntervalTicks;
+	return selectedText->m_Text;
+}
+
 void CServer::ConKick(IConsole::IResult *pResult, void *pUser)
 {
 	if(pResult->NumArguments() > 1)
@@ -1859,6 +2024,7 @@ void CServer::ConStatus(IConsole::IResult *pResult, void *pUser)
 			pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
 		}
 	}
+	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Quick help: kick <id> <reason=''> | ban <id> <min=5> <reason=''> | voteban <id> <sec=300> | kill <id>");
 }
 
 void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser)
@@ -1943,7 +2109,7 @@ void CServer::rconLogClientOut(int ClientID, const char *msg)
 		char aBuf[32];
 		str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", ClientID);
 		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
-		DecreaseLoggedInAdmins();
+		UpdateLoggedInAdmins();
 	}
 }
 
@@ -2033,6 +2199,10 @@ void CServer::RegisterCommands()
 	
 	Console()->Register("add_login", "ss", CFGFLAG_SERVER, ConAddLogin, this, "Add a subadmin login. The rcon password will be user:pass with no additional spaces.", IConsole::ACCESS_LEVEL_ADMIN);
 	Console()->Register("remove_login", "s", CFGFLAG_SERVER, ConRemoveLogin, this, "Remove a subadmin login", IConsole::ACCESS_LEVEL_ADMIN);
+	
+	Console()->Register("add_info", "is", CFGFLAG_SERVER, ConAddInfo, this, "Add a info text that is printed in the chat repeatedly in the given interval of minutes.");
+	Console()->Register("remove_info", "i", CFGFLAG_SERVER, ConRemoveInfo, this, "Remove a info text");
+	Console()->Register("list_info", "", CFGFLAG_SERVER, ConListInfo, this, "Show all info texts");
 
 	// register console commands in sub parts
 	m_ServerBan.InitServerBan(Console(), Storage(), this);
diff --git a/src/engine/server/server.h b/src/engine/server/server.h
index 7959603a..9b3ac371 100644
--- a/src/engine/server/server.h
+++ b/src/engine/server/server.h
@@ -71,12 +71,22 @@ class CServer : public IServer
 	
 	// keep track of how many admins are logged in
 	int m_numLoggedInAdmins;
-	void DecreaseLoggedInAdmins() {
-		if (!--m_numLoggedInAdmins) UpdateServerInfo();
-	}
-	void IncreaseLoggedInAdmins() {
-		if (++m_numLoggedInAdmins) UpdateServerInfo();
-	}
+	void UpdateLoggedInAdmins();
+	
+	// info messages
+	void UpdateInfoTexts();
+	struct CInfoText
+	{
+		int m_Interval;
+		int m_IntervalTicks;
+		int m_NextTick;
+		std::string m_Text;
+		CInfoText *m_Next;
+	};
+	CInfoText *m_InfoTexts;
+	int m_InfoTextInterval;
+	int m_InfoTextMsgInterval;
+	int m_InfoTextIntervalPause;
 	
 public:
 	class IGameServer *GameServer() { return m_pGameServer; }
@@ -290,6 +300,15 @@ public:
 	static void ConAddLogin(IConsole::IResult *pResult, void *pUser);
 	static void ConRemoveLogin(IConsole::IResult *pResult, void *pUser);
 	
+	// info messages
+	static void ConAddInfo(IConsole::IResult *pResult, void *pUser);
+	static void ConRemoveInfo(IConsole::IResult *pResult, void *pUser);
+	static void ConListInfo(IConsole::IResult *pResult, void *pUser);
+	int GetInfoTextIntervalPause() { return m_InfoTextIntervalPause; }
+	int GetInfoTextMsgInterval() { return m_InfoTextMsgInterval; }
+	int GetInfoTextInterval() { return m_InfoTextInterval; }
+	std::string GetNextInfoText();
+	
 	virtual int GetNumLoggedInAdmins() { return m_numLoggedInAdmins; }
 	
 	// logins
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index 2c1828da..b541f240 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -89,6 +89,8 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
 		m_ActiveWeapon = WEAPON_GUN;
 		m_LastWeapon = WEAPON_HAMMER;
 	}
+
+	pPlayer->m_RespawnProtection = Server()->Tick() + Server()->TickSpeed() * 2;
     /* end zCatch */
 	
 	m_LastNoAmmoSound = -1;
@@ -879,10 +881,11 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
 	/* zCatch */
 	if(From == m_pPlayer->GetCID() || Weapon == WEAPON_GAME)
 		return false;
-
 	if(g_Config.m_SvMode == 4 && Weapon == WEAPON_GRENADE && Dmg < g_Config.m_SvGrenadeMinDamage)
 		return false;
 
+	if(m_pPlayer->m_RespawnProtection > Server()->Tick() || GameServer()->m_apPlayers[From]->m_RespawnProtection > Server()->Tick())
+		return false;
 	m_Health = 0;
 	m_Armor = 0;
 	/* end zCatch */
diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h
index 0d68707a..240ee0e2 100644
--- a/src/game/server/entities/character.h
+++ b/src/game/server/entities/character.h
@@ -73,6 +73,8 @@ public:
 	bool HasBeenThereRecently(vec2 v, const vec2 *&pos, int firstTick, int lastTick) const;
 	bool AimedAtCharRecently(vec2 v, const CCharacter *c, const vec2 *&pos, const vec2 *&posVictim, int firstTick);
 	float HowCloseToXRecently(vec2 x, const vec2 *&pos, int firstTick);
+	void SetEmoteType(int EmoteType) { m_EmoteType = EmoteType; };
+	void SetEmoteStop(int EmoteStop) { m_EmoteStop = EmoteStop; };
 
 private:
 	// player controlling this character
@@ -105,6 +107,7 @@ private:
 	int m_EmoteType;
 	int m_EmoteStop;
 
+
 	// last tick that the player took any action ie some input
 	int m_LastAction;
 	int m_LastNoAmmoSound;
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index 52b5b9fd..27d17c11 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -526,6 +526,14 @@ void CGameContext::OnTick()
 			}
 		}
 	}
+	
+	// info messages
+	// execute if interval is given and message interval is due, respecting the pause
+	if(Server()->GetInfoTextInterval() > 0
+		&& ((Server()->Tick() % Server()->GetInfoTextInterval()) - Server()->GetInfoTextIntervalPause()) % Server()->GetInfoTextMsgInterval() == 0)
+	{
+		SendChat(-1, CGameContext::CHAT_ALL, Server()->GetNextInfoText().c_str());
+	}
 
 	// bot detection
 	// it is based on the behaviour of some bots to shoot at a player's _exact_ position
@@ -940,20 +948,16 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 					if(MuteValidation(pPlayer))
 					{
 						// prepare message
-						const char *msgForm = "/PM/ %s",
-							*msgFormSender = "/PM -> %s / %s";
+						const char *msgForm = "/PM -> %s / %s";
 						int len = 32 + MAX_NAME_LENGTH + str_length(msgStart);
 						char *msg = (char*)malloc(len * sizeof(char));
 						CNetMsg_Sv_Chat M;
 						M.m_Team = 0;
 						M.m_ClientID = ClientID;
-						// send to sender
-						str_format(msg, len * sizeof(char), msgFormSender, Server()->ClientName(recipient), msgStart);
+						// send to sender and recipient
+						str_format(msg, len * sizeof(char), msgForm, Server()->ClientName(recipient), msgStart);
 						M.m_pMessage = msg;
 						Server()->SendPackMsg(&M, MSGFLAG_VITAL, ClientID);
-						// send to recipient
-						str_format(msg, len * sizeof(char), msgForm, msgStart);
-						M.m_pMessage = msg;
 						Server()->SendPackMsg(&M, MSGFLAG_VITAL, recipient);
 						// tidy up
 						free(msg);
@@ -1350,6 +1354,43 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 		pPlayer->m_LastEmote = Server()->Tick();
 
 		SendEmoticon(ClientID, pMsg->m_Emoticon);
+		CCharacter* pChr = pPlayer->GetCharacter();
+					if(pChr)
+					{
+						switch(pMsg->m_Emoticon)
+						{
+						case EMOTICON_EXCLAMATION:
+						case EMOTICON_GHOST:
+						case EMOTICON_QUESTION:
+						case EMOTICON_WTF:
+								pChr->SetEmoteType(EMOTE_SURPRISE);
+								break;
+						case EMOTICON_DOTDOT:
+						case EMOTICON_DROP:
+						case EMOTICON_ZZZ:
+								pChr->SetEmoteType(EMOTE_BLINK);
+								break;
+						case EMOTICON_EYES:
+						case EMOTICON_HEARTS:
+						case EMOTICON_MUSIC:
+								pChr->SetEmoteType(EMOTE_HAPPY);
+								break;
+						case EMOTICON_OOP:
+						case EMOTICON_SORRY:
+						case EMOTICON_SUSHI:
+								pChr->SetEmoteType(EMOTE_PAIN);
+								break;
+						case EMOTICON_DEVILTEE:
+						case EMOTICON_SPLATTEE:
+						case EMOTICON_ZOMG:
+								pChr->SetEmoteType(EMOTE_ANGRY);
+								break;
+							default:
+								pChr->SetEmoteType(EMOTE_NORMAL);
+								break;
+						}
+						pChr->SetEmoteStop(Server()->Tick() + 2 * Server()->TickSpeed());
+					}
 	}
 	else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused)
 	{
diff --git a/src/game/server/gamemodes/zcatch.cpp b/src/game/server/gamemodes/zcatch.cpp
index 63ed3dfb..cd36d12f 100644
--- a/src/game/server/gamemodes/zcatch.cpp
+++ b/src/game/server/gamemodes/zcatch.cpp
@@ -2,7 +2,7 @@
 /* If you are missing that file, acquire a complete release at teeworlds.com.                */
 /* zCatch by erd and Teetime                                                                 */
 /* Modified by Teelevision for zCatch/TeeVi, see readme.txt and license.txt.                 */
-
+#include <iostream>
 #include <engine/shared/config.h>
 #include <game/server/gamecontext.h>
 #include <game/server/gamecontroller.h>
@@ -122,13 +122,77 @@ int CGameController_zCatch::OnCharacterDeath(class CCharacter *pVictim, class CP
 
 void CGameController_zCatch::OnPlayerInfoChange(class CPlayer *pP)
 {
-	if(g_Config.m_SvColorIndicator && pP->m_zCatchNumKillsInARow <= 20)
-	{
-		int Num = max(0, 160 - pP->m_zCatchNumKillsInARow * 10);
-		pP->m_TeeInfos.m_ColorBody = Num * 0x010000 + 0xff00;
-		pP->m_TeeInfos.m_ColorFeet = pP->m_zCatchNumKillsInARow == 20 ? 0x40ff00 : pP->m_TeeInfos.m_ColorBody;
-		pP->m_TeeInfos.m_UseCustomColor = 1;
-	}
+    if(g_Config.m_SvColorIndicator)
+    {
+    	switch(pP->m_zCatchNumKillsInARow){
+    		case 0:
+				pP->m_TeeInfos.m_ColorBody = 0xFFBB00;
+				pP->m_TeeInfos.m_ColorFeet =  0x11FF00;
+				break;
+    		case 15:
+				pP->m_TeeInfos.m_ColorBody = 0xEEFF00;
+				break;
+    		case 14:
+				pP->m_TeeInfos.m_ColorBody = 0xDDFF00;
+				break;
+    		case 13:
+				pP->m_TeeInfos.m_ColorBody = 0xCCFF00;
+				break;
+    		case 12:
+				pP->m_TeeInfos.m_ColorBody = 0xBBFF00;
+				break;
+    		case 11:
+				pP->m_TeeInfos.m_ColorBody = 0xAAFF00;
+				break;
+    		case 10:
+				pP->m_TeeInfos.m_ColorBody = 0x99FF00;
+				break;
+    		case 9:
+				pP->m_TeeInfos.m_ColorBody = 0x88FF00;
+				break;
+    		case 8:
+				pP->m_TeeInfos.m_ColorBody = 0x77FF00;
+				break;
+    		case 7:
+				pP->m_TeeInfos.m_ColorBody = 0x66FF00;
+				break;
+    		case 6:
+				pP->m_TeeInfos.m_ColorBody = 0x55FF00;
+				break;
+    		case 5:
+				pP->m_TeeInfos.m_ColorBody = 0x44FF00;
+				break;
+    		case 4:
+				pP->m_TeeInfos.m_ColorBody = 0x33FF00;
+				break;
+    		case 3:
+				pP->m_TeeInfos.m_ColorBody = 0x22FF00;
+				break;
+    		case 2:
+				pP->m_TeeInfos.m_ColorBody = 0x11FF00;
+				break;
+    		case 1:
+				pP->m_TeeInfos.m_ColorBody = 0x00FF00;
+				break;
+    		default:
+				pP->m_TeeInfos.m_ColorBody = 0x000000;
+				break;
+    	}
+    	pP->m_TeeInfos.m_ColorFeet = 0x11FF00 + pP->m_TeeInfos.m_ColorFeet;
+    	pP->m_TeeInfos.m_UseCustomColor = 1;
+    }
+//	if(g_Config.m_SvColorIndicator){
+//		if(pP->m_zCatchNumKillsInARow > 1 || pP->m_zCatchNumKillsInARow < 16)
+//		{
+//				pP->m_TeeInfos.m_ColorBody = 0x11FF00 + pP->m_TeeInfos.m_ColorBody;
+//		}
+//		else
+//		{
+//				pP->m_TeeInfos.m_ColorBody = 0x11FF00;
+//		}
+//				pP->m_TeeInfos.m_ColorFeet = pP->m_TeeInfos.m_ColorBody;
+//				pP->m_TeeInfos.m_UseCustomColor = 1;
+//	}
 }
 
 void CGameController_zCatch::StartRound()
diff --git a/src/game/server/player.h b/src/game/server/player.h
index 97fb299c..7189d7e2 100644
--- a/src/game/server/player.h
+++ b/src/game/server/player.h
@@ -113,6 +113,8 @@ public:
 	int m_CampTick;
 	vec2 m_CampPos;
 	
+	int m_RespawnProtection;
+
 	// zCatch/TeeVi
 	enum
 	{