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