about summary refs log tree commit diff
diff options
context:
space:
mode:
authorsavander <savander.pl@gmail.com>2014-11-07 17:24:32 +0100
committersavander <savander.pl@gmail.com>2014-11-07 17:24:32 +0100
commit6e77966e93fefa3fe965721f81ea3b9be85c755a (patch)
tree597a101284a888e153c58c430079dd2792821ed8
parent4f8d463263590581d88ce2eeae4d6f0886675f55 (diff)
downloadzcatch-6e77966e93fefa3fe965721f81ea3b9be85c755a.tar.gz
zcatch-6e77966e93fefa3fe965721f81ea3b9be85c755a.zip
Remove: t / ti, Added Whisper system from DDnet by deen
-rw-r--r--src/engine/shared/protocol.h8
-rw-r--r--src/game/server/gamecontext.cpp300
-rw-r--r--src/game/server/gamecontext.h11
-rw-r--r--src/game/server/player.cpp4
-rw-r--r--src/game/server/player.h3
-rw-r--r--src/game/server/ranking.cpp19
-rw-r--r--src/game/version.h2
7 files changed, 250 insertions, 97 deletions
diff --git a/src/engine/shared/protocol.h b/src/engine/shared/protocol.h
index ba04da8a..14cac9f7 100644
--- a/src/engine/shared/protocol.h
+++ b/src/engine/shared/protocol.h
@@ -59,6 +59,7 @@ enum
 	NETMSG_RCON_AUTH,		//
 	NETMSG_REQUEST_MAP_DATA,//
 
+
 	NETMSG_AUTH_START,		//
 	NETMSG_AUTH_RESPONSE,	//
 
@@ -93,5 +94,12 @@ enum
 	MSGFLAG_RECORD=8,
 	MSGFLAG_NOSEND=16
 };
+enum
+{
+	VERSION_VANILLA = 0,
+	VERSION_DDRACE = 1,
+	VERSION_DDNET_OLD = 2,
+	VERSION_DDNET_WHISPER = 217,
+};
 
 #endif
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index 305a3adf..8c7bac51 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -837,7 +837,37 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 		/* begin zCatch*/
 		if(!str_comp_num("/", pMsg->m_pMessage, 1))
 		{
-			if(!str_comp_nocase("info", pMsg->m_pMessage + 1))
+			if (str_comp_nocase_num(pMsg->m_pMessage+1, "w ", 2) == 0)
+			{
+				char pWhisperMsg[256];
+				str_copy(pWhisperMsg, pMsg->m_pMessage + 3, 256);
+				Whisper(pPlayer->GetCID(), pWhisperMsg);
+			}
+			else if (str_comp_nocase_num(pMsg->m_pMessage+1, "whisper ", 8) == 0)
+			{
+				char pWhisperMsg[256];
+				str_copy(pWhisperMsg, pMsg->m_pMessage + 9, 256);
+				Whisper(pPlayer->GetCID(), pWhisperMsg);
+			}
+			else if (str_comp_nocase_num(pMsg->m_pMessage+1, "c ", 2) == 0)
+			{
+				char pWhisperMsg[256];
+				str_copy(pWhisperMsg, pMsg->m_pMessage + 3, 256);
+				Converse(pPlayer->GetCID(), pWhisperMsg);
+			}
+			else if (str_comp_nocase_num(pMsg->m_pMessage+1, "converse ", 9) == 0)
+			{
+				char pWhisperMsg[256];
+				str_copy(pWhisperMsg, pMsg->m_pMessage + 10, 256);
+				Converse(pPlayer->GetCID(), pWhisperMsg);
+			}
+			else if(!str_comp_nocase("w", pMsg->m_pMessage + 1) || !str_comp_nocase("whisper", pMsg->m_pMessage + 1)
+					|| !str_comp_nocase("c", pMsg->m_pMessage + 1) || !str_comp_nocase("converse", pMsg->m_pMessage + 1)){
+				char aBuf[128];
+				str_format(aBuf, sizeof(aBuf), "Type /help to see how use this command.");
+				SendChatTarget(ClientID, aBuf);
+			}
+			else if(!str_comp_nocase("info", pMsg->m_pMessage + 1))
 			{
 				char aBuf[128];
 				str_format(aBuf, sizeof(aBuf), "zCatch %s by erd and Teetime, modified by Teelevision modified by Savander. See /help.", ZCATCH_VERSION);
@@ -848,9 +878,9 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 					str_format(aBuf, sizeof(aBuf), "If there are less than %d players, the round does not end and all players are released instead.", g_Config.m_SvLastStandingPlayers);
 					SendChatTarget(ClientID, aBuf);
 				}
-				SendChatTarget(ClientID, " ");
-				SendChatTarget(ClientID, "Commands list: top5, rank, help, victims, kills, t, ti");
+				SendChatTarget(ClientID, "Commands list: top5, rank, help, victims, kills, w, whisper, c, converse");
 			}
