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. */
6 #include <engine/engine.h>
7 #include <engine/graphics.h>
8 #include <engine/storage.h>
9 #include <engine/textrender.h>
10 #include <engine/shared/config.h>
11 #include <engine/shared/linereader.h>
13 #include <game/generated/protocol.h>
14 #include <game/generated/client_data.h>
16 #include <game/client/components/sounds.h>
17 #include <game/client/ui.h>
18 #include <game/client/render.h>
19 #include <game/client/gameclient.h>
20 #include <game/client/animstate.h>
21 #include <game/localization.h>
24 #include "countryflags.h"
28 CMenusKeyBinder
CMenus::m_Binder
;
30 CMenusKeyBinder::CMenusKeyBinder()
36 bool CMenusKeyBinder::OnInput(IInput::CEvent Event
)
40 if(Event
.m_Flags
&IInput::FLAG_PRESS
)
52 void CMenus::RenderSettingsGeneral(CUIRect MainView
)
55 CUIRect Label
, Button
, Left
, Right
, Game
, Client
;
56 MainView
.HSplitTop(150.0f
, &Game
, &Client
);
61 Game
.HSplitTop(30.0f
, &Label
, &Game
);
62 UI()->DoLabelScaled(&Label
, Localize("Game"), 20.0f
, -1);
63 Game
.Margin(5.0f
, &Game
);
64 Game
.VSplitMid(&Left
, &Right
);
65 Left
.VSplitRight(5.0f
, &Left
, 0);
66 Right
.VMargin(5.0f
, &Right
);
69 Left
.HSplitTop(20.0f
, &Button
, &Left
);
70 static int s_DynamicCameraButton
= 0;
71 if(DoButton_CheckBox(&s_DynamicCameraButton
, Localize("Dynamic Camera"), g_Config
.m_ClMouseDeadzone
!= 0, &Button
))
73 if(g_Config
.m_ClMouseDeadzone
)
75 g_Config
.m_ClMouseFollowfactor
= 0;
76 g_Config
.m_ClMouseMaxDistance
= 400;
77 g_Config
.m_ClMouseDeadzone
= 0;
81 g_Config
.m_ClMouseFollowfactor
= 60;
82 g_Config
.m_ClMouseMaxDistance
= 1000;
83 g_Config
.m_ClMouseDeadzone
= 300;
88 Left
.HSplitTop(5.0f
, 0, &Left
);
89 Left
.HSplitTop(20.0f
, &Button
, &Left
);
90 if(DoButton_CheckBox(&g_Config
.m_ClAutoswitchWeapons
, Localize("Switch weapon on pickup"), g_Config
.m_ClAutoswitchWeapons
, &Button
))
91 g_Config
.m_ClAutoswitchWeapons
^= 1;
94 Left
.HSplitTop(5.0f
, 0, &Left
);
95 Left
.HSplitTop(20.0f
, &Button
, &Left
);
96 if(DoButton_CheckBox(&g_Config
.m_ClShowhud
, Localize("Show ingame HUD"), g_Config
.m_ClShowhud
, &Button
))
97 g_Config
.m_ClShowhud
^= 1;
100 Right
.HSplitTop(20.0f
, &Button
, &Right
);
101 if(DoButton_CheckBox(&g_Config
.m_ClNameplates
, Localize("Show name plates"), g_Config
.m_ClNameplates
, &Button
))
102 g_Config
.m_ClNameplates
^= 1;
104 if(g_Config
.m_ClNameplates
)
106 Right
.HSplitTop(2.5f
, 0, &Right
);
107 Right
.VSplitLeft(30.0f
, 0, &Right
);
108 Right
.HSplitTop(20.0f
, &Button
, &Right
);
109 if(DoButton_CheckBox(&g_Config
.m_ClNameplatesAlways
, Localize("Always show name plates"), g_Config
.m_ClNameplatesAlways
, &Button
))
110 g_Config
.m_ClNameplatesAlways
^= 1;
112 Right
.HSplitTop(2.5f
, 0, &Right
);
113 Right
.HSplitTop(20.0f
, &Label
, &Right
);
114 Right
.HSplitTop(20.0f
, &Button
, &Right
);
115 str_format(aBuf
, sizeof(aBuf
), "%s: %i", Localize("Name plates size"), g_Config
.m_ClNameplatesSize
);
116 UI()->DoLabelScaled(&Label
, aBuf
, 13.0f
, -1);
117 Button
.HMargin(2.0f
, &Button
);
118 g_Config
.m_ClNameplatesSize
= (int)(DoScrollbarH(&g_Config
.m_ClNameplatesSize
, &Button
, g_Config
.m_ClNameplatesSize
/100.0f
)*100.0f
+0.1f
);
120 Right
.HSplitTop(20.0f
, &Button
, &Right
);
121 if(DoButton_CheckBox(&g_Config
.m_ClNameplatesTeamcolors
, Localize("Use team colors for name plates"), g_Config
.m_ClNameplatesTeamcolors
, &Button
))
122 g_Config
.m_ClNameplatesTeamcolors
^= 1;
129 Client
.HSplitTop(30.0f
, &Label
, &Client
);
130 UI()->DoLabelScaled(&Label
, Localize("Client"), 20.0f
, -1);
131 Client
.Margin(5.0f
, &Client
);
132 Client
.VSplitMid(&Left
, &Right
);
133 Left
.VSplitRight(5.0f
, &Left
, 0);
134 Right
.VMargin(5.0f
, &Right
);
136 // auto demo settings
138 Left
.HSplitTop(20.0f
, &Button
, &Left
);
139 if(DoButton_CheckBox(&g_Config
.m_ClAutoDemoRecord
, Localize("Automatically record demos"), g_Config
.m_ClAutoDemoRecord
, &Button
))
140 g_Config
.m_ClAutoDemoRecord
^= 1;
142 Right
.HSplitTop(20.0f
, &Button
, &Right
);
143 if(DoButton_CheckBox(&g_Config
.m_ClAutoScreenshot
, Localize("Automatically take game over screenshot"), g_Config
.m_ClAutoScreenshot
, &Button
))
144 g_Config
.m_ClAutoScreenshot
^= 1;
146 Left
.HSplitTop(10.0f
, 0, &Left
);
147 Left
.VSplitLeft(20.0f
, 0, &Left
);
148 Left
.HSplitTop(20.0f
, &Label
, &Left
);
149 Button
.VSplitRight(20.0f
, &Button
, 0);
151 if(g_Config
.m_ClAutoDemoMax
)
152 str_format(aBuf
, sizeof(aBuf
), "%s: %i", Localize("Max demos"), g_Config
.m_ClAutoDemoMax
);
154 str_format(aBuf
, sizeof(aBuf
), "%s: %s", Localize("Max demos"), Localize("no limit"));
155 UI()->DoLabelScaled(&Label
, aBuf
, 13.0f
, -1);
156 Left
.HSplitTop(20.0f
, &Button
, 0);
157 Button
.HMargin(2.0f
, &Button
);
158 g_Config
.m_ClAutoDemoMax
= static_cast<int>(DoScrollbarH(&g_Config
.m_ClAutoDemoMax
, &Button
, g_Config
.m_ClAutoDemoMax
/1000.0f
)*1000.0f
+0.1f
);
160 Right
.HSplitTop(10.0f
, 0, &Right
);
161 Right
.VSplitLeft(20.0f
, 0, &Right
);
162 Right
.HSplitTop(20.0f
, &Label
, &Right
);
163 Button
.VSplitRight(20.0f
, &Button
, 0);
164 if(g_Config
.m_ClAutoScreenshotMax
)
165 str_format(aBuf
, sizeof(aBuf
), "%s: %i", Localize("Max Screenshots"), g_Config
.m_ClAutoScreenshotMax
);
167 str_format(aBuf
, sizeof(aBuf
), "%s: %s", Localize("Max Screenshots"), Localize("no limit"));
168 UI()->DoLabelScaled(&Label
, aBuf
, 13.0f
, -1);
169 Right
.HSplitTop(20.0f
, &Button
, 0);
170 Button
.HMargin(2.0f
, &Button
);
171 g_Config
.m_ClAutoScreenshotMax
= static_cast<int>(DoScrollbarH(&g_Config
.m_ClAutoScreenshotMax
, &Button
, g_Config
.m_ClAutoScreenshotMax
/1000.0f
)*1000.0f
+0.1f
);
176 void CMenus::RenderSettingsPlayer(CUIRect MainView
)
178 CUIRect Button
, Label
;
179 MainView
.HSplitTop(10.0f
, 0, &MainView
);
182 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
183 Button
.VSplitLeft(80.0f
, &Label
, &Button
);
184 Button
.VSplitLeft(150.0f
, &Button
, 0);
186 str_format(aBuf
, sizeof(aBuf
), "%s:", Localize("Name"));
187 UI()->DoLabelScaled(&Label
, aBuf
, 14.0, -1);
188 static float s_OffsetName
= 0.0f
;
189 if(DoEditBox(g_Config
.m_PlayerName
, &Button
, g_Config
.m_PlayerName
, sizeof(g_Config
.m_PlayerName
), 14.0f
, &s_OffsetName
))
190 m_NeedSendinfo
= true;
193 MainView
.HSplitTop(5.0f
, 0, &MainView
);
194 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
195 Button
.VSplitLeft(80.0f
, &Label
, &Button
);
196 Button
.VSplitLeft(150.0f
, &Button
, 0);
197 str_format(aBuf
, sizeof(aBuf
), "%s:", Localize("Clan"));
198 UI()->DoLabelScaled(&Label
, aBuf
, 14.0, -1);
199 static float s_OffsetClan
= 0.0f
;
200 if(DoEditBox(g_Config
.m_PlayerClan
, &Button
, g_Config
.m_PlayerClan
, sizeof(g_Config
.m_PlayerClan
), 14.0f
, &s_OffsetClan
))
201 m_NeedSendinfo
= true;
203 // country flag selector
204 MainView
.HSplitTop(20.0f
, 0, &MainView
);
205 static float s_ScrollValue
= 0.0f
;
206 int OldSelected
= -1;
207 UiDoListboxStart(&s_ScrollValue
, &MainView
, 50.0f
, Localize("Country"), "", m_pClient
->m_pCountryFlags
->Num(), 6, OldSelected
, s_ScrollValue
);
209 for(int i
= 0; i
< m_pClient
->m_pCountryFlags
->Num(); ++i
)
211 const CCountryFlags::CCountryFlag
*pEntry
= m_pClient
->m_pCountryFlags
->GetByIndex(i
);
212 if(pEntry
->m_CountryCode
== g_Config
.m_PlayerCountry
)
215 CListboxItem Item
= UiDoListboxNextItem(&pEntry
->m_CountryCode
, OldSelected
== i
);
218 Item
.m_Rect
.Margin(10.0f
, &Item
.m_Rect
);
219 float OldWidth
= Item
.m_Rect
.w
;
220 Item
.m_Rect
.w
= Item
.m_Rect
.h
*2;
221 Item
.m_Rect
.x
+= (OldWidth
-Item
.m_Rect
.w
)/ 2.0f
;
222 Graphics()->TextureSet(pEntry
->m_Texture
);
223 Graphics()->QuadsBegin();
224 Graphics()->SetColor(1.0f
, 1.0f
, 1.0f
, 1.0f
);
225 IGraphics::CQuadItem
QuadItem(Item
.m_Rect
.x
, Item
.m_Rect
.y
, Item
.m_Rect
.w
, Item
.m_Rect
.h
);
226 Graphics()->QuadsDrawTL(&QuadItem
, 1);
227 Graphics()->QuadsEnd();
231 const int NewSelected
= UiDoListboxEnd(&s_ScrollValue
, 0);
232 if(OldSelected
!= NewSelected
)
234 g_Config
.m_PlayerCountry
= m_pClient
->m_pCountryFlags
->GetByIndex(NewSelected
)->m_CountryCode
;
235 m_NeedSendinfo
= true;
239 void CMenus::RenderSettingsTee(CUIRect MainView
)
241 CUIRect Button
, Label
;
242 MainView
.HSplitTop(10.0f
, 0, &MainView
);
245 const CSkins::CSkin
*pOwnSkin
= m_pClient
->m_pSkins
->Get(m_pClient
->m_pSkins
->Find(g_Config
.m_PlayerSkin
));
246 CTeeRenderInfo OwnSkinInfo
;
247 if(g_Config
.m_PlayerUseCustomColor
)
249 OwnSkinInfo
.m_Texture
= pOwnSkin
->m_ColorTexture
;
250 OwnSkinInfo
.m_ColorBody
= m_pClient
->m_pSkins
->GetColorV4(g_Config
.m_PlayerColorBody
);
251 OwnSkinInfo
.m_ColorFeet
= m_pClient
->m_pSkins
->GetColorV4(g_Config
.m_PlayerColorFeet
);
255 OwnSkinInfo
.m_Texture
= pOwnSkin
->m_OrgTexture
;
256 OwnSkinInfo
.m_ColorBody
= vec4(1.0f
, 1.0f
, 1.0f
, 1.0f
);
257 OwnSkinInfo
.m_ColorFeet
= vec4(1.0f
, 1.0f
, 1.0f
, 1.0f
);
259 OwnSkinInfo
.m_Size
= 50.0f
*UI()->Scale();
261 MainView
.HSplitTop(20.0f
, &Label
, &MainView
);
262 Label
.VSplitLeft(230.0f
, &Label
, 0);
264 str_format(aBuf
, sizeof(aBuf
), "%s:", Localize("Your skin"));
265 UI()->DoLabelScaled(&Label
, aBuf
, 14.0f
, -1);
267 MainView
.HSplitTop(50.0f
, &Label
, &MainView
);
268 Label
.VSplitLeft(230.0f
, &Label
, 0);
269 RenderTools()->DrawUIRect(&Label
, vec4(1.0f
, 1.0f
, 1.0f
, 0.25f
), CUI::CORNER_ALL
, 10.0f
);
270 RenderTools()->RenderTee(CAnimState::GetIdle(), &OwnSkinInfo
, 0, vec2(1, 0), vec2(Label
.x
+30.0f
, Label
.y
+28.0f
));
271 Label
.HSplitTop(15.0f
, 0, &Label
);;
272 Label
.VSplitLeft(70.0f
, 0, &Label
);
273 UI()->DoLabelScaled(&Label
, g_Config
.m_PlayerSkin
, 14.0f
, -1, 150.0f
);
275 // custom colour selector
276 MainView
.HSplitTop(20.0f
, 0, &MainView
);
277 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
278 Button
.VSplitLeft(230.0f
, &Button
, 0);
279 if(DoButton_CheckBox(&g_Config
.m_PlayerColorBody
, Localize("Custom colors"), g_Config
.m_PlayerUseCustomColor
, &Button
))
281 g_Config
.m_PlayerUseCustomColor
= g_Config
.m_PlayerUseCustomColor
?0:1;
282 m_NeedSendinfo
= true;
285 MainView
.HSplitTop(5.0f
, 0, &MainView
);
286 MainView
.HSplitTop(82.5f
, &Label
, &MainView
);
287 if(g_Config
.m_PlayerUseCustomColor
)
290 Label
.VSplitMid(&aRects
[0], &aRects
[1]);
291 aRects
[0].VSplitRight(10.0f
, &aRects
[0], 0);
292 aRects
[1].VSplitLeft(10.0f
, 0, &aRects
[1]);
295 paColors
[0] = &g_Config
.m_PlayerColorBody
;
296 paColors
[1] = &g_Config
.m_PlayerColorFeet
;
298 const char *paParts
[] = {
301 const char *paLabels
[] = {
305 static int s_aColorSlider
[2][3] = {{0}};
307 for(int i
= 0; i
< 2; i
++)
309 aRects
[i
].HSplitTop(20.0f
, &Label
, &aRects
[i
]);
310 UI()->DoLabelScaled(&Label
, paParts
[i
], 14.0f
, -1);
311 aRects
[i
].VSplitLeft(20.0f
, 0, &aRects
[i
]);
312 aRects
[i
].HSplitTop(2.5f
, 0, &aRects
[i
]);
314 int PrevColor
= *paColors
[i
];
316 for(int s
= 0; s
< 3; s
++)
318 aRects
[i
].HSplitTop(20.0f
, &Label
, &aRects
[i
]);
319 Label
.VSplitLeft(100.0f
, &Label
, &Button
);
320 Button
.HMargin(2.0f
, &Button
);
322 float k
= ((PrevColor
>>((2-s
)*8))&0xff) / 255.0f
;
323 k
= DoScrollbarH(&s_aColorSlider
[i
][s
], &Button
, k
);
325 Color
+= clamp((int)(k
*255), 0, 255);
326 UI()->DoLabelScaled(&Label
, paLabels
[s
], 14.0f
, -1);
329 if(PrevColor
!= Color
)
330 m_NeedSendinfo
= true;
332 *paColors
[i
] = Color
;
337 MainView
.HSplitTop(20.0f
, 0, &MainView
);
338 static bool s_InitSkinlist
= true;
339 static sorted_array
<const CSkins::CSkin
*> s_paSkinList
;
340 static float s_ScrollValue
= 0.0f
;
343 s_paSkinList
.clear();
344 for(int i
= 0; i
< m_pClient
->m_pSkins
->Num(); ++i
)
346 const CSkins::CSkin
*s
= m_pClient
->m_pSkins
->Get(i
);
348 if(s
->m_aName
[0] == 'x' && s
->m_aName
[1] == '_')
352 s_InitSkinlist
= false;
355 int OldSelected
= -1;
356 UiDoListboxStart(&s_InitSkinlist
, &MainView
, 50.0f
, Localize("Skins"), "", s_paSkinList
.size(), 4, OldSelected
, s_ScrollValue
);
358 for(int i
= 0; i
< s_paSkinList
.size(); ++i
)
360 const CSkins::CSkin
*s
= s_paSkinList
[i
];
364 if(str_comp(s
->m_aName
, g_Config
.m_PlayerSkin
) == 0)
367 CListboxItem Item
= UiDoListboxNextItem(&s_paSkinList
[i
], OldSelected
== i
);
371 if(g_Config
.m_PlayerUseCustomColor
)
373 Info
.m_Texture
= s
->m_ColorTexture
;
374 Info
.m_ColorBody
= m_pClient
->m_pSkins
->GetColorV4(g_Config
.m_PlayerColorBody
);
375 Info
.m_ColorFeet
= m_pClient
->m_pSkins
->GetColorV4(g_Config
.m_PlayerColorFeet
);
379 Info
.m_Texture
= s
->m_OrgTexture
;
380 Info
.m_ColorBody
= vec4(1.0f
, 1.0f
, 1.0f
, 1.0f
);
381 Info
.m_ColorFeet
= vec4(1.0f
, 1.0f
, 1.0f
, 1.0f
);
384 Info
.m_Size
= UI()->Scale()*50.0f
;
385 Item
.m_Rect
.HSplitTop(5.0f
, 0, &Item
.m_Rect
); // some margin from the top
386 RenderTools()->RenderTee(CAnimState::GetIdle(), &Info
, 0, vec2(1.0f
, 0.0f
), vec2(Item
.m_Rect
.x
+Item
.m_Rect
.w
/2, Item
.m_Rect
.y
+Item
.m_Rect
.h
/2));
390 vec3 BloodColor
= g_Config
.m_PlayerUseCustomColor
? m_pClient
->m_pSkins
->GetColorV3(g_Config
.m_PlayerColorBody
) : s
->m_BloodColor
;
391 Graphics()->TextureSet(-1);
392 Graphics()->QuadsBegin();
393 Graphics()->SetColor(BloodColor
.r
, BloodColor
.g
, BloodColor
.b
, 1.0f
);
394 IGraphics::CQuadItem
QuadItem(Item
.m_Rect
.x
, Item
.m_Rect
.y
, 12.0f
, 12.0f
);
395 Graphics()->QuadsDrawTL(&QuadItem
, 1);
396 Graphics()->QuadsEnd();
401 const int NewSelected
= UiDoListboxEnd(&s_ScrollValue
, 0);
402 if(OldSelected
!= NewSelected
)
404 mem_copy(g_Config
.m_PlayerSkin
, s_paSkinList
[NewSelected
]->m_aName
, sizeof(g_Config
.m_PlayerSkin
));
405 m_NeedSendinfo
= true;
410 typedef void (*pfnAssignFuncCallback
)(CConfiguration
*pConfig
, int Value
);
414 CLocConstString m_Name
;
415 const char *m_pCommand
;
419 static CKeyInfo gs_aKeys
[] =
421 { "Move left", "+left", 0}, // Localize - these strings are localized within CLocConstString
422 { "Move right", "+right", 0 },
423 { "Jump", "+jump", 0 },
424 { "Fire", "+fire", 0 },
425 { "Hook", "+hook", 0 },
426 { "Hammer", "+weapon1", 0 },
427 { "Pistol", "+weapon2", 0 },
428 { "Shotgun", "+weapon3", 0 },
429 { "Grenade", "+weapon4", 0 },
430 { "Rifle", "+weapon5", 0 },
431 { "Next weapon", "+nextweapon", 0 },
432 { "Prev. weapon", "+prevweapon", 0 },
433 { "Vote yes", "vote yes", 0 },
434 { "Vote no", "vote no", 0 },
435 { "Chat", "chat all", 0 },
436 { "Team chat", "chat team", 0 },
437 { "Show chat", "+show_chat", 0 },
438 { "Emoticon", "+emote", 0 },
439 { "Spectator mode", "+spectate", 0 },
440 { "Spectate next", "spectate_next", 0 },
441 { "Spectate previous", "spectate_previous", 0 },
442 { "Console", "toggle_local_console", 0 },
443 { "Remote console", "toggle_remote_console", 0 },
444 { "Screenshot", "screenshot", 0 },
445 { "Scoreboard", "+scoreboard", 0 },
448 /* This is for scripts/update_localization.py to work, don't remove!
449 Localize("Move left");Localize("Move right");Localize("Jump");Localize("Fire");Localize("Hook");Localize("Hammer");
450 Localize("Pistol");Localize("Shotgun");Localize("Grenade");Localize("Rifle");Localize("Next weapon");Localize("Prev. weapon");
451 Localize("Vote yes");Localize("Vote no");Localize("Chat");Localize("Team chat");Localize("Show chat");Localize("Emoticon");
452 Localize("Spectator mode");Localize("Spectate next");Localize("Spectate previous");Localize("Console");Localize("Remote console");Localize("Screenshot");Localize("Scoreboard");
455 const int g_KeyCount
= sizeof(gs_aKeys
) / sizeof(CKeyInfo
);
457 void CMenus::UiDoGetButtons(int Start
, int Stop
, CUIRect View
)
459 for (int i
= Start
; i
< Stop
; i
++)
461 CKeyInfo
&Key
= gs_aKeys
[i
];
462 CUIRect Button
, Label
;
463 View
.HSplitTop(20.0f
, &Button
, &View
);
464 Button
.VSplitLeft(135.0f
, &Label
, &Button
);
467 str_format(aBuf
, sizeof(aBuf
), "%s:", (const char *)Key
.m_Name
);
469 UI()->DoLabelScaled(&Label
, aBuf
, 13.0f
, -1);
470 int OldId
= Key
.m_KeyId
;
471 int NewId
= DoKeyReader((void *)&gs_aKeys
[i
].m_Name
, &Button
, OldId
);
474 if(OldId
!= 0 || NewId
== 0)
475 m_pClient
->m_pBinds
->Bind(OldId
, "");
477 m_pClient
->m_pBinds
->Bind(NewId
, gs_aKeys
[i
].m_pCommand
);
479 View
.HSplitTop(5.0f
, 0, &View
);
483 void CMenus::RenderSettingsControls(CUIRect MainView
)
485 // this is kinda slow, but whatever
486 for(int i
= 0; i
< g_KeyCount
; i
++)
487 gs_aKeys
[i
].m_KeyId
= 0;
489 for(int KeyId
= 0; KeyId
< KEY_LAST
; KeyId
++)
491 const char *pBind
= m_pClient
->m_pBinds
->Get(KeyId
);
495 for(int i
= 0; i
< g_KeyCount
; i
++)
496 if(str_comp(pBind
, gs_aKeys
[i
].m_pCommand
) == 0)
498 gs_aKeys
[i
].m_KeyId
= KeyId
;
503 CUIRect MovementSettings
, WeaponSettings
, VotingSettings
, ChatSettings
, MiscSettings
, ResetButton
;
504 MainView
.VSplitLeft(MainView
.w
/2-5.0f
, &MovementSettings
, &VotingSettings
);
508 MovementSettings
.HSplitTop(MainView
.h
/3+60.0f
, &MovementSettings
, &WeaponSettings
);
509 RenderTools()->DrawUIRect(&MovementSettings
, vec4(1,1,1,0.25f
), CUI::CORNER_ALL
, 10.0f
);
510 MovementSettings
.Margin(10.0f
, &MovementSettings
);
512 TextRender()->Text(0, MovementSettings
.x
, MovementSettings
.y
, 14.0f
*UI()->Scale(), Localize("Movement"), -1);
514 MovementSettings
.HSplitTop(14.0f
+5.0f
+10.0f
, 0, &MovementSettings
);
517 CUIRect Button
, Label
;
518 MovementSettings
.HSplitTop(20.0f
, &Button
, &MovementSettings
);
519 Button
.VSplitLeft(135.0f
, &Label
, &Button
);
520 UI()->DoLabel(&Label
, Localize("Mouse sens."), 14.0f
*UI()->Scale(), -1);
521 Button
.HMargin(2.0f
, &Button
);
522 g_Config
.m_InpMousesens
= (int)(DoScrollbarH(&g_Config
.m_InpMousesens
, &Button
, (g_Config
.m_InpMousesens
-5)/500.0f
)*500.0f
)+5;
523 //*key.key = ui_do_key_reader(key.key, &Button, *key.key);
524 MovementSettings
.HSplitTop(20.0f
, 0, &MovementSettings
);
527 UiDoGetButtons(0, 5, MovementSettings
);
533 WeaponSettings
.HSplitTop(10.0f
, 0, &WeaponSettings
);
534 WeaponSettings
.HSplitTop(MainView
.h
/3+50.0f
, &WeaponSettings
, &ResetButton
);
535 RenderTools()->DrawUIRect(&WeaponSettings
, vec4(1,1,1,0.25f
), CUI::CORNER_ALL
, 10.0f
);
536 WeaponSettings
.Margin(10.0f
, &WeaponSettings
);
538 TextRender()->Text(0, WeaponSettings
.x
, WeaponSettings
.y
, 14.0f
*UI()->Scale(), Localize("Weapon"), -1);
540 WeaponSettings
.HSplitTop(14.0f
+5.0f
+10.0f
, 0, &WeaponSettings
);
541 UiDoGetButtons(5, 12, WeaponSettings
);
546 ResetButton
.HSplitTop(10.0f
, 0, &ResetButton
);
547 RenderTools()->DrawUIRect(&ResetButton
, vec4(1,1,1,0.25f
), CUI::CORNER_ALL
, 10.0f
);
548 ResetButton
.HMargin(10.0f
, &ResetButton
);
549 ResetButton
.VMargin(30.0f
, &ResetButton
);
550 static int s_DefaultButton
= 0;
551 if(DoButton_Menu((void*)&s_DefaultButton
, Localize("Reset to defaults"), 0, &ResetButton
))
552 m_pClient
->m_pBinds
->SetDefaults();
557 VotingSettings
.VSplitLeft(10.0f
, 0, &VotingSettings
);
558 VotingSettings
.HSplitTop(MainView
.h
/3-75.0f
, &VotingSettings
, &ChatSettings
);
559 RenderTools()->DrawUIRect(&VotingSettings
, vec4(1,1,1,0.25f
), CUI::CORNER_ALL
, 10.0f
);
560 VotingSettings
.Margin(10.0f
, &VotingSettings
);
562 TextRender()->Text(0, VotingSettings
.x
, VotingSettings
.y
, 14.0f
*UI()->Scale(), Localize("Voting"), -1);
564 VotingSettings
.HSplitTop(14.0f
+5.0f
+10.0f
, 0, &VotingSettings
);
565 UiDoGetButtons(12, 14, VotingSettings
);
570 ChatSettings
.HSplitTop(10.0f
, 0, &ChatSettings
);
571 ChatSettings
.HSplitTop(MainView
.h
/3-45.0f
, &ChatSettings
, &MiscSettings
);
572 RenderTools()->DrawUIRect(&ChatSettings
, vec4(1,1,1,0.25f
), CUI::CORNER_ALL
, 10.0f
);
573 ChatSettings
.Margin(10.0f
, &ChatSettings
);
575 TextRender()->Text(0, ChatSettings
.x
, ChatSettings
.y
, 14.0f
*UI()->Scale(), Localize("Chat"), -1);
577 ChatSettings
.HSplitTop(14.0f
+5.0f
+10.0f
, 0, &ChatSettings
);
578 UiDoGetButtons(14, 17, ChatSettings
);
583 MiscSettings
.HSplitTop(10.0f
, 0, &MiscSettings
);
584 RenderTools()->DrawUIRect(&MiscSettings
, vec4(1,1,1,0.25f
), CUI::CORNER_ALL
, 10.0f
);
585 MiscSettings
.Margin(10.0f
, &MiscSettings
);
587 TextRender()->Text(0, MiscSettings
.x
, MiscSettings
.y
, 14.0f
*UI()->Scale(), Localize("Miscellaneous"), -1);
589 MiscSettings
.HSplitTop(14.0f
+5.0f
+10.0f
, 0, &MiscSettings
);
590 UiDoGetButtons(17, 25, MiscSettings
);
595 void CMenus::RenderSettingsGraphics(CUIRect MainView
)
599 bool CheckSettings
= false;
601 static const int MAX_RESOLUTIONS
= 256;
602 static CVideoMode s_aModes
[MAX_RESOLUTIONS
];
603 static int s_NumNodes
= Graphics()->GetVideoModes(s_aModes
, MAX_RESOLUTIONS
);
604 static int s_GfxScreenWidth
= g_Config
.m_GfxScreenWidth
;
605 static int s_GfxScreenHeight
= g_Config
.m_GfxScreenHeight
;
606 static int s_GfxColorDepth
= g_Config
.m_GfxColorDepth
;
607 static int s_GfxFullscreen
= g_Config
.m_GfxFullscreen
;
608 static int s_GfxVsync
= g_Config
.m_GfxVsync
;
609 static int s_GfxFsaaSamples
= g_Config
.m_GfxFsaaSamples
;
610 static int s_GfxTextureQuality
= g_Config
.m_GfxTextureQuality
;
611 static int s_GfxTextureCompression
= g_Config
.m_GfxTextureCompression
;
614 MainView
.VSplitLeft(300.0f
, &MainView
, &ModeList
);
616 // draw allmodes switch
617 ModeList
.HSplitTop(20, &Button
, &ModeList
);
618 if(DoButton_CheckBox(&g_Config
.m_GfxDisplayAllModes
, Localize("Show only supported"), g_Config
.m_GfxDisplayAllModes
^1, &Button
))
620 g_Config
.m_GfxDisplayAllModes
^= 1;
621 s_NumNodes
= Graphics()->GetVideoModes(s_aModes
, MAX_RESOLUTIONS
);
625 static float s_ScrollValue
= 0;
626 int OldSelected
= -1;
627 int G
= gcd(s_GfxScreenWidth
, s_GfxScreenHeight
);
628 str_format(aBuf
, sizeof(aBuf
), "%s: %dx%d %d bit (%d:%d)", Localize("Current"), s_GfxScreenWidth
, s_GfxScreenHeight
, s_GfxColorDepth
, s_GfxScreenWidth
/G
, s_GfxScreenHeight
/G
);
629 UiDoListboxStart(&s_NumNodes
, &ModeList
, 24.0f
, Localize("Display Modes"), aBuf
, s_NumNodes
, 1, OldSelected
, s_ScrollValue
);
631 for(int i
= 0; i
< s_NumNodes
; ++i
)
633 const int Depth
= s_aModes
[i
].m_Red
+s_aModes
[i
].m_Green
+s_aModes
[i
].m_Blue
> 16 ? 24 : 16;
634 if(g_Config
.m_GfxColorDepth
== Depth
&&
635 g_Config
.m_GfxScreenWidth
== s_aModes
[i
].m_Width
&&
636 g_Config
.m_GfxScreenHeight
== s_aModes
[i
].m_Height
)
641 CListboxItem Item
= UiDoListboxNextItem(&s_aModes
[i
], OldSelected
== i
);
644 int G
= gcd(s_aModes
[i
].m_Width
, s_aModes
[i
].m_Height
);
645 str_format(aBuf
, sizeof(aBuf
), " %dx%d %d bit (%d:%d)", s_aModes
[i
].m_Width
, s_aModes
[i
].m_Height
, Depth
, s_aModes
[i
].m_Width
/G
, s_aModes
[i
].m_Height
/G
);
646 UI()->DoLabelScaled(&Item
.m_Rect
, aBuf
, 16.0f
, -1);
650 const int NewSelected
= UiDoListboxEnd(&s_ScrollValue
, 0);
651 if(OldSelected
!= NewSelected
)
653 const int Depth
= s_aModes
[NewSelected
].m_Red
+s_aModes
[NewSelected
].m_Green
+s_aModes
[NewSelected
].m_Blue
> 16 ? 24 : 16;
654 g_Config
.m_GfxColorDepth
= Depth
;
655 g_Config
.m_GfxScreenWidth
= s_aModes
[NewSelected
].m_Width
;
656 g_Config
.m_GfxScreenHeight
= s_aModes
[NewSelected
].m_Height
;
657 CheckSettings
= true;
661 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
662 if(DoButton_CheckBox(&g_Config
.m_GfxFullscreen
, Localize("Fullscreen"), g_Config
.m_GfxFullscreen
, &Button
))
664 g_Config
.m_GfxFullscreen
^= 1;
665 CheckSettings
= true;
668 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
669 if(DoButton_CheckBox(&g_Config
.m_GfxVsync
, Localize("V-Sync"), g_Config
.m_GfxVsync
, &Button
))
671 g_Config
.m_GfxVsync
^= 1;
672 CheckSettings
= true;
675 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
676 if(DoButton_CheckBox_Number(&g_Config
.m_GfxFsaaSamples
, Localize("FSAA samples"), g_Config
.m_GfxFsaaSamples
, &Button
))
678 g_Config
.m_GfxFsaaSamples
= (g_Config
.m_GfxFsaaSamples
+1)%17;
679 CheckSettings
= true;
682 MainView
.HSplitTop(40.0f
, &Button
, &MainView
);
683 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
684 if(DoButton_CheckBox(&g_Config
.m_GfxTextureQuality
, Localize("Quality Textures"), g_Config
.m_GfxTextureQuality
, &Button
))
686 g_Config
.m_GfxTextureQuality
^= 1;
687 CheckSettings
= true;
690 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
691 if(DoButton_CheckBox(&g_Config
.m_GfxTextureCompression
, Localize("Texture Compression"), g_Config
.m_GfxTextureCompression
, &Button
))
693 g_Config
.m_GfxTextureCompression
^= 1;
694 CheckSettings
= true;
697 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
698 if(DoButton_CheckBox(&g_Config
.m_GfxHighDetail
, Localize("High Detail"), g_Config
.m_GfxHighDetail
, &Button
))
699 g_Config
.m_GfxHighDetail
^= 1;
701 // check if the new settings require a restart
704 if(s_GfxScreenWidth
== g_Config
.m_GfxScreenWidth
&&
705 s_GfxScreenHeight
== g_Config
.m_GfxScreenHeight
&&
706 s_GfxColorDepth
== g_Config
.m_GfxColorDepth
&&
707 s_GfxFullscreen
== g_Config
.m_GfxFullscreen
&&
708 s_GfxVsync
== g_Config
.m_GfxVsync
&&
709 s_GfxFsaaSamples
== g_Config
.m_GfxFsaaSamples
&&
710 s_GfxTextureQuality
== g_Config
.m_GfxTextureQuality
&&
711 s_GfxTextureCompression
== g_Config
.m_GfxTextureCompression
)
712 m_NeedRestartGraphics
= false;
714 m_NeedRestartGraphics
= true;
720 MainView
.HSplitTop(20.0f
, 0, &MainView
);
721 MainView
.HSplitTop(20.0f
, &Text
, &MainView
);
722 //text.VSplitLeft(15.0f, 0, &text);
723 UI()->DoLabelScaled(&Text
, Localize("UI Color"), 14.0f
, -1);
725 const char *paLabels
[] = {
730 int *pColorSlider
[4] = {&g_Config
.m_UiColorHue
, &g_Config
.m_UiColorSat
, &g_Config
.m_UiColorLht
, &g_Config
.m_UiColorAlpha
};
731 for(int s
= 0; s
< 4; s
++)
734 MainView
.HSplitTop(19.0f
, &Button
, &MainView
);
735 Button
.VMargin(15.0f
, &Button
);
736 Button
.VSplitLeft(100.0f
, &Text
, &Button
);
737 //Button.VSplitRight(5.0f, &Button, 0);
738 Button
.HSplitTop(4.0f
, 0, &Button
);
740 float k
= (*pColorSlider
[s
]) / 255.0f
;
741 k
= DoScrollbarH(pColorSlider
[s
], &Button
, k
);
742 *pColorSlider
[s
] = (int)(k
*255.0f
);
743 UI()->DoLabelScaled(&Text
, paLabels
[s
], 15.0f
, -1);
747 void CMenus::RenderSettingsSound(CUIRect MainView
)
750 MainView
.VSplitMid(&MainView
, 0);
751 static int s_SndEnable
= g_Config
.m_SndEnable
;
752 static int s_SndRate
= g_Config
.m_SndRate
;
754 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
755 if(DoButton_CheckBox(&g_Config
.m_SndEnable
, Localize("Use sounds"), g_Config
.m_SndEnable
, &Button
))
757 g_Config
.m_SndEnable
^= 1;
758 if(g_Config
.m_SndEnable
)
760 if(g_Config
.m_SndMusic
)
761 m_pClient
->m_pSounds
->Play(CSounds::CHN_MUSIC
, SOUND_MENU
, 1.0f
, vec2(0, 0));
764 m_pClient
->m_pSounds
->Stop(SOUND_MENU
);
765 m_NeedRestartSound
= g_Config
.m_SndEnable
&& (!s_SndEnable
|| s_SndRate
!= g_Config
.m_SndRate
);
768 if(!g_Config
.m_SndEnable
)
771 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
772 if(DoButton_CheckBox(&g_Config
.m_SndMusic
, Localize("Play background music"), g_Config
.m_SndMusic
, &Button
))
774 g_Config
.m_SndMusic
^= 1;
775 if(g_Config
.m_SndMusic
)
776 m_pClient
->m_pSounds
->Play(CSounds::CHN_MUSIC
, SOUND_MENU
, 1.0f
, vec2(0, 0));
778 m_pClient
->m_pSounds
->Stop(SOUND_MENU
);
781 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
782 if(DoButton_CheckBox(&g_Config
.m_SndNonactiveMute
, Localize("Mute when not active"), g_Config
.m_SndNonactiveMute
, &Button
))
783 g_Config
.m_SndNonactiveMute
^= 1;
788 str_format(aBuf
, sizeof(aBuf
), "%d", g_Config
.m_SndRate
);
789 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
790 UI()->DoLabelScaled(&Button
, Localize("Sample rate"), 14.0f
, -1);
791 Button
.VSplitLeft(190.0f
, 0, &Button
);
792 static float Offset
= 0.0f
;
793 DoEditBox(&g_Config
.m_SndRate
, &Button
, aBuf
, sizeof(aBuf
), 14.0f
, &Offset
);
794 g_Config
.m_SndRate
= max(1, str_toint(aBuf
));
795 m_NeedRestartSound
= !s_SndEnable
|| s_SndRate
!= g_Config
.m_SndRate
;
800 CUIRect Button
, Label
;
801 MainView
.HSplitTop(5.0f
, &Button
, &MainView
);
802 MainView
.HSplitTop(20.0f
, &Button
, &MainView
);
803 Button
.VSplitLeft(190.0f
, &Label
, &Button
);
804 Button
.HMargin(2.0f
, &Button
);
805 UI()->DoLabelScaled(&Label
, Localize("Sound volume"), 14.0f
, -1);
806 g_Config
.m_SndVolume
= (int)(DoScrollbarH(&g_Config
.m_SndVolume
, &Button
, g_Config
.m_SndVolume
/100.0f
)*100.0f
);
807 MainView
.HSplitTop(20.0f
, 0, &MainView
);
815 CLanguage(const char *n
, const char *f
, int Code
) : m_Name(n
), m_FileName(f
), m_CountryCode(Code
) {}
821 bool operator<(const CLanguage
&Other
) { return m_Name
< Other
.m_Name
; }
824 void LoadLanguageIndexfile(IStorage
*pStorage
, IConsole
*pConsole
, sorted_array
<CLanguage
> *pLanguages
)
826 IOHANDLE File
= pStorage
->OpenFile("languages/index.txt", IOFLAG_READ
, IStorage::TYPE_ALL
);
829 pConsole
->Print(IConsole::OUTPUT_LEVEL_ADDINFO
, "localization", "couldn't open index file");
834 char aReplacement
[128];
835 CLineReader LineReader
;
836 LineReader
.Init(File
);
838 while((pLine
= LineReader
.Get()))
840 if(!str_length(pLine
) || pLine
[0] == '#') // skip empty lines and comments
843 str_copy(aOrigin
, pLine
, sizeof(aOrigin
));
845 pLine
= LineReader
.Get();
848 pConsole
->Print(IConsole::OUTPUT_LEVEL_ADDINFO
, "localization", "unexpected end of index file");
852 if(pLine
[0] != '=' || pLine
[1] != '=' || pLine
[2] != ' ')
855 str_format(aBuf
, sizeof(aBuf
), "malform replacement for index '%s'", aOrigin
);
856 pConsole
->Print(IConsole::OUTPUT_LEVEL_ADDINFO
, "localization", aBuf
);
857 (void)LineReader
.Get();
860 str_copy(aReplacement
, pLine
+3, sizeof(aReplacement
));
862 pLine
= LineReader
.Get();
865 pConsole
->Print(IConsole::OUTPUT_LEVEL_ADDINFO
, "localization", "unexpected end of index file");
869 if(pLine
[0] != '=' || pLine
[1] != '=' || pLine
[2] != ' ')
872 str_format(aBuf
, sizeof(aBuf
), "malform replacement for index '%s'", aOrigin
);
873 pConsole
->Print(IConsole::OUTPUT_LEVEL_ADDINFO
, "localization", aBuf
);
878 str_format(aFileName
, sizeof(aFileName
), "languages/%s.txt", aOrigin
);
879 pLanguages
->add(CLanguage(aReplacement
, aFileName
, str_toint(pLine
+3)));
884 void CMenus::RenderLanguageSelection(CUIRect MainView
)
886 static int s_LanguageList
= 0;
887 static int s_SelectedLanguage
= 0;
888 static sorted_array
<CLanguage
> s_Languages
;
889 static float s_ScrollValue
= 0;
891 if(s_Languages
.size() == 0)
893 s_Languages
.add(CLanguage("English", "", 826));
894 LoadLanguageIndexfile(Storage(), Console(), &s_Languages
);
895 for(int i
= 0; i
< s_Languages
.size(); i
++)
896 if(str_comp(s_Languages
[i
].m_FileName
, g_Config
.m_ClLanguagefile
) == 0)
898 s_SelectedLanguage
= i
;
903 int OldSelected
= s_SelectedLanguage
;
905 UiDoListboxStart(&s_LanguageList
, &MainView
, 24.0f
, Localize("Language"), "", s_Languages
.size(), 1, s_SelectedLanguage
, s_ScrollValue
);
907 for(sorted_array
<CLanguage
>::range r
= s_Languages
.all(); !r
.empty(); r
.pop_front())
909 CListboxItem Item
= UiDoListboxNextItem(&r
.front());
914 Item
.m_Rect
.VSplitLeft(Item
.m_Rect
.h
*2.0f
, &Rect
, &Item
.m_Rect
);
915 Rect
.VMargin(6.0f
, &Rect
);
916 Rect
.HMargin(3.0f
, &Rect
);
917 Graphics()->TextureSet(m_pClient
->m_pCountryFlags
->GetByCountryCode(r
.front().m_CountryCode
)->m_Texture
);
918 Graphics()->QuadsBegin();
919 IGraphics::CQuadItem
QuadItem(Rect
.x
, Rect
.y
, Rect
.w
, Rect
.h
);
920 Graphics()->QuadsDrawTL(&QuadItem
, 1);
921 Graphics()->QuadsEnd();
922 Item
.m_Rect
.HSplitTop(2.0f
, 0, &Item
.m_Rect
);
923 UI()->DoLabelScaled(&Item
.m_Rect
, r
.front().m_Name
, 16.0f
, -1);
927 s_SelectedLanguage
= UiDoListboxEnd(&s_ScrollValue
, 0);
929 if(OldSelected
!= s_SelectedLanguage
)
931 str_copy(g_Config
.m_ClLanguagefile
, s_Languages
[s_SelectedLanguage
].m_FileName
, sizeof(g_Config
.m_ClLanguagefile
));
932 g_Localization
.Load(s_Languages
[s_SelectedLanguage
].m_FileName
, Storage(), Console());
936 void CMenus::RenderSettings(CUIRect MainView
)
938 static int s_SettingsPage
= 0;
941 CUIRect Temp
, TabBar
, RestartWarning
;
942 MainView
.HSplitBottom(15.0f
, &MainView
, &RestartWarning
);
943 MainView
.VSplitRight(120.0f
, &MainView
, &TabBar
);
944 RenderTools()->DrawUIRect(&MainView
, ms_ColorTabbarActive
, CUI::CORNER_B
|CUI::CORNER_TL
, 10.0f
);
945 TabBar
.HSplitTop(50.0f
, &Temp
, &TabBar
);
946 RenderTools()->DrawUIRect(&Temp
, ms_ColorTabbarActive
, CUI::CORNER_R
, 10.0f
);
948 MainView
.HSplitTop(10.0f
, 0, &MainView
);
952 const char *aTabs
[] = {
953 Localize("Language"),
957 Localize("Controls"),
958 Localize("Graphics"),
961 int NumTabs
= (int)(sizeof(aTabs
)/sizeof(*aTabs
));
963 for(int i
= 0; i
< NumTabs
; i
++)
965 TabBar
.HSplitTop(10, &Button
, &TabBar
);
966 TabBar
.HSplitTop(26, &Button
, &TabBar
);
967 if(DoButton_MenuTab(aTabs
[i
], aTabs
[i
], s_SettingsPage
== i
, &Button
, CUI::CORNER_R
))
971 MainView
.Margin(10.0f
, &MainView
);
973 if(s_SettingsPage
== 0)
974 RenderLanguageSelection(MainView
);
975 else if(s_SettingsPage
== 1)
976 RenderSettingsGeneral(MainView
);
977 else if(s_SettingsPage
== 2)
978 RenderSettingsPlayer(MainView
);
979 else if(s_SettingsPage
== 3)
980 RenderSettingsTee(MainView
);
981 else if(s_SettingsPage
== 4)
982 RenderSettingsControls(MainView
);
983 else if(s_SettingsPage
== 5)
984 RenderSettingsGraphics(MainView
);
985 else if(s_SettingsPage
== 6)
986 RenderSettingsSound(MainView
);
988 if(m_NeedRestartGraphics
|| m_NeedRestartSound
)
989 UI()->DoLabel(&RestartWarning
, Localize("You must restart the game for all settings to take effect."), 15.0f
, -1);