ddnet/src/game/client/components/chat.cpp

439 lines
12 KiB
C++
Raw Normal View History

#include <string.h>
#include <stdio.h>
2008-08-27 19:41:02 +00:00
2010-05-29 07:25:38 +00:00
#include <engine/graphics.h>
#include <engine/textrender.h>
#include <engine/keys.h>
#include <engine/shared/config.h>
2010-05-29 07:25:38 +00:00
#include <game/generated/protocol.h>
#include <game/generated/client_data.h>
2010-05-29 07:25:38 +00:00
#include <game/client/gameclient.h>
2008-08-29 05:34:18 +00:00
#include <game/client/components/scoreboard.h>
2010-05-29 07:25:38 +00:00
#include <game/client/components/sounds.h>
#include <game/client/components/camera.h>
2010-05-29 07:25:38 +00:00
#include <game/localization.h>
2010-05-29 07:25:38 +00:00
#include "chat.h"
CChat::CChat()
{
2010-05-29 07:25:38 +00:00
OnReset();
}
void CChat::OnReset()
{
for(int i = 0; i < MAX_LINES; i++)
2009-05-31 09:44:20 +00:00
{
2010-05-29 07:25:38 +00:00
m_aLines[i].m_Time = 0;
m_aLines[i].m_aText[0] = 0;
m_aLines[i].m_aName[0] = 0;
}
m_Show = false;
2010-05-29 07:25:38 +00:00
}
void CChat::OnRelease()
{
m_Show = false;
}
2010-05-29 07:25:38 +00:00
void CChat::OnStateChange(int NewState, int OldState)
{
if(OldState <= IClient::STATE_CONNECTING)
{
m_Mode = MODE_NONE;
2009-05-31 09:44:20 +00:00
for(int i = 0; i < MAX_LINES; i++)
2010-05-29 07:25:38 +00:00
m_aLines[i].m_Time = 0;
m_CurrentLine = 0;
m_ChatMoving = false;
2009-05-31 09:44:20 +00:00
}
}
2010-08-25 20:30:21 +00:00
void CChat::ConSay(IConsole::IResult *pResult, void *pUserData, int ClientID)
2008-08-27 19:41:02 +00:00
{
2010-05-29 07:25:38 +00:00
((CChat*)pUserData)->Say(0, pResult->GetString(0));
2008-08-27 19:41:02 +00:00
}
2010-08-25 20:30:21 +00:00
void CChat::ConSayTeam(IConsole::IResult *pResult, void *pUserData, int ClientID)
2008-08-27 19:41:02 +00:00
{
2010-05-29 07:25:38 +00:00
((CChat*)pUserData)->Say(1, pResult->GetString(0));
2008-08-27 19:41:02 +00:00
}
2010-08-25 20:30:21 +00:00
void CChat::ConChat(IConsole::IResult *pResult, void *pUserData, int ClientID)
2008-08-27 19:41:02 +00:00
{
2010-05-29 07:25:38 +00:00
const char *pMode = pResult->GetString(0);
if(str_comp(pMode, "all") == 0)
((CChat*)pUserData)->EnableMode(0);
else if(str_comp(pMode, "team") == 0)
((CChat*)pUserData)->EnableMode(1);
2008-08-27 19:41:02 +00:00
else
((CChat*)pUserData)->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", "expected all or team as mode");
2008-08-27 19:41:02 +00:00
}
2010-08-25 20:30:21 +00:00
void CChat::ConShowChat(IConsole::IResult *pResult, void *pUserData, int ClientID)
{
((CChat *)pUserData)->m_Show = pResult->GetInteger(0) != 0;
}
2010-08-25 20:30:21 +00:00
void CChat::ConUpChat(IConsole::IResult *pResult, void *pUserData, int ClientID) {
((CChat*)pUserData)->m_ChatMoving = true;
((CChat*)pUserData)->m_RenderLine = (((CChat*)pUserData)->m_RenderLine - 1)%MAX_LINES;
}
2010-08-25 20:30:21 +00:00
void CChat::ConDownChat(IConsole::IResult *pResult, void *pUserData, int ClientID) {
((CChat*)pUserData)->m_ChatMoving = true;
((CChat*)pUserData)->m_RenderLine = (((CChat*)pUserData)->m_RenderLine + 1)%MAX_LINES;
}
2010-05-29 07:25:38 +00:00
void CChat::OnConsoleInit()
2008-08-27 19:41:02 +00:00
{
2010-08-25 20:30:21 +00:00
Console()->Register("say", "r", CFGFLAG_CLIENT, ConSay, this, "Say in chat", 0);
Console()->Register("say_team", "r", CFGFLAG_CLIENT, ConSayTeam, this, "Say in team chat", 0);
Console()->Register("chat", "s", CFGFLAG_CLIENT, ConChat, this, "Enable chat with all/team mode", 0);
Console()->Register("chat_up", "", CFGFLAG_CLIENT, ConUpChat, this, "Show early message", 0);
Console()->Register("chat_down", "", CFGFLAG_CLIENT, ConDownChat, this, "Show last message", 0);
Console()->Register("+show_chat", "", CFGFLAG_CLIENT, ConShowChat, this, "Show chat", 0);
2008-08-27 19:41:02 +00:00
}
2010-05-29 07:25:38 +00:00
bool CChat::OnInput(IInput::CEvent e)
{
2010-05-29 07:25:38 +00:00
if(m_Mode == MODE_NONE)
return false;
2010-05-29 07:25:38 +00:00
if(e.m_Flags&IInput::FLAG_PRESS && e.m_Key == KEY_ESCAPE)
{
2010-05-29 07:25:38 +00:00
m_Mode = MODE_NONE;
m_pClient->OnRelease();
}
2010-05-29 07:25:38 +00:00
else if(e.m_Flags&IInput::FLAG_PRESS && (e.m_Key == KEY_RETURN || e.m_Key == KEY_KP_ENTER))
{
2010-05-29 07:25:38 +00:00
if(m_Input.GetString()[0])
Say(m_Mode == MODE_ALL ? 0 : 1, m_Input.GetString());
m_Mode = MODE_NONE;
m_pClient->OnRelease();
}
else
2010-05-29 07:25:38 +00:00
m_Input.ProcessInput(e);
return true;
}
2010-05-29 07:25:38 +00:00
void CChat::EnableMode(int Team)
{
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
return;
2010-05-29 07:25:38 +00:00
if(m_Mode == MODE_NONE)
{
2010-05-29 07:25:38 +00:00
if(Team)
m_Mode = MODE_TEAM;
else
2010-05-29 07:25:38 +00:00
m_Mode = MODE_ALL;
2010-05-29 07:25:38 +00:00
m_Input.Clear();
Input()->ClearEvents();
}
}
2010-05-29 07:25:38 +00:00
void CChat::OnMessage(int MsgType, void *pRawMsg)
{
2010-05-29 07:25:38 +00:00
if(MsgType == NETMSGTYPE_SV_CHAT)
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Chat *pMsg = (CNetMsg_Sv_Chat *)pRawMsg;
AddLine(pMsg->m_Cid, pMsg->m_Team, pMsg->m_pMessage);
}
}
2010-05-29 07:25:38 +00:00
void CChat::AddLine(int ClientId, int Team, const char *pLine)
{
if(ClientId != -1 && m_pClient->m_aClients[ClientId].m_aName[0] == '\0') // unknown client
return;
2010-05-29 07:25:38 +00:00
char *p = const_cast<char*>(pLine);
while(*p)
{
2010-05-29 07:25:38 +00:00
pLine = p;
// find line seperator and strip multiline
while(*p)
{
if(*p++ == '\n')
{
*(p-1) = 0;
break;
}
}
2010-05-29 07:25:38 +00:00
m_CurrentLine = (m_CurrentLine+1)%MAX_LINES;
m_aLines[m_CurrentLine].m_Time = time_get();
m_aLines[m_CurrentLine].m_ClientId = ClientId;
m_aLines[m_CurrentLine].m_Team = Team;
m_aLines[m_CurrentLine].m_NameColor = -2;
if(ClientId == -1) // server message
{
// Arrows
if(g_Config.m_ClArrows && (strstr(pLine, " entered and joined the ")
|| strstr(pLine, " has left the game") || strstr(pLine, " joined the ")))
{
str_copy(m_aLines[m_CurrentLine].m_aName, " ", sizeof(m_aLines[m_CurrentLine].m_aName));
}
else
str_copy(m_aLines[m_CurrentLine].m_aName, "*** ", sizeof(m_aLines[m_CurrentLine].m_aName));
2010-05-29 07:25:38 +00:00
str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), "%s", pLine);
}
else
{
2010-05-29 07:25:38 +00:00
if(m_pClient->m_aClients[ClientId].m_Team == -1)
m_aLines[m_CurrentLine].m_NameColor = -1;
if(m_pClient->m_Snap.m_pGameobj && m_pClient->m_Snap.m_pGameobj->m_Flags&GAMEFLAG_TEAMS)
{
if(m_pClient->m_aClients[ClientId].m_Team == 0)
m_aLines[m_CurrentLine].m_NameColor = 0;
else if(m_pClient->m_aClients[ClientId].m_Team == 1)
m_aLines[m_CurrentLine].m_NameColor = 1;
}
str_copy(m_aLines[m_CurrentLine].m_aName, m_pClient->m_aClients[ClientId].m_aName, sizeof(m_aLines[m_CurrentLine].m_aName));
str_format(m_aLines[m_CurrentLine].m_aText, sizeof(m_aLines[m_CurrentLine].m_aText), ": %s", pLine);
}
2010-05-29 07:25:38 +00:00
char aBuf[1024];
str_format(aBuf, sizeof(aBuf), "%s%s", m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chat", aBuf);
}
2010-05-29 07:25:38 +00:00
// play sound
2010-05-29 07:25:38 +00:00
if(ClientId >= 0)
m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_CLIENT, 0, vec2(0,0));
else
2010-05-29 07:25:38 +00:00
m_pClient->m_pSounds->Play(CSounds::CHN_GUI, SOUND_CHAT_SERVER, 0, vec2(0,0));
if (!m_ChatMoving) {
m_RenderLine = m_CurrentLine;
}
m_ChatMoving = false;
}
2010-05-29 07:25:38 +00:00
void CChat::OnRender()
{
2009-10-27 14:38:53 +00:00
Graphics()->MapScreen(0,0,300*Graphics()->ScreenAspect(),300);
float x = 10.0f;
2008-09-07 08:44:30 +00:00
float y = 300.0f-20.0f;
2010-05-29 07:25:38 +00:00
if(m_Mode != MODE_NONE)
{
// render chat input
2010-05-29 07:25:38 +00:00
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, x, y, 8.0f, TEXTFLAG_RENDER);
Cursor.m_LineWidth = 200.0f;
2010-05-29 07:25:38 +00:00
if(m_Mode == MODE_ALL)
TextRender()->TextEx(&Cursor, Localize("All"), -1);
else if(m_Mode == MODE_TEAM)
TextRender()->TextEx(&Cursor, Localize("Team"), -1);
else
2010-05-29 07:25:38 +00:00
TextRender()->TextEx(&Cursor, Localize("Chat"), -1);
2009-06-15 07:34:25 +00:00
2010-05-29 07:25:38 +00:00
TextRender()->TextEx(&Cursor, ": ", -1);
2010-05-29 07:25:38 +00:00
TextRender()->TextEx(&Cursor, m_Input.GetString(), m_Input.GetCursorOffset());
CTextCursor Marker = Cursor;
TextRender()->TextEx(&Marker, "|", -1);
TextRender()->TextEx(&Cursor, m_Input.GetString()+m_Input.GetCursorOffset(), -1);
}
y -= 8.0f;
2010-05-29 07:25:38 +00:00
int64 Now = time_get();
float LineWidth = m_pClient->m_pScoreboard->Active() ? 95.0f : 200.0f;
float HeightLimit = m_pClient->m_pScoreboard->Active() ? 220.0f : m_Show ? 50.0f : 200.0f;
for(int i = 0; i < MAX_LINES; i++)
{
int r = ((m_RenderLine-i)+MAX_LINES)%MAX_LINES;
if(!m_Show && !m_ChatMoving) {
if(Now > m_aLines[r].m_Time+15*time_freq())
break;
}
2010-05-29 07:25:38 +00:00
float Begin = x;
float FontSize = (float)g_Config.m_ClTextSize * 0.01f * 6.0f; // Text size factor
// get the y offset
2010-05-29 07:25:38 +00:00
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, Begin, 0, FontSize, 0);
Cursor.m_LineWidth = LineWidth;
2010-05-29 07:25:38 +00:00
TextRender()->TextEx(&Cursor, m_aLines[r].m_aName, -1);
TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1);
y -= Cursor.m_Y + Cursor.m_FontSize;
2008-09-07 08:44:30 +00:00
// cut off if msgs waste too much space
if(y < HeightLimit)
2008-09-07 08:44:30 +00:00
break;
// reset the cursor
2010-05-29 07:25:38 +00:00
TextRender()->SetCursor(&Cursor, Begin, y, FontSize, TEXTFLAG_RENDER);
Cursor.m_LineWidth = LineWidth;
// render name
CGameClient::CClientData currentData = m_pClient->m_aClients[m_aLines[r].m_ClientId];
TextRender()->TextColor(
(float)(m_PredefinedColors[m_aLines[r].m_ClientId].r)/255.0f,
(float)(m_PredefinedColors[m_aLines[r].m_ClientId].g)/255.0f,
(float)(m_PredefinedColors[m_aLines[r].m_ClientId].b)/255.0f,1);
//TextRender()->TextColor(0.8f,0.8f,0.8f,1);//TODO: add colors at this strigng;
2010-05-29 07:25:38 +00:00
if(m_aLines[r].m_ClientId == -1)
TextRender()->TextColor(1,1,0.5f,1); // system
else if(m_aLines[r].m_Team)
TextRender()->TextColor(0.45f,0.9f,0.45f,1); // team message
else if(m_aLines[r].m_NameColor == 0)
TextRender()->TextColor(1.0f,0.5f,0.5f,1); // red
else if(m_aLines[r].m_NameColor == 1)
TextRender()->TextColor(0.7f,0.7f,1.0f,1); // blue
else if(m_aLines[r].m_NameColor == -1)
TextRender()->TextColor(0.75f,0.5f,0.75f, 1); // spectator
// render name
2010-05-29 07:25:38 +00:00
TextRender()->TextEx(&Cursor, m_aLines[r].m_aName, -1);
// render line
2010-05-29 07:25:38 +00:00
TextRender()->TextColor(1,1,1,1);
if(m_aLines[r].m_ClientId == -1)
TextRender()->TextColor(1,1,0.5f,1); // system
else if(m_aLines[r].m_Team)
TextRender()->TextColor(0.65f,1,0.65f,1); // team message
const int txtsize = 12.0f*g_Config.m_ClTextSize/100;
// Arrows
if(g_Config.m_ClArrows && m_aLines[r].m_ClientId == -1)
{
if(strstr(m_aLines[r].m_aText, " entered and joined the ")) // Asrrows for entering the game
{
if(strstr(m_aLines[r].m_aText, "blue team"))
TextRender()->TextColor(0.7f,0.7f,1.0f,1); // blue
else if(strstr(m_aLines[r].m_aText, "red team"))
TextRender()->TextColor(1.0f,0.5f,0.5f,1); // red
else if(strstr(m_aLines[r].m_aText, "spectators"))
TextRender()->TextColor(0.80f,0.43f,0.80f, 1); // purple
else if(strstr(m_aLines[r].m_aText, "the game"))
TextRender()->TextColor(0.8f,0.8f,0.4f,1);
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_ARROWS].m_Id);
Graphics()->QuadsBegin();
RenderTools()->SelectSprite(SPRITE_ARROW_GREEN);
IGraphics::CQuadItem QuadItem(x+1, y-2+txtsize/2, 10, 10);
Graphics()->QuadsDraw(&QuadItem, 1);
Graphics()->QuadsEnd();
char str[256];
strcpy(str, m_aLines[r].m_aText);
strcpy(strstr(str , " entered and joined the "), " ");
TextRender()->TextEx(&Cursor, str, -1);
}
else if(strstr(m_aLines[r].m_aText, " has left the game")) // Dunedune arrows for quitting the game
{
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_ARROWS].m_Id);
TextRender()->TextColor(1.0f,0.57f,0.18f,1);
Graphics()->QuadsBegin();
RenderTools()->SelectSprite(SPRITE_ARROW_RED);
IGraphics::CQuadItem QuadItem(x+1, y-2+txtsize/2, 10, 10);
Graphics()->QuadsDraw(&QuadItem, 1);
Graphics()->QuadsEnd();
char str[256];
strcpy(str, m_aLines[r].m_aText);
strcpy(strstr(str , " has left the game"), " ");
TextRender()->TextEx(&Cursor, str, -1);
}
else if(strstr(m_aLines[r].m_aText, " joined the ")) // Dunedune arrows for switching team
{
int team = -1;
if(strstr(m_aLines[r].m_aText, "blue team"))
{
TextRender()->TextColor(0.7f,0.7f,1.0f,1);
team = 1;
}
else if(strstr(m_aLines[r].m_aText, "red team"))
{
TextRender()->TextColor(1.0f,0.5f,0.5f, 1);
team = 0;
}
else if(strstr(m_aLines[r].m_aText, "spectators"))
{
TextRender()->TextColor(0.80f,0.43f,0.80f, 1);
team = -1;
}
else if(strstr(m_aLines[r].m_aText, "the game"))
{
TextRender()->TextColor(0.8f,0.8f,0.4f,1);
team = 2;
}
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_ARROWS].m_Id);
Graphics()->QuadsBegin();
if(team == -1)
RenderTools()->SelectSprite(SPRITE_ARROW_SPEC);
else
{
if(team == 1)
RenderTools()->SelectSprite(SPRITE_ARROW_RIGHT);
else if (team == 2)
RenderTools()->SelectSprite(SPRITE_ARROW_JOIN);
else if(!team)
RenderTools()->SelectSprite(SPRITE_ARROW_LEFT);
else
RenderTools()->SelectSprite(SPRITE_ARROW_SPEC);
}
IGraphics::CQuadItem QuadItem(x+1, (team == 0 || team == 1) ? y-1+txtsize : y-2+txtsize/2, 10, 10);
Graphics()->QuadsDraw(&QuadItem, 1);
Graphics()->QuadsEnd();
char str[256];
strcpy(str, m_aLines[r].m_aText);
strcpy(strstr(str , " joined the "), " ");
TextRender()->TextEx(&Cursor, str, -1);
}
else
TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1);
}
else
TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1);
}
2010-05-29 07:25:38 +00:00
TextRender()->TextColor(1,1,1,1);
}
2010-05-29 07:25:38 +00:00
void CChat::Say(int Team, const char *pLine)
{
if(!str_comp_num(pLine, "/follow", 7) ) {
int Num;
if(sscanf(pLine, "/follow %d", &Num) == 1) {
m_pClient->m_pCamera->SetFollow(Num);
}
} else {
// send chat message
CNetMsg_Cl_Say Msg;
Msg.m_Team = Team;
Msg.m_pMessage = pLine;
Client()->SendPackMsg(&Msg, MSGFLAG_VITAL);
}
}