+
 			else if(!str_comp_nocase("top5", pMsg->m_pMessage + 1) || !str_comp_nocase_num("top5 ", pMsg->m_pMessage + 1, 5))
 			{
 				if(!str_comp_nocase_num("top5 ", pMsg->m_pMessage + 1, 5)){
@@ -881,8 +911,8 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 				SendChatTarget(ClientID, "/top5 or /top5 <number> - Top5 winners on server.");
 				SendChatTarget(ClientID, "/victims - who is waiting for your death");
 				SendChatTarget(ClientID, "/kills -  list of players you killed");
-				SendChatTarget(ClientID, "/t <name> <msg> - write PM to <name>");
-				SendChatTarget(ClientID, "/ti <id> <msg> - write PM via ID");
+				SendChatTarget(ClientID, "/whisper <name> <msg>");
+				SendChatTarget(ClientID, "/converse <id> <msg>");
 			}
 			else if(!str_comp_nocase("victims", pMsg->m_pMessage + 1))
 			{
@@ -917,86 +947,6 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 					SendChatTarget(ClientID, "You caught no one since your last death.");
 				}
 			}
-			// tell / PM someone privately
-			else if(!str_comp_nocase_num("t ", pMsg->m_pMessage + 1, 2) || !str_comp_nocase_num("ti ", pMsg->m_pMessage + 1, 3))
-			{
-				const char *recipientStart, *msgStart;
-				int recipient = -1;
-				
-				// by name
-				if(!str_comp_nocase_num("t ", pMsg->m_pMessage + 1, 2))
-				{
-					int recipientNameLength;
-					const char *recipientName;
-					recipientStart = str_skip_whitespaces((char*)pMsg->m_pMessage + 3);
-					// check _all_ players (there might be partly identical names)
-					for(int i = 0; i < MAX_CLIENTS; ++i)
-					{
-						if(m_apPlayers[i]
-							&& (recipientName = Server()->ClientName(i))
-							&& (recipientNameLength = str_length(recipientName))
-							&& !str_comp_num(recipientName, recipientStart, recipientNameLength)
-							&& recipientStart[recipientNameLength] == ' '
-						)
-						{
-							if(recipient >= 0)
-							{
-								SendChatTarget(ClientID, "Could not deliver private message. More than one player could be addressed.");
-								return;
-							}
-							msgStart = recipientStart + recipientNameLength + 1;
-							recipient = i;
-						}
-					}
-				}
-				
-				// by id
-				else if(!str_comp_nocase_num("ti ", pMsg->m_pMessage + 1, 3))
-				{
-					recipientStart = str_skip_whitespaces((char*)pMsg->m_pMessage + 4);
-					// check if int given
-					for(const char *c = recipientStart; *c != ' '; ++c)
-					{
-						if(*c < '0' || '9' < *c)
-						{
-							SendChatTarget(ClientID, "No id given, syntax is: /ti id message.");
-							return;
-						}
-					}
-					int i = str_toint(recipientStart);
-					if(i <= MAX_CLIENTS)
-						if(m_apPlayers[i])
-						{
-							recipient = i;
-							msgStart = str_skip_whitespaces(str_skip_to_whitespace((char*)recipientStart));
-						}
-				}
-				
-				if(recipient >= 0)
-				{
-					if(MuteValidation(pPlayer))
-					{
-						// prepare message
-						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 and recipient
-						str_format(msg, len * sizeof(char), msgForm, Server()->ClientName(recipient), msgStart);
-						M.m_pMessage = msg;
-						Server()->SendPackMsg(&M, MSGFLAG_VITAL, ClientID);
-						Server()->SendPackMsg(&M, MSGFLAG_VITAL, recipient);
-						// tidy up
-						free(msg);
-					}
-				}
-				else
-				{
-					SendChatTarget(ClientID, "Could not deliver private message. Player not found.");
-				}
-			}
 			else
 			{
 				SendChatTarget(ClientID, "Unknown command, try /info");
@@ -1172,6 +1122,18 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 			pPlayer->m_LastVoteCall = Now;
 		}
 	}
