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#include "menus.h"
4
5#include <base/str.h>
6
7#include <engine/graphics.h>
8#include <engine/shared/config.h>
9#include <engine/textrender.h>
10
11#include <generated/client_data.h>
12
13#include <game/client/animstate.h>
14#include <game/client/components/chat.h>
15#include <game/client/components/effects.h>
16#include <game/client/components/items.h>
17#include <game/client/components/mapimages.h>
18#include <game/client/components/nameplates.h>
19#include <game/client/components/skins.h>
20#include <game/client/components/tooltips.h>
21#include <game/client/gameclient.h>
22#include <game/client/skin.h>
23#include <game/client/ui.h>
24#include <game/client/ui_listbox.h>
25#include <game/client/ui_scrollregion.h>
26#include <game/localization.h>
27
28enum
29{
30 APPEARANCE_TAB_HUD = 0,
31 APPEARANCE_TAB_CHAT = 1,
32 APPEARANCE_TAB_NAME_PLATE = 2,
33 APPEARANCE_TAB_HOOK_COLLISION = 3,
34 APPEARANCE_TAB_INFO_MESSAGES = 4,
35 APPEARANCE_TAB_LASER = 5,
36 NUMBER_OF_APPEARANCE_TABS = 6,
37};
38
39void CMenus::RenderSettingsAppearance(CUIRect MainView)
40{
41 char aBuf[128];
42 static int s_CurTab = 0;
43
44 CUIRect TabBar, LeftView, RightView, Button;
45
46 MainView.HSplitTop(Cut: 20.0f, pTop: &TabBar, pBottom: &MainView);
47 const float TabWidth = TabBar.w / (float)NUMBER_OF_APPEARANCE_TABS;
48 static CButtonContainer s_aPageTabs[NUMBER_OF_APPEARANCE_TABS] = {};
49 const char *apTabNames[NUMBER_OF_APPEARANCE_TABS] = {
50 Localize(pStr: "HUD"),
51 Localize(pStr: "Chat"),
52 Localize(pStr: "Name Plate"),
53 Localize(pStr: "Hook Collisions"),
54 Localize(pStr: "Info Messages"),
55 Localize(pStr: "Laser")};
56
57 for(int Tab = APPEARANCE_TAB_HUD; Tab < NUMBER_OF_APPEARANCE_TABS; ++Tab)
58 {
59 TabBar.VSplitLeft(Cut: TabWidth, pLeft: &Button, pRight: &TabBar);
60 const int Corners = Tab == APPEARANCE_TAB_HUD ? IGraphics::CORNER_L : (Tab == NUMBER_OF_APPEARANCE_TABS - 1 ? IGraphics::CORNER_R : IGraphics::CORNER_NONE);
61 if(DoButton_MenuTab(pButtonContainer: &s_aPageTabs[Tab], pText: apTabNames[Tab], Checked: s_CurTab == Tab, pRect: &Button, Corners, pAnimator: nullptr, pDefaultColor: nullptr, pActiveColor: nullptr, pHoverColor: nullptr, EdgeRounding: 4.0f))
62 {
63 s_CurTab = Tab;
64 }
65 }
66
67 MainView.HSplitTop(Cut: 10.0f, pTop: nullptr, pBottom: &MainView);
68
69 const float LineSize = 20.0f;
70 const float ColorPickerLineSize = 25.0f;
71 const float HeadlineFontSize = 20.0f;
72 const float HeadlineHeight = 30.0f;
73 const float MarginSmall = 5.0f;
74 const float MarginBetweenViews = 20.0f;
75
76 const float ColorPickerLabelSize = 13.0f;
77 const float ColorPickerLineSpacing = 5.0f;
78
79 if(s_CurTab == APPEARANCE_TAB_HUD)
80 {
81 MainView.VSplitMid(pLeft: &LeftView, pRight: &RightView, Spacing: MarginBetweenViews);
82
83 // ***** HUD ***** //
84 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "HUD"), FontSize: HeadlineFontSize,
85 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
86 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
87
88 // Switch of the entire HUD
89 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhud, pText: Localize(pStr: "Show ingame HUD"), pValue: &g_Config.m_ClShowhud, pRect: &LeftView, VMargin: LineSize);
90
91 // Switches of the various normal HUD elements
92 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudHealthAmmo, pText: Localize(pStr: "Show health, shields and ammo"), pValue: &g_Config.m_ClShowhudHealthAmmo, pRect: &LeftView, VMargin: LineSize);
93 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudScore, pText: Localize(pStr: "Show score"), pValue: &g_Config.m_ClShowhudScore, pRect: &LeftView, VMargin: LineSize);
94 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowLocalTimeAlways, pText: Localize(pStr: "Show local time always"), pValue: &g_Config.m_ClShowLocalTimeAlways, pRect: &LeftView, VMargin: LineSize);
95 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClSpecCursor, pText: Localize(pStr: "Show spectator cursor"), pValue: &g_Config.m_ClSpecCursor, pRect: &LeftView, VMargin: LineSize);
96
97 // Settings of the HUD element for votes
98 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowVotesAfterVoting, pText: Localize(pStr: "Show votes window after voting"), pValue: &g_Config.m_ClShowVotesAfterVoting, pRect: &LeftView, VMargin: LineSize);
99
100 // ***** Scoreboard ***** //
101 LeftView.HSplitTop(Cut: MarginBetweenViews, pTop: nullptr, pBottom: &LeftView);
102 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Scoreboard"), FontSize: HeadlineFontSize,
103 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
104 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
105
106 ColorRGBA GreenDefault(0.78f, 1.0f, 0.8f, 1.0f);
107 static CButtonContainer s_AuthedColor, s_SameClanColor;
108 DoLine_ColorPicker(pResetId: &s_AuthedColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Authed name color in scoreboard"), pColorValue: &g_Config.m_ClAuthedPlayerColor, DefaultColor: GreenDefault, CheckBoxSpacing: false);
109 DoLine_ColorPicker(pResetId: &s_SameClanColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Same clan color in scoreboard"), pColorValue: &g_Config.m_ClSameClanColor, DefaultColor: GreenDefault, CheckBoxSpacing: false);
110
111 // ***** DDRace HUD ***** //
112 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "DDRace HUD"), FontSize: HeadlineFontSize,
113 Align: TEXTALIGN_ML, pRect: &RightView, LineSize: HeadlineHeight);
114 RightView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &RightView);
115
116 // Switches of various DDRace HUD elements
117 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowIds, pText: Localize(pStr: "Show client IDs (scoreboard, chat, spectator)"), pValue: &g_Config.m_ClShowIds, pRect: &RightView, VMargin: LineSize);
118 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudDDRace, pText: Localize(pStr: "Show DDRace HUD"), pValue: &g_Config.m_ClShowhudDDRace, pRect: &RightView, VMargin: LineSize);
119 if(g_Config.m_ClShowhudDDRace)
120 {
121 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudJumpsIndicator, pText: Localize(pStr: "Show jumps indicator"), pValue: &g_Config.m_ClShowhudJumpsIndicator, pRect: &RightView, VMargin: LineSize);
122 }
123 else
124 {
125 RightView.HSplitTop(Cut: LineSize, pTop: nullptr, pBottom: &RightView); // Create empty space for hidden option
126 }
127
128 // Eye with a number of spectators
129 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudSpectatorCount, pText: Localize(pStr: "Show number of spectators"), pValue: &g_Config.m_ClShowhudSpectatorCount, pRect: &RightView, VMargin: LineSize);
130
131 // Switch for dummy actions display
132 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudDummyActions, pText: Localize(pStr: "Show dummy actions"), pValue: &g_Config.m_ClShowhudDummyActions, pRect: &RightView, VMargin: LineSize);
133
134 // Player movement information display settings
135 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudPlayerPosition, pText: Localize(pStr: "Show player position"), pValue: &g_Config.m_ClShowhudPlayerPosition, pRect: &RightView, VMargin: LineSize);
136 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudPlayerSpeed, pText: Localize(pStr: "Show player speed"), pValue: &g_Config.m_ClShowhudPlayerSpeed, pRect: &RightView, VMargin: LineSize);
137 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowhudPlayerAngle, pText: Localize(pStr: "Show player target angle"), pValue: &g_Config.m_ClShowhudPlayerAngle, pRect: &RightView, VMargin: LineSize);
138
139 // Freeze bar settings
140 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowFreezeBars, pText: Localize(pStr: "Show freeze bars"), pValue: &g_Config.m_ClShowFreezeBars, pRect: &RightView, VMargin: LineSize);
141 RightView.HSplitTop(Cut: LineSize * 2.0f, pTop: &Button, pBottom: &RightView);
142 if(g_Config.m_ClShowFreezeBars)
143 {
144 Ui()->DoScrollbarOption(pId: &g_Config.m_ClFreezeBarsAlphaInsideFreeze, pOption: &g_Config.m_ClFreezeBarsAlphaInsideFreeze, pRect: &Button, pStr: Localize(pStr: "Opacity of freeze bars inside freeze"), Min: 0, Max: 100, pScale: &CUi::ms_LinearScrollbarScale, Flags: CUi::SCROLLBAR_OPTION_MULTILINE, pSuffix: "%");
145 }
146 }
147 else if(s_CurTab == APPEARANCE_TAB_CHAT)
148 {
149 CChat &Chat = GameClient()->m_Chat;
150 CUIRect TopView, PreviewView;
151 MainView.HSplitBottom(Cut: 220.0f, pTop: &TopView, pBottom: &PreviewView);
152 TopView.HSplitBottom(Cut: MarginBetweenViews, pTop: &TopView, pBottom: nullptr);
153 TopView.VSplitMid(pLeft: &LeftView, pRight: &RightView, Spacing: MarginBetweenViews);
154
155 // ***** Chat ***** //
156 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Chat"), FontSize: HeadlineFontSize,
157 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
158 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
159
160 // General chat settings
161 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
162 if(DoButton_CheckBox(pId: &g_Config.m_ClShowChat, pText: Localize(pStr: "Show chat"), Checked: g_Config.m_ClShowChat, pRect: &Button))
163 {
164 g_Config.m_ClShowChat = g_Config.m_ClShowChat ? 0 : 1;
165 }
166 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
167 if(g_Config.m_ClShowChat)
168 {
169 static int s_ShowChat = 0;
170 if(DoButton_CheckBox(pId: &s_ShowChat, pText: Localize(pStr: "Always show chat"), Checked: g_Config.m_ClShowChat == 2, pRect: &Button))
171 g_Config.m_ClShowChat = g_Config.m_ClShowChat != 2 ? 2 : 1;
172 }
173
174 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClChatTeamColors, pText: Localize(pStr: "Show names in chat in team colors"), pValue: &g_Config.m_ClChatTeamColors, pRect: &LeftView, VMargin: LineSize);
175 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowChatFriends, pText: Localize(pStr: "Show only chat messages from friends"), pValue: &g_Config.m_ClShowChatFriends, pRect: &LeftView, VMargin: LineSize);
176 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClShowChatTeamMembersOnly, pText: Localize(pStr: "Show only chat messages from team members"), pValue: &g_Config.m_ClShowChatTeamMembersOnly, pRect: &LeftView, VMargin: LineSize);
177
178 if(DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClChatOld, pText: Localize(pStr: "Use old chat style"), pValue: &g_Config.m_ClChatOld, pRect: &LeftView, VMargin: LineSize))
179 GameClient()->m_Chat.RebuildChat();
180
181 // DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClCensorChat, Localize("Censor profanity"), &g_Config.m_ClCensorChat, &LeftView, LineSize);
182
183 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
184 if(Ui()->DoScrollbarOption(pId: &g_Config.m_ClChatFontSize, pOption: &g_Config.m_ClChatFontSize, pRect: &Button, pStr: Localize(pStr: "Chat font size"), Min: 10, Max: 100))
185 {
186 Chat.EnsureCoherentWidth();
187 Chat.RebuildChat();
188 }
189
190 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
191 if(Ui()->DoScrollbarOption(pId: &g_Config.m_ClChatWidth, pOption: &g_Config.m_ClChatWidth, pRect: &Button, pStr: Localize(pStr: "Chat width"), Min: 120, Max: 400))
192 {
193 Chat.EnsureCoherentFontSize();
194 Chat.RebuildChat();
195 }
196
197 static CButtonContainer s_BackgroundColor;
198 DoLine_ColorPicker(pResetId: &s_BackgroundColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Chat background color"), pColorValue: &g_Config.m_ClChatBackgroundColor, DefaultColor: color_cast<ColorRGBA>(hsl: ColorHSLA(DefaultConfig::ClChatBackgroundColor, true)), CheckBoxSpacing: false, pCheckBoxValue: nullptr, Alpha: true);
199
200 // ***** Messages ***** //
201 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Messages"), FontSize: HeadlineFontSize,
202 Align: TEXTALIGN_ML, pRect: &RightView, LineSize: HeadlineHeight);
203 RightView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &RightView);
204
205 // Message Colors and extra settings
206 static CButtonContainer s_SystemMessageColor;
207 DoLine_ColorPicker(pResetId: &s_SystemMessageColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &RightView, pText: Localize(pStr: "System message"), pColorValue: &g_Config.m_ClMessageSystemColor, DefaultColor: ColorRGBA(1.0f, 1.0f, 0.5f), CheckBoxSpacing: true, pCheckBoxValue: &g_Config.m_ClShowChatSystem);
208 static CButtonContainer s_HighlightedMessageColor;
209 DoLine_ColorPicker(pResetId: &s_HighlightedMessageColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &RightView, pText: Localize(pStr: "Highlighted message"), pColorValue: &g_Config.m_ClMessageHighlightColor, DefaultColor: ColorRGBA(1.0f, 0.5f, 0.5f));
210 static CButtonContainer s_TeamMessageColor;
211 DoLine_ColorPicker(pResetId: &s_TeamMessageColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &RightView, pText: Localize(pStr: "Team message"), pColorValue: &g_Config.m_ClMessageTeamColor, DefaultColor: ColorRGBA(0.65f, 1.0f, 0.65f));
212 static CButtonContainer s_FriendMessageColor;
213 DoLine_ColorPicker(pResetId: &s_FriendMessageColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &RightView, pText: Localize(pStr: "Friend message"), pColorValue: &g_Config.m_ClMessageFriendColor, DefaultColor: ColorRGBA(1.0f, 0.137f, 0.137f), CheckBoxSpacing: true, pCheckBoxValue: &g_Config.m_ClMessageFriend);
214 static CButtonContainer s_NormalMessageColor;
215 DoLine_ColorPicker(pResetId: &s_NormalMessageColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &RightView, pText: Localize(pStr: "Normal message"), pColorValue: &g_Config.m_ClMessageColor, DefaultColor: ColorRGBA(1.0f, 1.0f, 1.0f));
216
217 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s (echo)", Localize(pStr: "Client message"));
218 static CButtonContainer s_ClientMessageColor;
219 DoLine_ColorPicker(pResetId: &s_ClientMessageColor, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &RightView, pText: aBuf, pColorValue: &g_Config.m_ClMessageClientColor, DefaultColor: ColorRGBA(0.5f, 0.78f, 1.0f));
220
221 // ***** Chat Preview ***** //
222 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Preview"), FontSize: HeadlineFontSize,
223 Align: TEXTALIGN_ML, pRect: &PreviewView, LineSize: HeadlineHeight);
224 PreviewView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &PreviewView);
225
226 // Use the rest of the view for preview
227 PreviewView.Draw(Color: ColorRGBA(1, 1, 1, 0.1f), Corners: IGraphics::CORNER_ALL, Rounding: 5.0f);
228 PreviewView.Margin(Cut: MarginSmall, pOtherRect: &PreviewView);
229
230 ColorRGBA SystemColor = color_cast<ColorRGBA, ColorHSLA>(hsl: ColorHSLA(g_Config.m_ClMessageSystemColor));
231 ColorRGBA HighlightedColor = color_cast<ColorRGBA, ColorHSLA>(hsl: ColorHSLA(g_Config.m_ClMessageHighlightColor));
232 ColorRGBA TeamColor = color_cast<ColorRGBA, ColorHSLA>(hsl: ColorHSLA(g_Config.m_ClMessageTeamColor));
233 ColorRGBA FriendColor = color_cast<ColorRGBA, ColorHSLA>(hsl: ColorHSLA(g_Config.m_ClMessageFriendColor));
234 ColorRGBA NormalColor = color_cast<ColorRGBA, ColorHSLA>(hsl: ColorHSLA(g_Config.m_ClMessageColor));
235 ColorRGBA ClientColor = color_cast<ColorRGBA, ColorHSLA>(hsl: ColorHSLA(g_Config.m_ClMessageClientColor));
236 ColorRGBA DefaultNameColor(0.8f, 0.8f, 0.8f, 1.0f);
237
238 const float RealFontSize = Chat.FontSize() * 2;
239 const float RealMsgPaddingX = (!g_Config.m_ClChatOld ? Chat.MessagePaddingX() : 0) * 2;
240 const float RealMsgPaddingY = (!g_Config.m_ClChatOld ? Chat.MessagePaddingY() : 0) * 2;
241 const float RealMsgPaddingTee = (!g_Config.m_ClChatOld ? Chat.MessageTeeSize() + CChat::MESSAGE_TEE_PADDING_RIGHT : 0) * 2;
242 const float RealOffsetY = RealFontSize + RealMsgPaddingY;
243
244 const float X = RealMsgPaddingX / 2.0f + PreviewView.x;
245 float Y = PreviewView.y;
246 float LineWidth = g_Config.m_ClChatWidth * 2 - (RealMsgPaddingX * 1.5f) - RealMsgPaddingTee;
247
248 str_copy(dst&: aBuf, src: Client()->PlayerName());
249
250 const CAnimState *pIdleState = CAnimState::GetIdle();
251 const float RealTeeSize = Chat.MessageTeeSize() * 2;
252 const float RealTeeSizeHalved = Chat.MessageTeeSize();
253 constexpr float TWSkinUnreliableOffset = -0.25f;
254 const float OffsetTeeY = RealTeeSizeHalved;
255 const float FullHeightMinusTee = RealOffsetY - RealTeeSize;
256
257 struct SPreviewLine
258 {
259 int m_ClientId;
260 bool m_Team;
261 char m_aName[64];
262 char m_aText[256];
263 bool m_Friend;
264 bool m_Player;
265 bool m_Client;
266 bool m_Highlighted;
267 int m_TimesRepeated;
268
269 CTeeRenderInfo m_RenderInfo;
270 };
271
272 static std::vector<SPreviewLine> s_vLines;
273
274 enum ELineFlag
275 {
276 FLAG_TEAM = 1 << 0,
277 FLAG_FRIEND = 1 << 1,
278 FLAG_HIGHLIGHT = 1 << 2,
279 FLAG_CLIENT = 1 << 3
280 };
281 enum
282 {
283 PREVIEW_SYS,
284 PREVIEW_HIGHLIGHT,
285 PREVIEW_TEAM,
286 PREVIEW_FRIEND,
287 PREVIEW_SPAMMER,
288 PREVIEW_CLIENT
289 };
290 auto &&SetPreviewLine = [](int Index, int ClientId, const char *pName, const char *pText, int Flag, int Repeats) {
291 SPreviewLine *pLine;
292 if((int)s_vLines.size() <= Index)
293 {
294 s_vLines.emplace_back();
295 pLine = &s_vLines.back();
296 }
297 else
298 {
299 pLine = &s_vLines[Index];
300 }
301 pLine->m_ClientId = ClientId;
302 pLine->m_Team = Flag & FLAG_TEAM;
303 pLine->m_Friend = Flag & FLAG_FRIEND;
304 pLine->m_Player = ClientId >= 0;
305 pLine->m_Highlighted = Flag & FLAG_HIGHLIGHT;
306 pLine->m_Client = Flag & FLAG_CLIENT;
307 pLine->m_TimesRepeated = Repeats;
308 str_copy(dst&: pLine->m_aName, src: pName);
309 str_copy(dst&: pLine->m_aText, src: pText);
310 };
311 auto &&SetLineSkin = [RealTeeSize](int Index, const CSkin *pSkin) {
312 if(Index >= (int)s_vLines.size())
313 return;
314 s_vLines[Index].m_RenderInfo.m_Size = RealTeeSize;
315 s_vLines[Index].m_RenderInfo.Apply(pSkin);
316 };
317
318 auto &&RenderPreview = [&](int LineIndex, int x, int y, bool Render = true) {
319 if(LineIndex >= (int)s_vLines.size())
320 return vec2(0, 0);
321 CTextCursor LocalCursor;
322 LocalCursor.SetPosition(vec2(x, y));
323 LocalCursor.m_FontSize = RealFontSize;
324 LocalCursor.m_Flags = Render ? TEXTFLAG_RENDER : 0;
325 LocalCursor.m_LineWidth = LineWidth;
326 const auto &Line = s_vLines[LineIndex];
327
328 char aClientId[16] = "";
329 if(g_Config.m_ClShowIds && Line.m_ClientId >= 0 && Line.m_aName[0] != '\0')
330 {
331 GameClient()->FormatClientId(ClientId: Line.m_ClientId, aClientId, Format: EClientIdFormat::INDENT_FORCE);
332 }
333
334 char aCount[12];
335 if(Line.m_ClientId < 0)
336 str_format(buffer: aCount, buffer_size: sizeof(aCount), format: "[%d] ", Line.m_TimesRepeated + 1);
337 else
338 str_format(buffer: aCount, buffer_size: sizeof(aCount), format: " [%d]", Line.m_TimesRepeated + 1);
339
340 if(Line.m_Player)
341 {
342 LocalCursor.m_X += RealMsgPaddingTee;
343
344 if(Line.m_Friend && g_Config.m_ClMessageFriend)
345 {
346 if(Render)
347 TextRender()->TextColor(Color: FriendColor);
348 TextRender()->TextEx(pCursor: &LocalCursor, pText: "♥ ", Length: -1);
349 }
350 }
351
352 ColorRGBA NameColor;
353 if(Line.m_Team)
354 NameColor = CalculateNameColor(TextColorHSL: color_cast<ColorHSLA>(rgb: TeamColor));
355 else if(Line.m_Player)
356 NameColor = DefaultNameColor;
357 else if(Line.m_Client)
358 NameColor = ClientColor;
359 else
360 NameColor = SystemColor;
361
362 if(Render)
363 TextRender()->TextColor(Color: NameColor);
364
365 TextRender()->TextEx(pCursor: &LocalCursor, pText: aClientId);
366 TextRender()->TextEx(pCursor: &LocalCursor, pText: Line.m_aName);
367
368 if(Line.m_TimesRepeated > 0)
369 {
370 if(Render)
371 TextRender()->TextColor(r: 1.0f, g: 1.0f, b: 1.0f, a: 0.3f);
372 TextRender()->TextEx(pCursor: &LocalCursor, pText: aCount, Length: -1);
373 }
374
375 if(Line.m_ClientId >= 0 && Line.m_aName[0] != '\0')
376 {
377 if(Render)
378 TextRender()->TextColor(Color: NameColor);
379 TextRender()->TextEx(pCursor: &LocalCursor, pText: ": ", Length: -1);
380 }
381
382 CTextCursor AppendCursor = LocalCursor;
383 AppendCursor.m_LongestLineWidth = 0.0f;
384 if(!g_Config.m_ClChatOld)
385 {
386 AppendCursor.m_StartX = LocalCursor.m_X;
387 AppendCursor.m_LineWidth -= LocalCursor.m_LongestLineWidth;
388 }
389
390 if(Render)
391 {
392 if(Line.m_Highlighted)
393 TextRender()->TextColor(Color: HighlightedColor);
394 else if(Line.m_Team)
395 TextRender()->TextColor(Color: TeamColor);
396 else if(Line.m_Player)
397 TextRender()->TextColor(Color: NormalColor);
398 }
399
400 TextRender()->TextEx(pCursor: &AppendCursor, pText: Line.m_aText, Length: -1);
401 if(Render)
402 TextRender()->TextColor(Color: TextRender()->DefaultTextColor());
403
404 return vec2{LocalCursor.m_LongestLineWidth + AppendCursor.m_LongestLineWidth, AppendCursor.Height() + RealMsgPaddingY};
405 };
406
407 // Set preview lines
408 {
409 char aLineBuilder[128];
410
411 str_format(buffer: aLineBuilder, buffer_size: sizeof(aLineBuilder), format: "'%s' entered and joined the game", aBuf);
412 SetPreviewLine(PREVIEW_SYS, -1, "*** ", aLineBuilder, 0, 0);
413
414 str_format(buffer: aLineBuilder, buffer_size: sizeof(aLineBuilder), format: "Hey, how are you %s?", aBuf);
415 SetPreviewLine(PREVIEW_HIGHLIGHT, 7, "Random Tee", aLineBuilder, FLAG_HIGHLIGHT, 0);
416
417 SetPreviewLine(PREVIEW_TEAM, 11, "Your Teammate", "Let's speedrun this!", FLAG_TEAM, 0);
418 SetPreviewLine(PREVIEW_FRIEND, 8, "Friend", "Hello there", FLAG_FRIEND, 0);
419 SetPreviewLine(PREVIEW_SPAMMER, 9, "Spammer", "Hey fools, I'm spamming here!", 0, 5);
420 SetPreviewLine(PREVIEW_CLIENT, -1, "— ", "Echo command executed", FLAG_CLIENT, 0);
421 }
422
423 SetLineSkin(1, GameClient()->m_Skins.Find(pName: "pinky"));
424 SetLineSkin(2, GameClient()->m_Skins.Find(pName: "default"));
425 SetLineSkin(3, GameClient()->m_Skins.Find(pName: "cammostripes"));
426 SetLineSkin(4, GameClient()->m_Skins.Find(pName: "beast"));
427
428 // Backgrounds first
429 if(!g_Config.m_ClChatOld)
430 {
431 Graphics()->TextureClear();
432 Graphics()->QuadsBegin();
433 Graphics()->SetColor(color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClChatBackgroundColor, true)));
434
435 float TempY = Y;
436 const float RealBackgroundRounding = Chat.MessageRounding() * 2.0f;
437
438 auto &&RenderMessageBackground = [&](int LineIndex) {
439 auto Size = RenderPreview(LineIndex, 0, 0, false);
440 Graphics()->DrawRectExt(x: X - RealMsgPaddingX / 2.0f, y: TempY - RealMsgPaddingY / 2.0f, w: Size.x + RealMsgPaddingX * 1.5f, h: Size.y, r: RealBackgroundRounding, Corners: IGraphics::CORNER_ALL);
441 return Size.y;
442 };
443
444 if(g_Config.m_ClShowChatSystem)
445 {
446 TempY += RenderMessageBackground(PREVIEW_SYS);
447 }
448
449 if(!g_Config.m_ClShowChatFriends)
450 {
451 if(!g_Config.m_ClShowChatTeamMembersOnly)
452 TempY += RenderMessageBackground(PREVIEW_HIGHLIGHT);
453 TempY += RenderMessageBackground(PREVIEW_TEAM);
454 }
455
456 if(!g_Config.m_ClShowChatTeamMembersOnly)
457 TempY += RenderMessageBackground(PREVIEW_FRIEND);
458
459 if(!g_Config.m_ClShowChatFriends && !g_Config.m_ClShowChatTeamMembersOnly)
460 {
461 TempY += RenderMessageBackground(PREVIEW_SPAMMER);
462 }
463
464 TempY += RenderMessageBackground(PREVIEW_CLIENT);
465
466 Graphics()->QuadsEnd();
467 }
468
469 // System
470 if(g_Config.m_ClShowChatSystem)
471 {
472 Y += RenderPreview(PREVIEW_SYS, X, Y).y;
473 }
474
475 if(!g_Config.m_ClShowChatFriends)
476 {
477 // Highlighted
478 if(!g_Config.m_ClChatOld && !g_Config.m_ClShowChatTeamMembersOnly)
479 RenderTools()->RenderTee(pAnim: pIdleState, pInfo: &s_vLines[PREVIEW_HIGHLIGHT].m_RenderInfo, Emote: EMOTE_NORMAL, Dir: vec2(1, 0.1f), Pos: vec2(X + RealTeeSizeHalved, Y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset));
480 if(!g_Config.m_ClShowChatTeamMembersOnly)
481 Y += RenderPreview(PREVIEW_HIGHLIGHT, X, Y).y;
482
483 // Team
484 if(!g_Config.m_ClChatOld)
485 RenderTools()->RenderTee(pAnim: pIdleState, pInfo: &s_vLines[PREVIEW_TEAM].m_RenderInfo, Emote: EMOTE_NORMAL, Dir: vec2(1, 0.1f), Pos: vec2(X + RealTeeSizeHalved, Y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset));
486 Y += RenderPreview(PREVIEW_TEAM, X, Y).y;
487 }
488
489 // Friend
490 if(!g_Config.m_ClChatOld && !g_Config.m_ClShowChatTeamMembersOnly)
491 RenderTools()->RenderTee(pAnim: pIdleState, pInfo: &s_vLines[PREVIEW_FRIEND].m_RenderInfo, Emote: EMOTE_NORMAL, Dir: vec2(1, 0.1f), Pos: vec2(X + RealTeeSizeHalved, Y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset));
492 if(!g_Config.m_ClShowChatTeamMembersOnly)
493 Y += RenderPreview(PREVIEW_FRIEND, X, Y).y;
494
495 // Normal
496 if(!g_Config.m_ClShowChatFriends && !g_Config.m_ClShowChatTeamMembersOnly)
497 {
498 if(!g_Config.m_ClChatOld)
499 RenderTools()->RenderTee(pAnim: pIdleState, pInfo: &s_vLines[PREVIEW_SPAMMER].m_RenderInfo, Emote: EMOTE_NORMAL, Dir: vec2(1, 0.1f), Pos: vec2(X + RealTeeSizeHalved, Y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset));
500 Y += RenderPreview(PREVIEW_SPAMMER, X, Y).y;
501 }
502 // Client
503 RenderPreview(PREVIEW_CLIENT, X, Y);
504
505 TextRender()->TextColor(Color: TextRender()->DefaultTextColor());
506 }
507 else if(s_CurTab == APPEARANCE_TAB_NAME_PLATE)
508 {
509 MainView.VSplitMid(pLeft: &LeftView, pRight: &RightView, Spacing: MarginBetweenViews);
510
511 // ***** Name Plate ***** //
512 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Name Plate"), FontSize: HeadlineFontSize,
513 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
514 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
515
516 // General name plate settings
517 {
518 int Pressed = (g_Config.m_ClNamePlates ? 2 : 0) + (g_Config.m_ClNamePlatesOwn ? 1 : 0);
519 if(DoLine_RadioMenu(View&: LeftView, pLabel: Localize(pStr: "Show name plates"),
520 vButtonContainers&: m_vButtonContainersNamePlateShow,
521 vLabels: {Localize(pStr: "None", pContext: "Show name plates"), Localize(pStr: "Own", pContext: "Show name plates"), Localize(pStr: "Others", pContext: "Show name plates"), Localize(pStr: "All", pContext: "Show name plates")},
522 vValues: {0, 1, 2, 3},
523 Value&: Pressed))
524 {
525 g_Config.m_ClNamePlates = Pressed & 2 ? 1 : 0;
526 g_Config.m_ClNamePlatesOwn = Pressed & 1 ? 1 : 0;
527 }
528 }
529 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
530 Ui()->DoScrollbarOption(pId: &g_Config.m_ClNamePlatesSize, pOption: &g_Config.m_ClNamePlatesSize, pRect: &Button, pStr: Localize(pStr: "Name plates size"), Min: -50, Max: 100);
531 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
532 Ui()->DoScrollbarOption(pId: &g_Config.m_ClNamePlatesOffset, pOption: &g_Config.m_ClNamePlatesOffset, pRect: &Button, pStr: Localize(pStr: "Name plates offset"), Min: 10, Max: 50);
533
534 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClNamePlatesClan, pText: Localize(pStr: "Show clan above name plates"), pValue: &g_Config.m_ClNamePlatesClan, pRect: &LeftView, VMargin: LineSize);
535 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
536 if(g_Config.m_ClNamePlatesClan)
537 Ui()->DoScrollbarOption(pId: &g_Config.m_ClNamePlatesClanSize, pOption: &g_Config.m_ClNamePlatesClanSize, pRect: &Button, pStr: Localize(pStr: "Clan plates size"), Min: -50, Max: 100);
538
539 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClNamePlatesTeamcolors, pText: Localize(pStr: "Use team colors for name plates"), pValue: &g_Config.m_ClNamePlatesTeamcolors, pRect: &LeftView, VMargin: LineSize);
540 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClNamePlatesFriendMark, pText: Localize(pStr: "Show friend icon in name plates"), pValue: &g_Config.m_ClNamePlatesFriendMark, pRect: &LeftView, VMargin: LineSize);
541
542 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClNamePlatesIds, pText: Localize(pStr: "Show client IDs in name plates"), pValue: &g_Config.m_ClNamePlatesIds, pRect: &LeftView, VMargin: LineSize);
543 if(g_Config.m_ClNamePlatesIds > 0)
544 DoButton_CheckBoxAutoVMarginAndSet(pId: &g_Config.m_ClNamePlatesIdsSeparateLine, pText: Localize(pStr: "Show client IDs on a separate line"), pValue: &g_Config.m_ClNamePlatesIdsSeparateLine, pRect: &LeftView, VMargin: LineSize);
545 else
546 LeftView.HSplitTop(Cut: LineSize, pTop: nullptr, pBottom: &LeftView);
547 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
548 if(g_Config.m_ClNamePlatesIds > 0 && g_Config.m_ClNamePlatesIdsSeparateLine > 0)
549 Ui()->DoScrollbarOption(pId: &g_Config.m_ClNamePlatesIdsSize, pOption: &g_Config.m_ClNamePlatesIdsSize, pRect: &Button, pStr: Localize(pStr: "Client IDs size"), Min: -50, Max: 100);
550
551 // ***** Hook Strength ***** //
552 LeftView.HSplitTop(Cut: MarginBetweenViews, pTop: nullptr, pBottom: &LeftView);
553 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Hook Strength"), FontSize: HeadlineFontSize,
554 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
555 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
556
557 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
558 if(DoButton_CheckBox(pId: &g_Config.m_ClNamePlatesStrong, pText: Localize(pStr: "Show hook strength icon indicator"), Checked: g_Config.m_ClNamePlatesStrong, pRect: &Button))
559 {
560 g_Config.m_ClNamePlatesStrong = g_Config.m_ClNamePlatesStrong ? 0 : 1;
561 }
562 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
563 if(g_Config.m_ClNamePlatesStrong)
564 {
565 static int s_NamePlatesStrong = 0;
566 if(DoButton_CheckBox(pId: &s_NamePlatesStrong, pText: Localize(pStr: "Show hook strength number indicator"), Checked: g_Config.m_ClNamePlatesStrong == 2, pRect: &Button))
567 g_Config.m_ClNamePlatesStrong = g_Config.m_ClNamePlatesStrong != 2 ? 2 : 1;
568 }
569
570 LeftView.HSplitTop(Cut: LineSize * 2.0f, pTop: &Button, pBottom: &LeftView);
571 if(g_Config.m_ClNamePlatesStrong)
572 {
573 Ui()->DoScrollbarOption(pId: &g_Config.m_ClNamePlatesStrongSize, pOption: &g_Config.m_ClNamePlatesStrongSize, pRect: &Button, pStr: Localize(pStr: "Size of hook strength icon and number indicator"), Min: -50, Max: 100, pScale: &CUi::ms_LinearScrollbarScale, Flags: CUi::SCROLLBAR_OPTION_MULTILINE);
574 }
575
576 // ***** Key Presses ***** //
577 LeftView.HSplitTop(Cut: MarginBetweenViews, pTop: nullptr, pBottom: &LeftView);
578 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Key Presses"), FontSize: HeadlineFontSize,
579 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
580 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
581
582 DoLine_RadioMenu(View&: LeftView, pLabel: Localize(pStr: "Show players' key presses"),
583 vButtonContainers&: m_vButtonContainersNamePlateKeyPresses,
584 vLabels: {Localize(pStr: "None", pContext: "Show players' key presses"), Localize(pStr: "Own", pContext: "Show players' key presses"), Localize(pStr: "Others", pContext: "Show players' key presses"), Localize(pStr: "All", pContext: "Show players' key presses")},
585 vValues: {0, 3, 1, 2},
586 Value&: g_Config.m_ClShowDirection);
587
588 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
589 if(g_Config.m_ClShowDirection > 0)
590 Ui()->DoScrollbarOption(pId: &g_Config.m_ClDirectionSize, pOption: &g_Config.m_ClDirectionSize, pRect: &Button, pStr: Localize(pStr: "Size of key press icons"), Min: -50, Max: 100);
591
592 // ***** Name Plate Preview ***** //
593 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Preview"), FontSize: HeadlineFontSize,
594 Align: TEXTALIGN_ML, pRect: &RightView, LineSize: HeadlineHeight);
595 RightView.HSplitTop(Cut: 2.0f * MarginSmall, pTop: nullptr, pBottom: &RightView);
596
597 // ***** Name Plate Dummy Preview ***** //
598 RightView.HSplitBottom(Cut: LineSize, pTop: &RightView, pBottom: &Button);
599 if(DoButton_CheckBox(pId: &m_DummyNamePlatePreview, pText: g_Config.m_ClDummy ? Localize(pStr: "Preview player's name plate") : Localize(pStr: "Preview dummy's name plate"), Checked: m_DummyNamePlatePreview, pRect: &Button))
600 m_DummyNamePlatePreview = !m_DummyNamePlatePreview;
601
602 int Dummy = g_Config.m_ClDummy != (m_DummyNamePlatePreview ? 1 : 0);
603
604 const vec2 Position = RightView.Center();
605
606 GameClient()->m_NamePlates.RenderNamePlatePreview(Position, Dummy);
607 }
608 else if(s_CurTab == APPEARANCE_TAB_HOOK_COLLISION)
609 {
610 MainView.VSplitMid(pLeft: &LeftView, pRight: &RightView, Spacing: MarginBetweenViews);
611
612 // ***** Hookline ***** //
613 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Hook collision line"), FontSize: HeadlineFontSize,
614 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
615 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
616
617 // General hookline settings
618 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
619 if(DoButton_CheckBox(pId: &g_Config.m_ClShowHookCollOwn, pText: Localize(pStr: "Show own player's hook collision line"), Checked: g_Config.m_ClShowHookCollOwn, pRect: &Button))
620 {
621 g_Config.m_ClShowHookCollOwn = g_Config.m_ClShowHookCollOwn ? 0 : 1;
622 }
623 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
624 if(g_Config.m_ClShowHookCollOwn)
625 {
626 static int s_ShowHookCollOwn = 0;
627 if(DoButton_CheckBox(pId: &s_ShowHookCollOwn, pText: Localize(pStr: "Always show own player's hook collision line"), Checked: g_Config.m_ClShowHookCollOwn == 2, pRect: &Button))
628 g_Config.m_ClShowHookCollOwn = g_Config.m_ClShowHookCollOwn != 2 ? 2 : 1;
629 }
630
631 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
632 if(DoButton_CheckBox(pId: &g_Config.m_ClShowHookCollOther, pText: Localize(pStr: "Show other players' hook collision lines"), Checked: g_Config.m_ClShowHookCollOther, pRect: &Button))
633 {
634 g_Config.m_ClShowHookCollOther = g_Config.m_ClShowHookCollOther >= 1 ? 0 : 1;
635 }
636 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
637 if(g_Config.m_ClShowHookCollOther)
638 {
639 static int s_ShowHookCollOther = 0;
640 if(DoButton_CheckBox(pId: &s_ShowHookCollOther, pText: Localize(pStr: "Always show other players' hook collision lines"), Checked: g_Config.m_ClShowHookCollOther == 2, pRect: &Button))
641 g_Config.m_ClShowHookCollOther = g_Config.m_ClShowHookCollOther != 2 ? 2 : 1;
642 }
643
644 LeftView.HSplitTop(Cut: LineSize * 2.0f, pTop: &Button, pBottom: &LeftView);
645 Ui()->DoScrollbarOption(pId: &g_Config.m_ClHookCollSize, pOption: &g_Config.m_ClHookCollSize, pRect: &Button, pStr: Localize(pStr: "Width of your own hook collision line"), Min: 0, Max: 20, pScale: &CUi::ms_LinearScrollbarScale, Flags: CUi::SCROLLBAR_OPTION_MULTILINE);
646
647 LeftView.HSplitTop(Cut: LineSize * 2.0f, pTop: &Button, pBottom: &LeftView);
648 Ui()->DoScrollbarOption(pId: &g_Config.m_ClHookCollSizeOther, pOption: &g_Config.m_ClHookCollSizeOther, pRect: &Button, pStr: Localize(pStr: "Width of others' hook collision line"), Min: 0, Max: 20, pScale: &CUi::ms_LinearScrollbarScale, Flags: CUi::SCROLLBAR_OPTION_MULTILINE);
649
650 LeftView.HSplitTop(Cut: LineSize * 2.0f, pTop: &Button, pBottom: &LeftView);
651 Ui()->DoScrollbarOption(pId: &g_Config.m_ClHookCollAlpha, pOption: &g_Config.m_ClHookCollAlpha, pRect: &Button, pStr: Localize(pStr: "Hook collision line opacity"), Min: 0, Max: 100, pScale: &CUi::ms_LinearScrollbarScale, Flags: CUi::SCROLLBAR_OPTION_MULTILINE, pSuffix: "%");
652
653 static CButtonContainer s_HookCollNoCollResetId, s_HookCollHookableCollResetId, s_HookCollTeeCollResetId, s_HookCollTipColorResetId;
654 static int s_HookCollToolTip;
655
656 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Colors of the hook collision line:"), FontSize: 13.0f,
657 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
658
659 Ui()->DoButtonLogic(pId: &s_HookCollToolTip, Checked: 0, pRect: &LeftView, Flags: BUTTONFLAG_NONE); // Just for the tooltip, result ignored
660 GameClient()->m_Tooltips.DoToolTip(pId: &s_HookCollToolTip, pNearRect: &LeftView, pText: Localize(pStr: "Your movements are not taken into account when calculating the line colors"));
661 DoLine_ColorPicker(pResetId: &s_HookCollNoCollResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "When nothing is hookable", pContext: "Hook collision line color"), pColorValue: &g_Config.m_ClHookCollColorNoColl, DefaultColor: ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f), CheckBoxSpacing: false);
662 DoLine_ColorPicker(pResetId: &s_HookCollHookableCollResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "When something is hookable", pContext: "Hook collision line color"), pColorValue: &g_Config.m_ClHookCollColorHookableColl, DefaultColor: ColorRGBA(130.0f / 255.0f, 232.0f / 255.0f, 160.0f / 255.0f, 1.0f), CheckBoxSpacing: false);
663 DoLine_ColorPicker(pResetId: &s_HookCollTeeCollResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "When a Tee is hookable", pContext: "Hook collision line color"), pColorValue: &g_Config.m_ClHookCollColorTeeColl, DefaultColor: ColorRGBA(1.0f, 1.0f, 0.0f, 1.0f), CheckBoxSpacing: false);
664 DoLine_ColorPicker(pResetId: &s_HookCollTipColorResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Hook collision line tip", pContext: "Hook collision line color"), pColorValue: &g_Config.m_ClHookCollTipColor, DefaultColor: ColorRGBA(1.0f, 1.0f, 0.0f, 0.5f), CheckBoxSpacing: false, pCheckBoxValue: nullptr, Alpha: true);
665
666 // ***** Hook collisions preview ***** //
667 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Preview"), FontSize: HeadlineFontSize,
668 Align: TEXTALIGN_ML, pRect: &RightView, LineSize: HeadlineHeight);
669 RightView.HSplitTop(Cut: 2 * MarginSmall, pTop: nullptr, pBottom: &RightView);
670
671 auto DoHookCollision = [this](const vec2 &Pos, const float &Length, const int &Size, const ColorRGBA &Color, const ColorRGBA &TipColor, const bool &Invert) {
672 ColorRGBA ColorModified = Color;
673 ColorRGBA TipColorModified = TipColor;
674 if(Invert)
675 ColorModified = color_invert(col: ColorModified);
676 ColorModified = ColorModified.WithAlpha(alpha: (float)g_Config.m_ClHookCollAlpha / 100);
677 TipColorModified = TipColor.WithMultipliedAlpha(alpha: (float)g_Config.m_ClHookCollAlpha / 100);
678 Graphics()->TextureClear();
679 if(Size > 0)
680 {
681 Graphics()->QuadsBegin();
682 Graphics()->SetColor(ColorModified);
683 float LineWidth = 0.5f + (float)(Size - 1) * 0.25f;
684 IGraphics::CQuadItem QuadItem(Pos.x, Pos.y - LineWidth, Length, LineWidth * 2.f);
685 Graphics()->QuadsDrawTL(pArray: &QuadItem, Num: 1);
686 if(TipColor.a > 0.0f)
687 {
688 Graphics()->SetColor(TipColorModified);
689 IGraphics::CQuadItem TipQuadItem(Pos.x + Length, Pos.y - LineWidth, 15.f, LineWidth * 2.f);
690 Graphics()->QuadsDrawTL(pArray: &TipQuadItem, Num: 1);
691 }
692 Graphics()->QuadsEnd();
693 }
694 else
695 {
696 Graphics()->LinesBegin();
697 Graphics()->SetColor(ColorModified);
698 IGraphics::CLineItem LineItem(Pos.x, Pos.y, Pos.x + Length, Pos.y);
699 Graphics()->LinesDraw(pArray: &LineItem, Num: 1);
700 if(TipColor.a > 0.0f)
701 {
702 Graphics()->SetColor(TipColorModified);
703 IGraphics::CLineItem TipLineItem(Pos.x + Length, Pos.y, Pos.x + Length + 15.f, Pos.y);
704 Graphics()->LinesDraw(pArray: &TipLineItem, Num: 1);
705 }
706 Graphics()->LinesEnd();
707 }
708 };
709
710 CTeeRenderInfo OwnSkinInfo;
711 OwnSkinInfo.Apply(pSkin: GameClient()->m_Skins.Find(pName: g_Config.m_ClPlayerSkin));
712 OwnSkinInfo.ApplyColors(CustomColoredSkin: g_Config.m_ClPlayerUseCustomColor, ColorBody: g_Config.m_ClPlayerColorBody, ColorFeet: g_Config.m_ClPlayerColorFeet);
713 OwnSkinInfo.m_Size = 50.0f;
714
715 CTeeRenderInfo DummySkinInfo;
716 DummySkinInfo.Apply(pSkin: GameClient()->m_Skins.Find(pName: g_Config.m_ClDummySkin));
717 DummySkinInfo.ApplyColors(CustomColoredSkin: g_Config.m_ClDummyUseCustomColor, ColorBody: g_Config.m_ClDummyColorBody, ColorFeet: g_Config.m_ClDummyColorFeet);
718 DummySkinInfo.m_Size = 50.0f;
719
720 vec2 TeeRenderPos, DummyRenderPos;
721
722 const float LineLength = 150.f;
723 const float LeftMargin = 30.f;
724
725 const int TileScale = 32.0f;
726
727 // Toggled via checkbox later, inverts some previews
728 static bool s_HookCollPressed = false;
729
730 CUIRect PreviewColl;
731
732 // ***** Unhookable Tile Preview *****
733 CUIRect PreviewNoColl;
734 RightView.HSplitTop(Cut: 50.0f, pTop: &PreviewNoColl, pBottom: &RightView);
735 RightView.HSplitTop(Cut: 4 * MarginSmall, pTop: nullptr, pBottom: &RightView);
736 TeeRenderPos = vec2(PreviewNoColl.x + LeftMargin, PreviewNoColl.y + PreviewNoColl.h / 2.0f);
737 DoHookCollision(TeeRenderPos, PreviewNoColl.w - LineLength, g_Config.m_ClHookCollSize, color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClHookCollColorNoColl)), ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f), s_HookCollPressed);
738 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &OwnSkinInfo, Emote: 0, Dir: vec2(1.0f, 0.0f), Pos: TeeRenderPos);
739
740 CUIRect NoHookTileRect;
741 PreviewNoColl.VSplitRight(Cut: LineLength, pLeft: &PreviewNoColl, pRight: &NoHookTileRect);
742 NoHookTileRect.VSplitLeft(Cut: 50.0f, pLeft: &NoHookTileRect, pRight: nullptr);
743 NoHookTileRect.Margin(Cut: 10.0f, pOtherRect: &NoHookTileRect);
744
745 // Render unhookable tile
746 Graphics()->TextureClear();
747 Graphics()->TextureSet(Texture: GameClient()->m_MapImages.GetEntities(EntityLayerType: MAP_IMAGE_ENTITY_LAYER_TYPE_ALL_EXCEPT_SWITCH));
748 Graphics()->SetColor(r: 1.0f, g: 1.0f, b: 1.0f, a: 1.0f);
749 RenderMap()->RenderTile(x: NoHookTileRect.x, y: NoHookTileRect.y, Index: TILE_NOHOOK, Scale: TileScale, Color: ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
750
751 // ***** Hookable Tile Preview *****
752 RightView.HSplitTop(Cut: 50.0f, pTop: &PreviewColl, pBottom: &RightView);
753 RightView.HSplitTop(Cut: 4 * MarginSmall, pTop: nullptr, pBottom: &RightView);
754 TeeRenderPos = vec2(PreviewColl.x + LeftMargin, PreviewColl.y + PreviewColl.h / 2.0f);
755 DoHookCollision(TeeRenderPos, PreviewColl.w - LineLength, g_Config.m_ClHookCollSize, color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClHookCollColorHookableColl)), ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f), s_HookCollPressed);
756 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &OwnSkinInfo, Emote: 0, Dir: vec2(1.0f, 0.0f), Pos: TeeRenderPos);
757
758 CUIRect HookTileRect;
759 PreviewColl.VSplitRight(Cut: LineLength, pLeft: &PreviewColl, pRight: &HookTileRect);
760 HookTileRect.VSplitLeft(Cut: 50.0f, pLeft: &HookTileRect, pRight: nullptr);
761 HookTileRect.Margin(Cut: 10.0f, pOtherRect: &HookTileRect);
762
763 // Render hookable tile
764 Graphics()->TextureClear();
765 Graphics()->TextureSet(Texture: GameClient()->m_MapImages.GetEntities(EntityLayerType: MAP_IMAGE_ENTITY_LAYER_TYPE_ALL_EXCEPT_SWITCH));
766 Graphics()->SetColor(r: 1.0f, g: 1.0f, b: 1.0f, a: 1.0f);
767 RenderMap()->RenderTile(x: HookTileRect.x, y: HookTileRect.y, Index: TILE_SOLID, Scale: TileScale, Color: ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
768
769 // ***** Hook Dummy Preview *****
770 RightView.HSplitTop(Cut: 50.0f, pTop: &PreviewColl, pBottom: &RightView);
771 RightView.HSplitTop(Cut: 4 * MarginSmall, pTop: nullptr, pBottom: &RightView);
772 TeeRenderPos = vec2(PreviewColl.x + LeftMargin, PreviewColl.y + PreviewColl.h / 2.0f);
773 DummyRenderPos = vec2(PreviewColl.x + PreviewColl.w - LineLength - 5.f + LeftMargin, PreviewColl.y + PreviewColl.h / 2.0f);
774 DoHookCollision(TeeRenderPos, PreviewColl.w - LineLength - 15.f, g_Config.m_ClHookCollSize, color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClHookCollColorTeeColl)), ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f), s_HookCollPressed);
775 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &DummySkinInfo, Emote: 0, Dir: vec2(1.0f, 0.0f), Pos: DummyRenderPos);
776 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &OwnSkinInfo, Emote: 0, Dir: vec2(1.0f, 0.0f), Pos: TeeRenderPos);
777
778 // ***** Hook Dummy Reverse Preview *****
779 RightView.HSplitTop(Cut: 50.0f, pTop: &PreviewColl, pBottom: &RightView);
780 RightView.HSplitTop(Cut: 4 * MarginSmall, pTop: nullptr, pBottom: &RightView);
781 TeeRenderPos = vec2(PreviewColl.x + LeftMargin, PreviewColl.y + PreviewColl.h / 2.0f);
782 DummyRenderPos = vec2(PreviewColl.x + PreviewColl.w - LineLength - 5.f + LeftMargin, PreviewColl.y + PreviewColl.h / 2.0f);
783 DoHookCollision(TeeRenderPos, PreviewColl.w - LineLength - 15.f, g_Config.m_ClHookCollSizeOther, color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClHookCollColorTeeColl)), ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f), false);
784 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &OwnSkinInfo, Emote: 0, Dir: vec2(1.0f, 0.0f), Pos: DummyRenderPos);
785 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &DummySkinInfo, Emote: 0, Dir: vec2(1.0f, 0.0f), Pos: TeeRenderPos);
786
787 // ***** Hook Line Tip Preview *****
788 RightView.HSplitTop(Cut: 50.0f, pTop: &PreviewColl, pBottom: &RightView);
789 RightView.HSplitTop(Cut: 4 * MarginSmall, pTop: nullptr, pBottom: &RightView);
790 TeeRenderPos = vec2(PreviewColl.x + LeftMargin, PreviewColl.y + PreviewColl.h / 2.0f);
791 DoHookCollision(TeeRenderPos, PreviewColl.w - LineLength - 15.f, g_Config.m_ClHookCollSize, color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClHookCollColorNoColl)), color_cast<ColorRGBA>(hsl: ColorHSLA(g_Config.m_ClHookCollTipColor, true)), s_HookCollPressed);
792 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &OwnSkinInfo, Emote: 0, Dir: vec2(1.0f, 0.0f), Pos: TeeRenderPos);
793
794 // ***** Preview +hookcoll pressed toggle *****
795 RightView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &RightView);
796 if(DoButton_CheckBox(pId: &s_HookCollPressed, pText: Localize(pStr: "Preview 'Hook collisions' being pressed"), Checked: s_HookCollPressed, pRect: &Button))
797 s_HookCollPressed = !s_HookCollPressed;
798 }
799 else if(s_CurTab == APPEARANCE_TAB_INFO_MESSAGES)
800 {
801 MainView.VSplitMid(pLeft: &LeftView, pRight: &RightView, Spacing: MarginBetweenViews);
802
803 // ***** Info Messages ***** //
804 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Info Messages"), FontSize: HeadlineFontSize,
805 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
806 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
807
808 // General info messages settings
809 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
810 if(DoButton_CheckBox(pId: &g_Config.m_ClShowKillMessages, pText: Localize(pStr: "Show kill messages"), Checked: g_Config.m_ClShowKillMessages, pRect: &Button))
811 {
812 g_Config.m_ClShowKillMessages ^= 1;
813 }
814
815 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
816 if(DoButton_CheckBox(pId: &g_Config.m_ClShowFinishMessages, pText: Localize(pStr: "Show finish messages"), Checked: g_Config.m_ClShowFinishMessages, pRect: &Button))
817 {
818 g_Config.m_ClShowFinishMessages ^= 1;
819 }
820
821 static CButtonContainer s_KillMessageNormalColorId, s_KillMessageHighlightColorId;
822 DoLine_ColorPicker(pResetId: &s_KillMessageNormalColorId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Normal Color"), pColorValue: &g_Config.m_ClKillMessageNormalColor, DefaultColor: ColorRGBA(1.0f, 1.0f, 1.0f), CheckBoxSpacing: false);
823 DoLine_ColorPicker(pResetId: &s_KillMessageHighlightColorId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Highlight Color"), pColorValue: &g_Config.m_ClKillMessageHighlightColor, DefaultColor: ColorRGBA(1.0f, 1.0f, 1.0f), CheckBoxSpacing: false);
824 }
825 else if(s_CurTab == APPEARANCE_TAB_LASER)
826 {
827 MainView.VSplitMid(pLeft: &LeftView, pRight: &RightView, Spacing: MarginBetweenViews);
828
829 // ***** Weapons ***** //
830 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Weapons"), FontSize: HeadlineFontSize,
831 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
832 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
833
834 // General weapon laser settings
835 static CButtonContainer s_LaserRifleOutResetId, s_LaserRifleInResetId, s_LaserShotgunOutResetId, s_LaserShotgunInResetId;
836
837 ColorHSLA LaserRifleOutlineColor = DoLine_ColorPicker(pResetId: &s_LaserRifleOutResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Rifle Laser Outline Color"), pColorValue: &g_Config.m_ClLaserRifleOutlineColor, DefaultColor: ColorRGBA(0.074402f, 0.074402f, 0.247166f, 1.0f), CheckBoxSpacing: false);
838 ColorHSLA LaserRifleInnerColor = DoLine_ColorPicker(pResetId: &s_LaserRifleInResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Rifle Laser Inner Color"), pColorValue: &g_Config.m_ClLaserRifleInnerColor, DefaultColor: ColorRGBA(0.498039f, 0.498039f, 1.0f, 1.0f), CheckBoxSpacing: false);
839 ColorHSLA LaserShotgunOutlineColor = DoLine_ColorPicker(pResetId: &s_LaserShotgunOutResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Shotgun Laser Outline Color"), pColorValue: &g_Config.m_ClLaserShotgunOutlineColor, DefaultColor: ColorRGBA(0.125490f, 0.098039f, 0.043137f, 1.0f), CheckBoxSpacing: false);
840 ColorHSLA LaserShotgunInnerColor = DoLine_ColorPicker(pResetId: &s_LaserShotgunInResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Shotgun Laser Inner Color"), pColorValue: &g_Config.m_ClLaserShotgunInnerColor, DefaultColor: ColorRGBA(0.570588f, 0.417647f, 0.252941f, 1.0f), CheckBoxSpacing: false);
841
842 // ***** Entities ***** //
843 LeftView.HSplitTop(Cut: 10.0f, pTop: nullptr, pBottom: &LeftView);
844 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Entities"), FontSize: HeadlineFontSize,
845 Align: TEXTALIGN_ML, pRect: &LeftView, LineSize: HeadlineHeight);
846 LeftView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &LeftView);
847
848 // General entity laser settings
849 static CButtonContainer s_LaserDoorOutResetId, s_LaserDoorInResetId, s_LaserFreezeOutResetId, s_LaserFreezeInResetId, s_LaserDraggerOutResetId, s_LaserDraggerInResetId;
850
851 ColorHSLA LaserDoorOutlineColor = DoLine_ColorPicker(pResetId: &s_LaserDoorOutResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Door Laser Outline Color"), pColorValue: &g_Config.m_ClLaserDoorOutlineColor, DefaultColor: ColorRGBA(0.0f, 0.131372f, 0.096078f, 1.0f), CheckBoxSpacing: false);
852 ColorHSLA LaserDoorInnerColor = DoLine_ColorPicker(pResetId: &s_LaserDoorInResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Door Laser Inner Color"), pColorValue: &g_Config.m_ClLaserDoorInnerColor, DefaultColor: ColorRGBA(0.262745f, 0.760784f, 0.639215f, 1.0f), CheckBoxSpacing: false);
853 ColorHSLA LaserFreezeOutlineColor = DoLine_ColorPicker(pResetId: &s_LaserFreezeOutResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Freeze Laser Outline Color"), pColorValue: &g_Config.m_ClLaserFreezeOutlineColor, DefaultColor: ColorRGBA(0.131372f, 0.123529f, 0.182352f, 1.0f), CheckBoxSpacing: false);
854 ColorHSLA LaserFreezeInnerColor = DoLine_ColorPicker(pResetId: &s_LaserFreezeInResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Freeze Laser Inner Color"), pColorValue: &g_Config.m_ClLaserFreezeInnerColor, DefaultColor: ColorRGBA(0.482352f, 0.443137f, 0.564705f, 1.0f), CheckBoxSpacing: false);
855 ColorHSLA LaserDraggerOutlineColor = DoLine_ColorPicker(pResetId: &s_LaserDraggerOutResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Dragger Outline Color"), pColorValue: &g_Config.m_ClLaserDraggerOutlineColor, DefaultColor: ColorRGBA(0.1640625f, 0.015625f, 0.015625f, 1.0f), CheckBoxSpacing: false);
856 ColorHSLA LaserDraggerInnerColor = DoLine_ColorPicker(pResetId: &s_LaserDraggerInResetId, LineSize: ColorPickerLineSize, LabelSize: ColorPickerLabelSize, BottomMargin: ColorPickerLineSpacing, pMainRect: &LeftView, pText: Localize(pStr: "Dragger Inner Color"), pColorValue: &g_Config.m_ClLaserDraggerInnerColor, DefaultColor: ColorRGBA(.8666666f, .3725490f, .3725490f, 1.0f), CheckBoxSpacing: false);
857
858 static CButtonContainer s_AllToRifleResetId, s_AllToDefaultResetId;
859
860 LeftView.HSplitTop(Cut: 4 * MarginSmall, pTop: nullptr, pBottom: &LeftView);
861 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
862 if(DoButton_Menu(pButtonContainer: &s_AllToRifleResetId, pText: Localize(pStr: "Set all to Rifle"), Checked: 0, pRect: &Button))
863 {
864 g_Config.m_ClLaserShotgunOutlineColor = g_Config.m_ClLaserRifleOutlineColor;
865 g_Config.m_ClLaserShotgunInnerColor = g_Config.m_ClLaserRifleInnerColor;
866 g_Config.m_ClLaserDoorOutlineColor = g_Config.m_ClLaserRifleOutlineColor;
867 g_Config.m_ClLaserDoorInnerColor = g_Config.m_ClLaserRifleInnerColor;
868 g_Config.m_ClLaserFreezeOutlineColor = g_Config.m_ClLaserRifleOutlineColor;
869 g_Config.m_ClLaserFreezeInnerColor = g_Config.m_ClLaserRifleInnerColor;
870 g_Config.m_ClLaserDraggerOutlineColor = g_Config.m_ClLaserRifleOutlineColor;
871 g_Config.m_ClLaserDraggerInnerColor = g_Config.m_ClLaserRifleInnerColor;
872 }
873
874 // values taken from the CL commands
875 LeftView.HSplitTop(Cut: 2 * MarginSmall, pTop: nullptr, pBottom: &LeftView);
876 LeftView.HSplitTop(Cut: LineSize, pTop: &Button, pBottom: &LeftView);
877 if(DoButton_Menu(pButtonContainer: &s_AllToDefaultResetId, pText: Localize(pStr: "Reset to defaults"), Checked: 0, pRect: &Button))
878 {
879 g_Config.m_ClLaserRifleOutlineColor = 11176233;
880 g_Config.m_ClLaserRifleInnerColor = 11206591;
881 g_Config.m_ClLaserShotgunOutlineColor = 1866773;
882 g_Config.m_ClLaserShotgunInnerColor = 1467241;
883 g_Config.m_ClLaserDoorOutlineColor = 7667473;
884 g_Config.m_ClLaserDoorInnerColor = 7701379;
885 g_Config.m_ClLaserFreezeOutlineColor = 11613223;
886 g_Config.m_ClLaserFreezeInnerColor = 12001153;
887 g_Config.m_ClLaserDraggerOutlineColor = 57618;
888 g_Config.m_ClLaserDraggerInnerColor = 42398;
889 }
890
891 // ***** Laser Preview ***** //
892 Ui()->DoLabel_AutoLineSize(pText: Localize(pStr: "Preview"), FontSize: HeadlineFontSize,
893 Align: TEXTALIGN_ML, pRect: &RightView, LineSize: HeadlineHeight);
894 RightView.HSplitTop(Cut: MarginSmall, pTop: nullptr, pBottom: &RightView);
895
896 const float LaserPreviewHeight = 60.0f;
897 CUIRect LaserPreview;
898 RightView.HSplitTop(Cut: LaserPreviewHeight, pTop: &LaserPreview, pBottom: &RightView);
899 RightView.HSplitTop(Cut: 2 * MarginSmall, pTop: nullptr, pBottom: &RightView);
900 DoLaserPreview(pRect: &LaserPreview, OutlineColor: LaserRifleOutlineColor, InnerColor: LaserRifleInnerColor, LaserType: LASERTYPE_RIFLE);
901
902 RightView.HSplitTop(Cut: LaserPreviewHeight, pTop: &LaserPreview, pBottom: &RightView);
903 RightView.HSplitTop(Cut: 2 * MarginSmall, pTop: nullptr, pBottom: &RightView);
904 DoLaserPreview(pRect: &LaserPreview, OutlineColor: LaserShotgunOutlineColor, InnerColor: LaserShotgunInnerColor, LaserType: LASERTYPE_SHOTGUN);
905
906 RightView.HSplitTop(Cut: LaserPreviewHeight, pTop: &LaserPreview, pBottom: &RightView);
907 RightView.HSplitTop(Cut: 2 * MarginSmall, pTop: nullptr, pBottom: &RightView);
908 DoLaserPreview(pRect: &LaserPreview, OutlineColor: LaserDoorOutlineColor, InnerColor: LaserDoorInnerColor, LaserType: LASERTYPE_DOOR);
909
910 RightView.HSplitTop(Cut: LaserPreviewHeight, pTop: &LaserPreview, pBottom: &RightView);
911 RightView.HSplitTop(Cut: 2 * MarginSmall, pTop: nullptr, pBottom: &RightView);
912 DoLaserPreview(pRect: &LaserPreview, OutlineColor: LaserFreezeOutlineColor, InnerColor: LaserFreezeInnerColor, LaserType: LASERTYPE_FREEZE);
913
914 RightView.HSplitTop(Cut: LaserPreviewHeight, pTop: &LaserPreview, pBottom: &RightView);
915 RightView.HSplitTop(Cut: 2 * MarginSmall, pTop: nullptr, pBottom: &RightView);
916 DoLaserPreview(pRect: &LaserPreview, OutlineColor: LaserDraggerOutlineColor, InnerColor: LaserDraggerInnerColor, LaserType: LASERTYPE_DRAGGER);
917 }
918}
919
920void CMenus::DoLaserPreview(const CUIRect *pRect, const ColorHSLA LaserOutlineColor, const ColorHSLA LaserInnerColor, const int LaserType)
921{
922 CUIRect Section = *pRect;
923 vec2 From = vec2(Section.x + 30.0f, Section.y + Section.h / 2.0f);
924 vec2 Pos = vec2(Section.x + Section.w - 20.0f, Section.y + Section.h / 2.0f);
925
926 const ColorRGBA OuterColor = color_cast<ColorRGBA>(hsl: ColorHSLA(LaserOutlineColor));
927 const ColorRGBA InnerColor = color_cast<ColorRGBA>(hsl: ColorHSLA(LaserInnerColor));
928 const float TicksHead = Client()->GlobalTime() * Client()->GameTickSpeed();
929
930 // TicksBody = 4.0 for less laser width for weapon alignment
931 GameClient()->m_Items.RenderLaser(From, Pos, OuterColor, InnerColor, TicksBody: 4.0f, TicksHead, Type: LaserType);
932
933 switch(LaserType)
934 {
935 case LASERTYPE_RIFLE:
936 Graphics()->TextureSet(Texture: GameClient()->m_GameSkin.m_SpriteWeaponLaser);
937 Graphics()->SelectSprite(Id: SPRITE_WEAPON_LASER_BODY);
938 Graphics()->QuadsBegin();
939 Graphics()->QuadsSetSubset(TopLeftU: 0, TopLeftV: 0, BottomRightU: 1, BottomRightV: 1);
940 Graphics()->DrawSprite(x: Section.x + 30.0f, y: Section.y + Section.h / 2.0f, Size: 60.0f);
941 Graphics()->QuadsEnd();
942 break;
943 case LASERTYPE_SHOTGUN:
944 Graphics()->TextureSet(Texture: GameClient()->m_GameSkin.m_SpriteWeaponShotgun);
945 Graphics()->SelectSprite(Id: SPRITE_WEAPON_SHOTGUN_BODY);
946 Graphics()->QuadsBegin();
947 Graphics()->QuadsSetSubset(TopLeftU: 0, TopLeftV: 0, BottomRightU: 1, BottomRightV: 1);
948 Graphics()->DrawSprite(x: Section.x + 30.0f, y: Section.y + Section.h / 2.0f, Size: 60.0f);
949 Graphics()->QuadsEnd();
950 break;
951 case LASERTYPE_DRAGGER:
952 {
953 CTeeRenderInfo TeeRenderInfo;
954 TeeRenderInfo.Apply(pSkin: GameClient()->m_Skins.Find(pName: g_Config.m_ClPlayerSkin));
955 TeeRenderInfo.ApplyColors(CustomColoredSkin: g_Config.m_ClPlayerUseCustomColor, ColorBody: g_Config.m_ClPlayerColorBody, ColorFeet: g_Config.m_ClPlayerColorFeet);
956 TeeRenderInfo.m_Size = 64.0f;
957 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &TeeRenderInfo, Emote: EMOTE_NORMAL, Dir: vec2(-1, 0), Pos);
958 break;
959 }
960 case LASERTYPE_FREEZE:
961 {
962 CTeeRenderInfo TeeRenderInfo;
963 if(g_Config.m_ClShowNinja)
964 TeeRenderInfo.Apply(pSkin: GameClient()->m_Skins.Find(pName: "x_ninja"));
965 else
966 TeeRenderInfo.Apply(pSkin: GameClient()->m_Skins.Find(pName: g_Config.m_ClPlayerSkin));
967 TeeRenderInfo.m_TeeRenderFlags = TEE_EFFECT_FROZEN;
968 TeeRenderInfo.m_Size = 64.0f;
969 TeeRenderInfo.m_ColorBody = ColorRGBA(1, 1, 1);
970 TeeRenderInfo.m_ColorFeet = ColorRGBA(1, 1, 1);
971 RenderTools()->RenderTee(pAnim: CAnimState::GetIdle(), pInfo: &TeeRenderInfo, Emote: EMOTE_PAIN, Dir: vec2(1, 0), Pos: From);
972 GameClient()->m_Effects.FreezingFlakes(Pos: From, Size: vec2(32, 32), Alpha: 1.0f);
973 break;
974 }
975 default:
976 GameClient()->m_Items.RenderLaser(From, Pos: From, OuterColor, InnerColor, TicksBody: 4.0f, TicksHead, Type: LaserType);
977 }
978}
979