1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef GAME_CLIENT_COMPONENTS_CHAT_H
4#define GAME_CLIENT_COMPONENTS_CHAT_H
5
6#include <base/str.h>
7
8#include <engine/console.h>
9#include <engine/shared/config.h>
10#include <engine/shared/protocol.h>
11#include <engine/shared/ringbuffer.h>
12
13#include <generated/protocol7.h>
14
15#include <game/client/component.h>
16#include <game/client/lineinput.h>
17#include <game/client/render.h>
18
19#include <vector>
20
21constexpr auto SAVES_FILE = "ddnet-saves.txt";
22
23class CChat : public CComponent
24{
25 static constexpr float CHAT_HEIGHT_FULL = 200.0f;
26 static constexpr float CHAT_HEIGHT_MIN = 50.0f;
27 static constexpr float CHAT_FONTSIZE_WIDTH_RATIO = 2.5f;
28
29 enum
30 {
31 MAX_LINES = 64,
32 MAX_LINE_LENGTH = 256
33 };
34
35 CLineInputBuffered<MAX_LINE_LENGTH> m_Input;
36 class CLine
37 {
38 public:
39 CLine();
40 void Reset(CChat &This);
41
42 bool m_Initialized;
43 int64_t m_Time;
44 float m_aYOffset[2];
45 int m_ClientId;
46 int m_TeamNumber;
47 bool m_Team;
48 bool m_Whisper;
49 int m_NameColor;
50 char m_aName[64];
51 char m_aText[MAX_LINE_LENGTH];
52 bool m_Friend;
53 bool m_Highlighted;
54 std::optional<ColorRGBA> m_CustomColor;
55
56 STextContainerIndex m_TextContainerIndex;
57 int m_QuadContainerIndex;
58
59 std::shared_ptr<CManagedTeeRenderInfo> m_pManagedTeeRenderInfo;
60
61 float m_TextYOffset;
62
63 int m_TimesRepeated;
64 };
65
66 bool m_PrevScoreBoardShowed;
67 bool m_PrevShowChat;
68
69 CLine m_aLines[MAX_LINES];
70 int m_CurrentLine;
71
72 enum
73 {
74 // client IDs for special messages
75 CLIENT_MSG = -2,
76 SERVER_MSG = -1,
77 };
78
79 enum
80 {
81 MODE_NONE = 0,
82 MODE_ALL,
83 MODE_TEAM,
84 };
85
86 enum
87 {
88 CHAT_SERVER = 0,
89 CHAT_HIGHLIGHT,
90 CHAT_CLIENT,
91 CHAT_NUM,
92 };
93
94 int m_Mode;
95 bool m_Show;
96 bool m_CompletionUsed;
97 int m_CompletionChosen;
98 char m_aCompletionBuffer[MAX_LINE_LENGTH];
99 int m_PlaceholderOffset;
100 int m_PlaceholderLength;
101 static char ms_aDisplayText[MAX_LINE_LENGTH];
102 class CRateablePlayer
103 {
104 public:
105 int m_ClientId;
106 int m_Score;
107 };
108 CRateablePlayer m_aPlayerCompletionList[MAX_CLIENTS];
109 int m_PlayerCompletionListLength;
110
111 struct CCommand
112 {
113 char m_aName[IConsole::TEMPCMD_NAME_LENGTH];
114 char m_aParams[IConsole::TEMPCMD_PARAMS_LENGTH];
115 char m_aHelpText[IConsole::TEMPCMD_HELP_LENGTH];
116
117 CCommand() = default;
118 CCommand(const char *pName, const char *pParams, const char *pHelpText)
119 {
120 str_copy(dst&: m_aName, src: pName);
121 str_copy(dst&: m_aParams, src: pParams);
122 str_copy(dst&: m_aHelpText, src: pHelpText);
123 }
124
125 bool operator<(const CCommand &Other) const { return str_comp(a: m_aName, b: Other.m_aName) < 0; }
126 bool operator<=(const CCommand &Other) const { return str_comp(a: m_aName, b: Other.m_aName) <= 0; }
127 bool operator==(const CCommand &Other) const { return str_comp(a: m_aName, b: Other.m_aName) == 0; }
128 };
129
130 std::vector<CCommand> m_vServerCommands;
131 bool m_ServerCommandsNeedSorting;
132
133 struct CHistoryEntry
134 {
135 int m_Team;
136 char m_aText[1];
137 };
138 CHistoryEntry *m_pHistoryEntry;
139 CStaticRingBuffer<CHistoryEntry, 64 * 1024, CRingBufferBase::FLAG_RECYCLE> m_History;
140 int m_PendingChatCounter;
141 int64_t m_LastChatSend;
142 int64_t m_aLastSoundPlayed[CHAT_NUM];
143 bool m_IsInputCensored;
144 char m_aCurrentInputText[MAX_LINE_LENGTH];
145 bool m_EditingNewLine;
146
147 bool m_ServerSupportsCommandInfo;
148
149 static void ConSay(IConsole::IResult *pResult, void *pUserData);
150 static void ConSayTeam(IConsole::IResult *pResult, void *pUserData);
151 static void ConChat(IConsole::IResult *pResult, void *pUserData);
152 static void ConShowChat(IConsole::IResult *pResult, void *pUserData);
153 static void ConEcho(IConsole::IResult *pResult, void *pUserData);
154 static void ConClearChat(IConsole::IResult *pResult, void *pUserData);
155
156 static void ConchainChatOld(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
157 static void ConchainChatFontSize(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
158 static void ConchainChatWidth(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
159
160 bool LineShouldHighlight(const char *pLine, const char *pName);
161 void StoreSave(const char *pText);
162
163public:
164 CChat();
165 int Sizeof() const override { return sizeof(*this); }
166
167 static constexpr float MESSAGE_TEE_PADDING_RIGHT = 0.5f;
168
169 bool IsActive() const { return m_Mode != MODE_NONE; }
170 void AddLine(int ClientId, int Team, const char *pLine);
171 void EnableMode(int Team);
172 void DisableMode();
173 void RegisterCommand(const char *pName, const char *pParams, const char *pHelpText);
174 void UnregisterCommand(const char *pName);
175 void Echo(const char *pString);
176
177 void OnWindowResize() override;
178 void OnConsoleInit() override;
179 void OnStateChange(int NewState, int OldState) override;
180 void OnRender() override;
181 void OnPrepareLines(float y);
182 void Reset();
183 void OnRelease() override;
184 void OnMessage(int MsgType, void *pRawMsg) override;
185 bool OnInput(const IInput::CEvent &Event) override;
186 void OnInit() override;
187
188 void RebuildChat();
189 void ClearLines();
190
191 void EnsureCoherentFontSize() const;
192 void EnsureCoherentWidth() const;
193
194 float FontSize() const { return g_Config.m_ClChatFontSize / 10.0f; }
195 float MessagePaddingX() const { return FontSize() * (5 / 6.f); }
196 float MessagePaddingY() const { return FontSize() * (1 / 6.f); }
197 float MessageTeeSize() const { return FontSize() * (7 / 6.f); }
198 float MessageRounding() const { return FontSize() * (1 / 2.f); }
199
200 // ----- send functions -----
201
202 // Sends a chat message to the server.
203 //
204 // @param Team MODE_ALL=0 MODE_TEAM=1
205 // @param pLine the chat message
206 void SendChat(int Team, const char *pLine);
207
208 // Sends a chat message to the server.
209 //
210 // It uses a queue with a maximum of 3 entries
211 // that ensures there is a minimum delay of one second
212 // between sent messages.
213 //
214 // It uses team or public chat depending on m_Mode.
215 void SendChatQueued(const char *pLine);
216};
217#endif
218