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