about summary refs log tree commit diff
path: root/src/game/server/gamecontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/server/gamecontext.cpp')
-rw-r--r--src/game/server/gamecontext.cpp300
1 files changed, 215 insertions, 85 deletions
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; }