+	else if (MsgID == NETMSGTYPE_CL_ISDDNET)
+			{
+				int Version = pUnpacker->GetInt();
+
+				if (pUnpacker->Error())
+				{
+					if (pPlayer->m_ClientVersion < VERSION_DDRACE)
+						pPlayer->m_ClientVersion = VERSION_DDRACE;
+				}
+				else if(pPlayer->m_ClientVersion < Version)
+					pPlayer->m_ClientVersion = Version;
+	}
 	else if(MsgID == NETMSGTYPE_CL_VOTE)
 	{
 		if(!m_VoteCloseTime)
@@ -2192,6 +2154,174 @@ bool CGameContext::IsClientAimBot(int ClientID)
 	return m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_IsAimBot;
 }
 
+
+bool CheckClientID2(int ClientID)
+{
+	dbg_assert(ClientID >= 0 || ClientID < MAX_CLIENTS,
+			"The Client ID is wrong");
+	if (ClientID < 0 || ClientID >= MAX_CLIENTS)
+		return false;
+	return true;
+}
+
+void CGameContext::Whisper(int ClientID, char *pStr)
+{
+	char *pName;
+	char *pMessage;
+	int Error = 0;
+
+	pStr = str_skip_whitespaces(pStr);
+
+	int Victim;
+
+	// add token
+	if(*pStr == '"')
+	{
+		pStr++;
+
+		pName = pStr; // we might have to process escape data
+		while(1)
+		{
+			if(pStr[0] == '"')
+				break;
+			else if(pStr[0] == '\\')
+			{
+				if(pStr[1] == '\\')
+					pStr++; // skip due to escape
+				else if(pStr[1] == '"')
+					pStr++; // skip due to escape
+			}
+			else if(pStr[0] == 0)
+				Error = 1;
+
+			pStr++;
+		}
+
+		// write null termination
+		*pStr = 0;
+		pStr++;
+
+		for(Victim = 0; Victim < MAX_CLIENTS; Victim++)
+			if (str_comp(pName, Server()->ClientName(Victim)) == 0)
+				break;
+
+	}
+	else
+	{
+		pName = pStr;
+		while(1)
+		{
+			if(pStr[0] == 0)
+			{
+				Error = 1;
+				break;
+			}
+			if(pStr[0] == ' ')
+			{
+				pStr[0] = 0;
+				for(Victim = 0; Victim < MAX_CLIENTS; Victim++)
+					if (str_comp(pName, Server()->ClientName(Victim)) == 0)
+						break;
+
+				pStr[0] = ' ';
+
+				if (Victim < MAX_CLIENTS)
+					break;
+			}
+			pStr++;
+		}
+	}
+
+	if(pStr[0] != ' ')
+	{
+		Error = 1;
+	}
+
+	*pStr = 0;
+	pStr++;
+
+	pMessage = pStr;
+
+	char aBuf[256];
+
+	if (Error)
+	{
+		str_format(aBuf, sizeof(aBuf), "Invalid whisper");
+		SendChatTarget(ClientID, aBuf);
+		return;
+	}
+
+	if (Victim >= MAX_CLIENTS || !CheckClientID2(Victim))
+	{
+		str_format(aBuf, sizeof(aBuf), "No player with name \"%s\" found", pName);
+		SendChatTarget(ClientID, aBuf);
+		return;
+	}
+
+	WhisperID(ClientID, Victim, pMessage);
+}
+
+void CGameContext::WhisperID(int ClientID, int VictimID, char *pMessage)
+{
+	if (!CheckClientID2(ClientID))
+		return;
+
+	if (!CheckClientID2(VictimID))
+		return;
+
+	if (m_apPlayers[ClientID])
+		m_apPlayers[ClientID]->m_LastWhisperTo = VictimID;
+
+	char aBuf[256];
+	if(m_apPlayers[ClientID]->m_LastWhisperTo != ClientID){
+		if (m_apPlayers[ClientID] && m_apPlayers[ClientID]->m_ClientVersion >= VERSION_DDNET_WHISPER)
+		{
+			CNetMsg_Sv_Chat Msg;
+			Msg.m_Team = CHAT_WHISPER_SEND;
+			Msg.m_ClientID = VictimID;
+			Msg.m_pMessage = pMessage;
+			Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, ClientID);
+		}
+		else
+		{
+			str_format(aBuf, sizeof(aBuf), "[→ %s] %s", Server()->ClientName(VictimID), pMessage);
+			SendChatTarget(ClientID, aBuf);
+		}
+
+		if (m_apPlayers[VictimID] && m_apPlayers[VictimID]->m_ClientVersion >= VERSION_DDNET_WHISPER)
+		{
+			CNetMsg_Sv_Chat Msg2;
+			Msg2.m_Team = CHAT_WHISPER_RECV;
+			Msg2.m_ClientID = ClientID;
+			Msg2.m_pMessage = pMessage;
+			Server()->SendPackMsg(&Msg2, MSGFLAG_VITAL, VictimID);
+		}
+		else
+		{
+			str_format(aBuf, sizeof(aBuf), "[← %s] %s", Server()->ClientName(ClientID), pMessage);
+			SendChatTarget(VictimID, aBuf);
+		}
+	}else{
+		str_format(aBuf, sizeof(aBuf), "You can't talk to yourself.");
+		SendChatTarget(ClientID, aBuf);
+	}
+}
+
+void CGameContext::Converse(int ClientID, char *pStr)
+{
+	CPlayer *pPlayer = m_apPlayers[ClientID];
+	if (!pPlayer)
+		return;
+
+	if (pPlayer->m_LastWhisperTo < 0)
+		SendChatTarget(ClientID, "You do not have an ongoing conversation. Whisper to someone to start one");
+	else
+	{
+		WhisperID(ClientID, pPlayer->m_LastWhisperTo, pStr);
+	}
+}
+
+
 const char *CGameContext::GameType() { return m_pController && m_pController->m_pGameType ? m_pController->m_pGameType : ""; }
 const char *CGameContext::Version() { return GAME_VERSION; }
 const char *CGameContext::NetVersion() { return GAME_NETVERSION; }
diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h
index 41d6d899..3cb6245c 100644
--- a/src/game/server/gamecontext.h
+++ b/src/game/server/gamecontext.h
@@ -19,8 +19,7 @@
 
 
 #define MAX_MUTES 35
-#define ZCATCH_VERSION "0.4.9 BETA"
-
+#define ZCATCH_VERSION "0.5"
 /*
 	Tick
 		Game Context (CGameContext::tick)
@@ -79,6 +78,10 @@ class CGameContext : public IGameServer
 	
 	static void ConKill(IConsole::IResult *pResult, void *pUserData);
 
+	void Whisper(int ClientID, char *pStr);
+	void WhisperID(int ClientID, int VictimID, char *pMessage);
+	void Converse(int ClientID, char *pStr);
+
 	CGameContext(int Resetting);
 	void Construct(int Resetting);
 
@@ -150,7 +153,9 @@ public:
 		CHAT_ALL=-2,
 		CHAT_SPEC=-1,
 		CHAT_RED=0,
-		CHAT_BLUE=1
+		CHAT_BLUE=1,
+		CHAT_WHISPER_SEND=2,
+		CHAT_WHISPER_RECV=3
 	};
 	
 	struct CMutes
diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp
index 91a75c9d..2081ad4a 100644
--- a/src/game/server/player.cpp
+++ b/src/game/server/player.cpp
@@ -47,6 +47,8 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team)
 	m_CurrentTarget.y = 0;
 	m_LastTarget.x = 0;
 	m_LastTarget.y = 0;
+
+	m_ClientVersion = VERSION_VANILLA;
 }
 
 CPlayer::~CPlayer()
@@ -58,8 +60,10 @@ CPlayer::~CPlayer()
 		delete tmp;
 	}
 	
+
 	delete m_pCharacter;
 	m_pCharacter = 0;
+
 }
 
 void CPlayer::Tick()
diff --git a/src/game/server/player.h b/src/game/server/player.h
index 416dccd7..877ae0bc 100644
--- a/src/game/server/player.h
+++ b/src/game/server/player.h
@@ -62,7 +62,8 @@ public:
 	int m_LastChangeInfo;
 	int m_LastEmote;
 	int m_LastKill;
-
+	int m_LastWhisperTo;
+	int m_ClientVersion;
 	// TODO: clean this up
 	struct
 	{
diff --git a/src/game/server/ranking.cpp b/src/game/server/ranking.cpp
index b5d88514..091c4b78 100644
--- a/src/game/server/ranking.cpp
+++ b/src/game/server/ranking.cpp
@@ -52,14 +52,14 @@ void CRanking::Init()
 			str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS zcatch_ranks (Name VARCHAR(%d) BINARY NOT NULL, Wins INT DEFAULT 0, UNIQUE KEY Name (Name)) CHARACTER SET utf8 ;", MAX_NAME_LENGTH);
 			m_pStatement->execute(aBuf);
 
-			dbg_msg("SQL", "Ranking table was created successfully");
+			dbg_msg("SQL", "Ranking table were created successfully");
 		}
 		catch (sql::SQLException &e)
 		{
 			char aBuf[256];
 			str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
 			dbg_msg("SQL", aBuf);
-			dbg_msg("SQL", "ERROR: Table was NOT created");
+			dbg_msg("SQL", "ERROR: Tables were NOT created");
 		}
 
 		// disconnect from database
@@ -155,7 +155,7 @@ bool CRanking::Connect()
 	}
 	catch (...)
 	{
-		dbg_msg("SQL", "Unknown Error cause by the MySQL/C++ Connector, my advice is to compile server_sql_debug and use it");
+		dbg_msg("SQL", "Unknown Error cause by the MySQL/C++ Connector, my advice compile server_debug and use it");
 
 		dbg_msg("SQL", "ERROR: SQL connection failed");
 		return false;
@@ -212,12 +212,17 @@ void CRanking::SaveRankingThread(void *pUser){
 						str_format(aBuf2, sizeof(aBuf), "Woah! You won for the first time! Now you have 1 win.");
 						pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf2);
 					}else{
-						str_format(aBuf2, sizeof(aBuf), "You're the winner! Now you have %d wins!", wins+1);
+						str_format(aBuf2, sizeof(aBuf), "You're winner! Now you have %d wins!", wins+1);
 						pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf2);
 					}
 				}
+
+
 			}
 
+
+
+
 			delete pData->m_pSqlData->m_pResults;
 
 			// if no entry found... create a new one
@@ -285,11 +290,11 @@ void CRanking::ShowRankingThread(void *pUser){
 				if(pData->m_pSqlData->m_pResults->rowsCount() == 1){
 					int wins = (int)pData->m_pSqlData->m_pResults->getInt("Wins");
 					int rank = (int)pData->m_pSqlData->m_pResults->getInt("rank");
-					str_format(aBuf2, sizeof(aBuf2), "%d. %s has %d %s, requested by %s.", rank,originalName,wins, (wins != 1) ? "wins" : "win", pData->m_aRequestingPlayer);
+					str_format(aBuf2, sizeof(aBuf2), "%d. %s's have %d %s Requested by %s.", rank,originalName,wins, (wins > 1) ? "wins." : "win.", pData->m_aRequestingPlayer);
 					pData->m_pSqlData->GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf2);
 				}
 			}else{
-				str_format(aBuf2, sizeof(aBuf2), "%s is not ranked.", originalName);
+				str_format(aBuf2, sizeof(aBuf2), "%s's is not ranked.", originalName);
 				pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf2);
 
 			}
@@ -356,7 +361,7 @@ void CRanking::ShowTop5Thread(void *pUser){
 			while(pData->m_pSqlData->m_pResults->next()){
 					int wins = (int)pData->m_pSqlData->m_pResults->getInt("Wins");
 					int rank = (int)pData->m_pSqlData->m_pResults->getInt("rank");
-					str_format(aBuf2, sizeof(aBuf2), "%d. %s has %d %s", rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(),wins, (wins != 1) ? "wins" : "win");
+					str_format(aBuf2, sizeof(aBuf2), "%d. %s's have %d %s", rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(),wins, (wins > 1) ? "wins." : "win.");
 					pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf2);
 			}
 			str_format(aBuf2, sizeof(aBuf2), "------=====]");
diff --git a/src/game/version.h b/src/game/version.h
index 76d95dd0..ed00afae 100644
--- a/src/game/version.h
+++ b/src/game/version.h
@@ -4,6 +4,6 @@
 #define GAME_VERSION_H
 #include "generated/nethash.cpp"
 #define GAME_VERSION "0.6.2"
-#define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH
+#define GAME_NETVERSION "0.6 626fce9a778df4d4"
 static const char GAME_RELEASE_VERSION[8] = {'0', '.', '6', '.', '2', 0};
 #endif