Bug Summary

File:Screens.c
Warning:line 1621, column 2
Value stored to 'offset' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple amd64-unknown-openbsd6.8 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name Screens.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mthread-model posix -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/local/lib/clang/10.0.1 -I /usr/X11R6/include -I /usr/local/include -fdebug-compilation-dir /home/ben/Projects/ClassiCube/src -ferror-limit 19 -fmessage-length 0 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -fobjc-runtime=gnustep -fdiagnostics-show-option -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/ClassiCube/src/scan/2020-12-10-180422-33404-1 -x c Screens.c
1#include "Screens.h"
2#include "Widgets.h"
3#include "Game.h"
4#include "Event.h"
5#include "Platform.h"
6#include "Inventory.h"
7#include "Drawer2D.h"
8#include "Graphics.h"
9#include "Funcs.h"
10#include "TexturePack.h"
11#include "Model.h"
12#include "Generator.h"
13#include "Server.h"
14#include "Chat.h"
15#include "ExtMath.h"
16#include "Window.h"
17#include "Camera.h"
18#include "Http.h"
19#include "Block.h"
20#include "Menus.h"
21#include "World.h"
22#include "Utils.h"
23
24#define CHAT_MAX_STATUS(sizeof(Chat_Status) / sizeof(Chat_Status[0])) Array_Elems(Chat_Status)(sizeof(Chat_Status) / sizeof(Chat_Status[0]))
25#define CHAT_MAX_BOTTOMRIGHT(sizeof(Chat_BottomRight) / sizeof(Chat_BottomRight[0])) Array_Elems(Chat_BottomRight)(sizeof(Chat_BottomRight) / sizeof(Chat_BottomRight[0]))
26#define CHAT_MAX_CLIENTSTATUS(sizeof(Chat_ClientStatus) / sizeof(Chat_ClientStatus[0])) Array_Elems(Chat_ClientStatus)(sizeof(Chat_ClientStatus) / sizeof(Chat_ClientStatus[0]))
27
28int Screen_FInput(void* s, int key) { return false0; }
29int Screen_FKeyPress(void* s, char keyChar) { return false0; }
30int Screen_FText(void* s, const cc_string* str) { return false0; }
31int Screen_FMouseScroll(void* s, float delta) { return false0; }
32int Screen_FPointer(void* s, int id, int x, int y) { return false0; }
33
34int Screen_TInput(void* s, int key) { return true1; }
35int Screen_TKeyPress(void* s, char keyChar) { return true1; }
36int Screen_TText(void* s, const cc_string* str) { return true1; }
37int Screen_TMouseScroll(void* s, float delta) { return true1; }
38int Screen_TPointer(void* s, int id, int x, int y) { return true1; }
39
40void Screen_NullFunc(void* screen) { }
41void Screen_NullUpdate(void* screen, double delta) { }
42int Screen_InputDown(void* screen, int key) { return key < KEY_F1 || key > KEY_F24; }
43
44CC_NOINLINE__attribute__((noinline)) static cc_bool IsOnlyChatActive(void) {
45 struct Screen* s;
46 int i;
47
48 for (i = 0; i < Gui.ScreensCount; i++) {
49 s = Gui_Screens[i];
50 if (s->grabsInput && s != (struct Screen*)Gui_Chat) return false0;
51 }
52 return true1;
53}
54
55
56/*########################################################################################################################*
57*--------------------------------------------------------HUDScreen--------------------------------------------------------*
58*#########################################################################################################################*/
59static struct HUDScreen {
60 Screen_Bodyconst struct ScreenVTABLE* VTABLE; cc_bool grabsInput; cc_bool
blocksWorld; cc_bool closable; cc_bool dirty; int maxVertices
; GfxResourceID vb; struct Widget** widgets; int numWidgets;
61 struct FontDesc font;
62 struct TextWidget line1, line2;
63 struct TextAtlas posAtlas;
64 double accumulator;
65 int frames, fps;
66 cc_bool hacksChanged;
67 float lastSpeed;
68 int lastFov;
69 struct HotbarWidget hotbar;
70} HUDScreen_Instance;
71
72static void HUDScreen_MakeText(struct HUDScreen* s, cc_string* status) {
73 int indices, ping;
74 s->fps = (int)(s->frames / s->accumulator);
75 String_Format1(status, "%i fps, ", &s->fps);
76
77 if (Game_ClassicMode) {
78 String_Format1(status, "%i chunk updates", &Game.ChunkUpdates);
79 } else {
80 if (Game.ChunkUpdates) {
81 String_Format1(status, "%i chunks/s, ", &Game.ChunkUpdates);
82 }
83
84 indices = ICOUNT(Game_Vertices)(((Game_Vertices) >> 2) * 6);
85 String_Format1(status, "%i vertices", &indices);
86
87 ping = Ping_AveragePingMS();
88 if (ping) String_Format1(status, ", ping %i ms", &ping);
89 }
90}
91
92static void HUDScreen_DrawPosition(struct HUDScreen* s) {
93 struct VertexTextured vertices[4 * 64];
94 struct VertexTextured* ptr = vertices;
95 PackedCol col = PACKEDCOL_WHITE(((cc_uint8)(255) << 0) | ((cc_uint8)(255) << 8) |
((cc_uint8)(255) << 16) | ((cc_uint8)(255) << 24
))
;
96
97 struct TextAtlas* atlas = &s->posAtlas;
98 struct Texture tex;
99 IVec3 pos;
100 int count;
101
102 /* Make "Position: " prefix */
103 tex = atlas->tex;
104 tex.X = 2; tex.Width = atlas->offset;
105 Gfx_Make2DQuad(&tex, col, &ptr);
106
107 IVec3_Floor(&pos, &LocalPlayer_Instance.Base.Position);
108 atlas->curX = atlas->offset + 2;
109
110 /* Make (X, Y, Z) suffix */
111 TextAtlas_Add(atlas, 13, &ptr);
112 TextAtlas_AddInt(atlas, pos.X, &ptr);
113 TextAtlas_Add(atlas, 11, &ptr);
114 TextAtlas_AddInt(atlas, pos.Y, &ptr);
115 TextAtlas_Add(atlas, 11, &ptr);
116 TextAtlas_AddInt(atlas, pos.Z, &ptr);
117 TextAtlas_Add(atlas, 14, &ptr);
118
119 Gfx_BindTexture(atlas->tex.ID);
120 /* TODO: Do we need to use a separate VB here? */
121 count = (int)(ptr - vertices);
122 Gfx_UpdateDynamicVb_IndexedTris(Models.Vb, vertices, count);
123}
124
125static float HUDScreen_CalcHacksSpeed(void) {
126 struct HacksComp* hacks = &LocalPlayer_Instance.Hacks;
127 float speed = 0;
128 if (!hacks->CanSpeed) return 0;
129
130 if (hacks->HalfSpeeding) speed += hacks->SpeedMultiplier / 2;
131 if (hacks->Speeding) speed += hacks->SpeedMultiplier;
132 return speed;
133}
134
135static cc_bool HUDScreen_HasHacksChanged(struct HUDScreen* s) {
136 struct HacksComp* hacks = &LocalPlayer_Instance.Hacks;
137 float speed = HUDScreen_CalcHacksSpeed();
138 return speed != s->lastSpeed || Game_Fov != s->lastFov || s->hacksChanged;
139}
140
141static void HUDScreen_UpdateHackState(struct HUDScreen* s) {
142 cc_string status; char statusBuffer[STRING_SIZE64 * 2];
143 struct HacksComp* hacks = &LocalPlayer_Instance.Hacks;
144 float speed = HUDScreen_CalcHacksSpeed();
145
146 s->lastSpeed = speed; s->lastFov = Game_Fov;
147 s->hacksChanged = false0;
148
149 String_InitArray(status, statusBuffer)status.buffer = statusBuffer; status.length = 0; status.capacity
= sizeof(statusBuffer);
;
150 if (Game_Fov != Game_DefaultFov) {
151 String_Format1(&status, "Zoom fov %i ", &Game_Fov);
152 }
153
154 if (hacks->Flying) String_AppendConst(&status, "Fly ON ");
155 if (speed) String_Format1(&status, "Speed %f1x ", &speed);
156 if (hacks->Noclip) String_AppendConst(&status, "Noclip ON ");
157
158 TextWidget_Set(&s->line2, &status, &s->font);
159}
160
161static void HUDScreen_Update(void* screen, double delta) {
162 struct HUDScreen* s = (struct HUDScreen*)screen;
163 cc_string status; char statusBuffer[STRING_SIZE64 * 2];
164
165 s->frames++;
166 s->accumulator += delta;
167 if (s->accumulator < 1.0) return;
168
169 String_InitArray(status, statusBuffer)status.buffer = statusBuffer; status.length = 0; status.capacity
= sizeof(statusBuffer);
;
170 HUDScreen_MakeText(s, &status);
171
172 TextWidget_Set(&s->line1, &status, &s->font);
173 s->accumulator = 0.0;
174 s->frames = 0;
175 Game.ChunkUpdates = 0;
176}
177
178static void HUDScreen_ContextLost(void* screen) {
179 struct HUDScreen* s = (struct HUDScreen*)screen;
180 Font_Free(&s->font);
181 TextAtlas_Free(&s->posAtlas);
182 Elem_Free(&s->hotbar)(&s->hotbar)->VTABLE->Free(&s->hotbar);
183 Elem_Free(&s->line1)(&s->line1)->VTABLE->Free(&s->line1);
184 Elem_Free(&s->line2)(&s->line2)->VTABLE->Free(&s->line2);
185}
186
187static void HUDScreen_ContextRecreated(void* screen) {
188 static const cc_string chars = String_FromConst("0123456789-, ()"){ "0123456789-, ()", (sizeof("0123456789-, ()") - 1), (sizeof
("0123456789-, ()") - 1)}
;
189 static const cc_string prefix = String_FromConst("Position: "){ "Position: ", (sizeof("Position: ") - 1), (sizeof("Position: "
) - 1)}
;
190
191 struct HUDScreen* s = (struct HUDScreen*)screen;
192 struct TextWidget* line1 = &s->line1;
193 struct TextWidget* line2 = &s->line2;
194
195 Drawer2D_MakeFont(&s->font, 16, FONT_FLAGS_PADDING);
196 Font_SetPadding(&s->font, 2);
197 HotbarWidget_SetFont(&s->hotbar, &s->font);
198
199 HUDScreen_Update(s, 1.0);
200 TextAtlas_Make(&s->posAtlas, &chars, &s->font, &prefix);
201
202 if (Game_ClassicMode) {
203 TextWidget_SetConst(line2, "0.30", &s->font);
204 } else {
205 HUDScreen_UpdateHackState(s);
206 }
207}
208
209static void HUDScreen_BuildMesh(void* screen) { }
210
211static void HUDScreen_Layout(void* screen) {
212 struct HUDScreen* s = (struct HUDScreen*)screen;
213 struct TextWidget* line1 = &s->line1;
214 struct TextWidget* line2 = &s->line2;
215 int posY;
216
217 Widget_SetLocation(line1, ANCHOR_MIN, ANCHOR_MIN, 2, 2);
218 posY = line1->y + line1->height;
219 s->posAtlas.tex.Y = posY;
220 Widget_SetLocation(line2, ANCHOR_MIN, ANCHOR_MIN, 2, 0);
221
222 if (Game_ClassicMode) {
223 /* Swap around so 0.30 version is at top */
224 line2->yOffset = line1->yOffset;
225 line1->yOffset = posY;
226 Widget_Layout(line1)(line1)->VTABLE->Reposition(line1);
227 } else {
228 /* We can't use y in TextWidget_Make because that DPI scales it */
229 line2->yOffset = posY + s->posAtlas.tex.Height;
230 }
231
232 Widget_Layout(&s->hotbar)(&s->hotbar)->VTABLE->Reposition(&s->hotbar
)
;
233 Widget_Layout(line2)(line2)->VTABLE->Reposition(line2);
234}
235
236static int HUDScreen_KeyDown(void* screen, int key) {
237 struct HUDScreen* s = (struct HUDScreen*)screen;
238 return Elem_HandlesKeyDown(&s->hotbar, key)(&s->hotbar)->VTABLE->HandlesKeyDown(&s->
hotbar, key)
;
239}
240
241static int HUDScreen_KeyUp(void* screen, int key) {
242 struct HUDScreen* s = (struct HUDScreen*)screen;
243 return Elem_HandlesKeyUp(&s->hotbar, key)(&s->hotbar)->VTABLE->HandlesKeyUp(&s->hotbar
, key)
;
244}
245
246static int HUDscreen_PointerDown(void* screen, int id, int x, int y) {
247 struct HUDScreen* s = (struct HUDScreen*)screen;
248 if (Input_TouchMode0 || Gui_GetInputGrab()) {
249 return Elem_HandlesPointerDown(&s->hotbar, id, x, y)(&s->hotbar)->VTABLE->HandlesPointerDown(&s->
hotbar, id, x, y)
;
250 }
251 return false0;
252}
253
254static void HUDScreen_HacksChanged(void* obj) {
255 ((struct HUDScreen*)obj)->hacksChanged = true1;
256}
257
258static void HUDScreen_Init(void* screen) {
259 struct HUDScreen* s = (struct HUDScreen*)screen;
260 HotbarWidget_Create(&s->hotbar);
261 TextWidget_Init(&s->line1);
262 TextWidget_Init(&s->line2);
263 Event_Register_(&UserEvents.HacksStateChanged, screen, HUDScreen_HacksChanged)Event_Register((struct Event_Void*)(&UserEvents.HacksStateChanged
), screen, (Event_Void_Callback)(HUDScreen_HacksChanged))
;
264}
265
266static void HUDScreen_Render(void* screen, double delta) {
267 struct HUDScreen* s = (struct HUDScreen*)screen;
268 if (Game_HideGui) return;
269
270 /* TODO: If Game_ShowFps is off and not classic mode, we should just return here */
271 Gfx_SetTexturing(true1);
272 if (Gui.ShowFPS) Elem_Render(&s->line1, delta)(&s->line1)->VTABLE->Render(&s->line1, delta
)
;
273
274 if (Game_ClassicMode) {
275 Elem_Render(&s->line2, delta)(&s->line2)->VTABLE->Render(&s->line2, delta
)
;
276 } else if (IsOnlyChatActive() && Gui.ShowFPS) {
277 if (HUDScreen_HasHacksChanged(s)) HUDScreen_UpdateHackState(s);
278 HUDScreen_DrawPosition(s);
279 Elem_Render(&s->line2, delta)(&s->line2)->VTABLE->Render(&s->line2, delta
)
;
280 }
281
282 if (!Gui_GetBlocksWorld()) Elem_Render(&s->hotbar, delta)(&s->hotbar)->VTABLE->Render(&s->hotbar, delta
)
;
283 Gfx_SetTexturing(false0);
284}
285
286static void HUDScreen_Free(void* screen) {
287 Event_Unregister_(&UserEvents.HacksStateChanged, screen, HUDScreen_HacksChanged)Event_Unregister((struct Event_Void*)(&UserEvents.HacksStateChanged
), screen, (Event_Void_Callback)(HUDScreen_HacksChanged))
;
288}
289
290static const struct ScreenVTABLE HUDScreen_VTABLE = {
291 HUDScreen_Init, HUDScreen_Update, HUDScreen_Free,
292 HUDScreen_Render, HUDScreen_BuildMesh,
293 HUDScreen_KeyDown, HUDScreen_KeyUp, Screen_FKeyPress, Screen_FText,
294 HUDscreen_PointerDown, Screen_FPointer, Screen_FPointer, Screen_FMouseScroll,
295 HUDScreen_Layout, HUDScreen_ContextLost, HUDScreen_ContextRecreated
296};
297void HUDScreen_Show(void) {
298 struct HUDScreen* s = &HUDScreen_Instance;
299 s->VTABLE = &HUDScreen_VTABLE;
300 Gui_HUD = s;
301 Gui_Add((struct Screen*)s, GUI_PRIORITY_HUD);
302}
303
304struct Widget* HUDScreen_GetHotbar(void) {
305 return (struct Widget*)&HUDScreen_Instance.hotbar;
306}
307
308
309/*########################################################################################################################*
310*----------------------------------------------------TabListOverlay-----------------------------------------------------*
311*#########################################################################################################################*/
312#define GROUP_NAME_ID((cc_uint16)65535) UInt16_MaxValue((cc_uint16)65535)
313#define LIST_COLUMN_PADDING5 5
314#define LIST_NAMES_PER_COLUMN16 16
315#define TABLIST_MAX_ENTRIES(256 * 2) (TABLIST_MAX_NAMES256 * 2)
316typedef int (*TabListEntryCompare)(int x, int y);
317
318static struct TabListOverlay {
319 Screen_Bodyconst struct ScreenVTABLE* VTABLE; cc_bool grabsInput; cc_bool
blocksWorld; cc_bool closable; cc_bool dirty; int maxVertices
; GfxResourceID vb; struct Widget** widgets; int numWidgets;
320 int x, y, width, height;
321 cc_bool active, classic;
322 int namesCount, elementOffset;
323 struct TextWidget title;
324 struct FontDesc font;
325 TabListEntryCompare compare;
326 cc_uint16 ids[TABLIST_MAX_ENTRIES(256 * 2)];
327 struct Texture textures[TABLIST_MAX_ENTRIES(256 * 2)];
328} TabListOverlay_Instance;
329#define TABLIST_MAX_VERTICES(4 + 4 * (256 * 2)) (TEXTWIDGET_MAX4 + 4 * TABLIST_MAX_ENTRIES(256 * 2))
330
331static void TabListOverlay_DrawText(struct Texture* tex, struct TabListOverlay* s, const cc_string* name) {
332 cc_string tmp; char tmpBuffer[STRING_SIZE64];
333 struct DrawTextArgs args;
334
335 if (Game_PureClassic(Game_ClassicMode && !Game_ClassicHacks)) {
336 String_InitArray(tmp, tmpBuffer)tmp.buffer = tmpBuffer; tmp.length = 0; tmp.capacity = sizeof
(tmpBuffer);
;
337 String_AppendColorless(&tmp, name);
338 } else {
339 tmp = *name;
340 }
341
342 DrawTextArgs_Make(&args, &tmp, &s->font, !s->classic);
343 Drawer2D_MakeTextTexture(tex, &args);
344}
345
346static int TabListOverlay_GetColumnWidth(struct TabListOverlay* s, int column) {
347 int i = column * LIST_NAMES_PER_COLUMN16;
348 int end = min(s->namesCount, i + LIST_NAMES_PER_COLUMN)((s->namesCount) < (i + 16) ? (s->namesCount) : (i +
16))
;
349 int maxWidth = 0;
350
351 for (; i < end; i++) {
352 maxWidth = max(maxWidth, s->textures[i].Width)((maxWidth) > (s->textures[i].Width) ? (maxWidth) : (s->
textures[i].Width))
;
353 }
354 return maxWidth + LIST_COLUMN_PADDING5 + s->elementOffset;
355}
356
357static int TabListOverlay_GetColumnHeight(struct TabListOverlay* s, int column) {
358 int i = column * LIST_NAMES_PER_COLUMN16;
359 int end = min(s->namesCount, i + LIST_NAMES_PER_COLUMN)((s->namesCount) < (i + 16) ? (s->namesCount) : (i +
16))
;
360 int height = 0;
361
362 for (; i < end; i++) {
363 height += s->textures[i].Height + 1;
364 }
365 return height;
366}
367
368static void TabListOverlay_SetColumnPos(struct TabListOverlay* s, int column, int x, int y) {
369 struct Texture tex;
370 int i = column * LIST_NAMES_PER_COLUMN16;
371 int end = min(s->namesCount, i + LIST_NAMES_PER_COLUMN)((s->namesCount) < (i + 16) ? (s->namesCount) : (i +
16))
;
372
373 for (; i < end; i++) {
374 tex = s->textures[i];
375 tex.X = x; tex.Y = y - 10;
376
377 y += tex.Height + 1;
378 /* offset player names a bit, compared to group name */
379 if (!s->classic && s->ids[i] != GROUP_NAME_ID((cc_uint16)65535)) {
380 tex.X += s->elementOffset;
381 }
382 s->textures[i] = tex;
383 }
384}
385
386static void TabListOverlay_Layout(void* screen) {
387 struct TabListOverlay* s = (struct TabListOverlay*)screen;
388 int minWidth, minHeight, paddingX, paddingY;
389 int i, x, y, width = 0, height = 0;
390 int columns = Math_CeilDiv(s->namesCount, LIST_NAMES_PER_COLUMN16);
391
392 for (i = 0; i < columns; i++) {
393 width += TabListOverlay_GetColumnWidth(s, i);
394 y = TabListOverlay_GetColumnHeight(s, i);
395 height = max(height, y)((height) > (y) ? (height) : (y));
396 }
397
398 minWidth = Display_ScaleX(480);
399 width = max(width, minWidth)((width) > (minWidth) ? (width) : (minWidth));
400 paddingX = Display_ScaleX(10);
401 paddingY = Display_ScaleY(10);
402
403 width += paddingX * 2;
404 height += paddingY * 2;
405
406 y = WindowInfo.Height / 4 - height / 2;
407 s->x = Gui_CalcPos(ANCHOR_CENTRE, 0, width , WindowInfo.Width );
408 s->y = Gui_CalcPos(ANCHOR_CENTRE, -max(0, y)((0) > (y) ? (0) : (y)), height, WindowInfo.Height);
409
410 x = s->x + paddingX;
411 y = s->y + paddingY;
412
413 for (i = 0; i < columns; i++) {
414 TabListOverlay_SetColumnPos(s, i, x, y);
415 x += TabListOverlay_GetColumnWidth(s, i);
416 }
417
418 s->y -= (s->title.height + paddingY);
419 s->width = width;
420 minHeight = Display_ScaleY(300);
421 s->height = max(minHeight, height + s->title.height)((minHeight) > (height + s->title.height) ? (minHeight)
: (height + s->title.height))
;
422
423 s->title.horAnchor = ANCHOR_CENTRE;
424 s->title.yOffset = s->y + paddingY / 2;
425 Widget_Layout(&s->title)(&s->title)->VTABLE->Reposition(&s->title
)
;
426}
427
428static void TabListOverlay_AddName(struct TabListOverlay* s, EntityID id, int index) {
429 cc_string name;
430 /* insert at end of list */
431 if (index == -1) { index = s->namesCount; s->namesCount++; }
432
433 name = TabList_UNSAFE_GetList(id)StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[id] - 2);
;
434 s->ids[index] = id;
435 TabListOverlay_DrawText(&s->textures[index], s, &name);
436}
437
438static void TabListOverlay_DeleteAt(struct TabListOverlay* s, int i) {
439 Gfx_DeleteTexture(&s->textures[i].ID);
440
441 for (; i < s->namesCount - 1; i++) {
442 s->ids[i] = s->ids[i + 1];
443 s->textures[i] = s->textures[i + 1];
444 }
445
446 s->namesCount--;
447 s->ids[s->namesCount] = 0;
448 s->textures[s->namesCount].ID = 0;
449}
450
451static void TabListOverlay_AddGroup(struct TabListOverlay* s, int id, int* index) {
452 cc_string group;
453 int i;
454 group = TabList_UNSAFE_GetGroup(id)StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[id] - 1);
;
455
456 for (i = Array_Elems(s->ids)(sizeof(s->ids) / sizeof(s->ids[0])) - 1; i > (*index); i--) {
457 s->ids[i] = s->ids[i - 1];
458 s->textures[i] = s->textures[i - 1];
459 }
460
461 s->ids[*index] = GROUP_NAME_ID((cc_uint16)65535);
462 TabListOverlay_DrawText(&s->textures[*index], s, &group);
463
464 (*index)++;
465 s->namesCount++;
466}
467
468static int TabListOverlay_GetGroupCount(struct TabListOverlay* s, int id, int i) {
469 cc_string group, curGroup;
470 int count;
471 group = TabList_UNSAFE_GetGroup(id)StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[id] - 1);
;
472
473 for (count = 0; i < s->namesCount; i++, count++) {
474 curGroup = TabList_UNSAFE_GetGroup(s->ids[i])StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[s->ids[i]] - 1);
;
475 if (!String_CaselessEquals(&group, &curGroup)) break;
476 }
477 return count;
478}
479
480static int TabListOverlay_PlayerCompare(int x, int y) {
481 cc_string xName; char xNameBuffer[STRING_SIZE64];
482 cc_string yName; char yNameBuffer[STRING_SIZE64];
483 cc_uint8 xRank, yRank;
484 cc_string xNameRaw, yNameRaw;
485
486 xRank = TabList.GroupRanks[x];
487 yRank = TabList.GroupRanks[y];
488 if (xRank != yRank) return (xRank < yRank ? -1 : 1);
489
490 String_InitArray(xName, xNameBuffer)xName.buffer = xNameBuffer; xName.length = 0; xName.capacity =
sizeof(xNameBuffer);
;
491 xNameRaw = TabList_UNSAFE_GetList(x)StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[x] - 2);
;
492 String_AppendColorless(&xName, &xNameRaw);
493
494 String_InitArray(yName, yNameBuffer)yName.buffer = yNameBuffer; yName.length = 0; yName.capacity =
sizeof(yNameBuffer);
;
495 yNameRaw = TabList_UNSAFE_GetList(y)StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[y] - 2);
;
496 String_AppendColorless(&yName, &yNameRaw);
497
498 return String_Compare(&xName, &yName);
499}
500
501static int TabListOverlay_GroupCompare(int x, int y) {
502 cc_string xGroup, yGroup;
503 /* TODO: should we use colourless comparison? ClassicalSharp sorts groups with colours */
504 xGroup = TabList_UNSAFE_GetGroup(x)StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[x] - 1);
;
505 yGroup = TabList_UNSAFE_GetGroup(y)StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[y] - 1);
;
506 return String_Compare(&xGroup, &yGroup);
507}
508
509static void TabListOverlay_QuickSort(int left, int right) {
510 struct Texture* values = TabListOverlay_Instance.textures; struct Texture value;
511 cc_uint16* keys = TabListOverlay_Instance.ids; cc_uint16 key;
512 TabListEntryCompare compareEntries = TabListOverlay_Instance.compare;
513
514 while (left < right) {
515 int i = left, j = right;
516 int pivot = keys[(i + j) / 2];
517
518 /* partition the list */
519 while (i <= j) {
520 while (compareEntries(pivot, keys[i]) > 0) i++;
521 while (compareEntries(pivot, keys[j]) < 0) j--;
522 QuickSort_Swap_KV_Maybe()if (i <= j) { key = keys[i]; keys[i] = keys[j]; keys[j] = key
; value = values[i]; values[i] = values[j]; values[j] = value
; i++; j--;}
;
523 }
524 /* recurse into the smaller subset */
525 QuickSort_Recurse(TabListOverlay_QuickSort)if (j - left <= right - i) { if (left < j) { TabListOverlay_QuickSort
(left, j); } left = i;} else { if (i < right) { TabListOverlay_QuickSort
(i, right); } right = j;}
526 }
527}
528
529static void TabListOverlay_SortEntries(struct TabListOverlay* s) {
530 int i, id, count;
531 if (!s->namesCount) return;
532
533 if (s->classic) {
534 TabListOverlay_Instance.compare = TabListOverlay_PlayerCompare;
535 TabListOverlay_QuickSort(0, s->namesCount - 1);
536 return;
537 }
538
539 /* Sort the list by group */
540 /* Loop backwards, since DeleteAt() reduces NamesCount */
541 for (i = s->namesCount - 1; i >= 0; i--) {
542 if (s->ids[i] != GROUP_NAME_ID((cc_uint16)65535)) continue;
543 TabListOverlay_DeleteAt(s, i);
544 }
545 TabListOverlay_Instance.compare = TabListOverlay_GroupCompare;
546 TabListOverlay_QuickSort(0, s->namesCount - 1);
547
548 /* Sort the entries in each group */
549 TabListOverlay_Instance.compare = TabListOverlay_PlayerCompare;
550 for (i = 0; i < s->namesCount; ) {
551 id = s->ids[i];
552 TabListOverlay_AddGroup(s, id, &i);
553
554 count = TabListOverlay_GetGroupCount(s, id, i);
555 TabListOverlay_QuickSort(i, i + (count - 1));
556 i += count;
557 }
558}
559
560static void TabListOverlay_SortAndLayout(struct TabListOverlay* s) {
561 TabListOverlay_SortEntries(s);
562 TabListOverlay_Layout(s);
563}
564
565static void TabListOverlay_Add(void* obj, int id) {
566 struct TabListOverlay* s = (struct TabListOverlay*)obj;
567 TabListOverlay_AddName(s, id, -1);
568 TabListOverlay_SortAndLayout(s);
569}
570
571static void TabListOverlay_Update(void* obj, int id) {
572 struct TabListOverlay* s = (struct TabListOverlay*)obj;
573 struct Texture tex;
574 int i;
575
576 for (i = 0; i < s->namesCount; i++) {
577 if (s->ids[i] != id) continue;
578 tex = s->textures[i];
579
580 Gfx_DeleteTexture(&tex.ID);
581 TabListOverlay_AddName(s, id, i);
582 TabListOverlay_SortAndLayout(s);
583 return;
584 }
585}
586
587static void TabListOverlay_Remove(void* obj, int id) {
588 struct TabListOverlay* s = (struct TabListOverlay*)obj;
589 int i;
590 for (i = 0; i < s->namesCount; i++) {
591 if (s->ids[i] != id) continue;
592
593 TabListOverlay_DeleteAt(s, i);
594 TabListOverlay_SortAndLayout(s);
595 return;
596 }
597}
598
599static int TabListOverlay_PointerDown(void* screen, int id, int x, int y) {
600 struct TabListOverlay* s = (struct TabListOverlay*)screen;
601 cc_string text; char textBuffer[STRING_SIZE64 * 4];
602 struct Texture tex;
603 cc_string player;
604 int i;
605
606 if (!((struct Screen*)Gui_Chat)->grabsInput) return false0;
607 String_InitArray(text, textBuffer)text.buffer = textBuffer; text.length = 0; text.capacity = sizeof
(textBuffer);
;
608
609 for (i = 0; i < s->namesCount; i++) {
610 if (!s->textures[i].ID || s->ids[i] == GROUP_NAME_ID((cc_uint16)65535)) continue;
611 tex = s->textures[i];
612 if (!Gui_Contains(tex.X, tex.Y, tex.Width, tex.Height, x, y)) continue;
613
614 player = TabList_UNSAFE_GetPlayer(s->ids[i])StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets
[s->ids[i]] - 3);
;
615 String_Format1(&text, "%s ", &player);
616 ChatScreen_AppendInput(&text);
617 return true1;
618 }
619 return false0;
620}
621
622static int TabListOverlay_KeyUp(void* screen, int key) {
623 struct TabListOverlay* s = (struct TabListOverlay*)screen;
624 if (key != KeyBinds[KEYBIND_TABLIST] || Input_TouchMode0) return false0;
625
626 Gui_Remove((struct Screen*)s);
627 return true1;
628}
629
630static void TabListOverlay_ContextLost(void* screen) {
631 struct TabListOverlay* s = (struct TabListOverlay*)screen;
632 int i;
633 for (i = 0; i < s->namesCount; i++) {
634 Gfx_DeleteTexture(&s->textures[i].ID);
635 }
636
637 Elem_Free(&s->title)(&s->title)->VTABLE->Free(&s->title);
638 Font_Free(&s->font);
639}
640
641static void TabListOverlay_ContextRecreated(void* screen) {
642 struct TabListOverlay* s = (struct TabListOverlay*)screen;
643 int size, id;
644
645 size = Drawer2D_BitmappedText ? 16 : 11;
646 Drawer2D_MakeFont(&s->font, size, FONT_FLAGS_PADDING);
647 s->namesCount = 0;
648
649 TextWidget_SetConst(&s->title, "Connected players:", &s->font);
650 Font_SetPadding(&s->font, 1);
651
652 /* TODO: Just recreate instead of this? maybe */
653 for (id = 0; id < TABLIST_MAX_NAMES256; id++) {
654 if (!TabList.NameOffsets[id]) continue;
655 TabListOverlay_AddName(s, (EntityID)id, -1);
656 }
657 TabListOverlay_SortAndLayout(s); /* TODO: Not do layout here too */
658}
659
660static void TabListOverlay_BuildMesh(void* screen) { }
661
662static void TabListOverlay_Render(void* screen, double delta) {
663 struct TabListOverlay* s = (struct TabListOverlay*)screen;
664 struct TextWidget* title = &s->title;
665 struct Screen* grabbed;
666 struct Texture tex;
667 int i;
668 PackedCol topCol = PackedCol_Make( 0, 0, 0, 180)(((cc_uint8)(0) << 0) | ((cc_uint8)(0) << 8) | ((
cc_uint8)(0) << 16) | ((cc_uint8)(180) << 24))
;
669 PackedCol bottomCol = PackedCol_Make(50, 50, 50, 205)(((cc_uint8)(50) << 0) | ((cc_uint8)(50) << 8) | (
(cc_uint8)(50) << 16) | ((cc_uint8)(205) << 24))
;
670
671 if (Game_HideGui || !IsOnlyChatActive()) return;
672 Gfx_SetTexturing(false0);
673 Gfx_Draw2DGradient(s->x, s->y, s->width, s->height, topCol, bottomCol);
674
675 Gfx_SetTexturing(true1);
676 Elem_Render(title, delta)(title)->VTABLE->Render(title, delta);
677 grabbed = Gui_GetInputGrab();
678
679 for (i = 0; i < s->namesCount; i++) {
680 if (!s->textures[i].ID) continue;
681 tex = s->textures[i];
682
683 if (grabbed && s->ids[i] != GROUP_NAME_ID((cc_uint16)65535)) {
684 if (Gui_ContainsPointers(tex.X, tex.Y, tex.Width, tex.Height)) tex.X += 4;
685 }
686 Texture_Render(&tex);
687 }
688 Gfx_SetTexturing(false0);
689
690 /* NOTE: Should usually be caught by KeyUp, but just in case. */
691 if (KeyBind_IsPressed(KEYBIND_TABLIST) || Input_TouchMode0) return;
692 Gui_Remove((struct Screen*)s);
693}
694
695static void TabListOverlay_Free(void* screen) {
696 struct TabListOverlay* s = (struct TabListOverlay*)screen;
697 s->active = false0;
698 Event_Unregister_(&TabListEvents.Added, s, TabListOverlay_Add)Event_Unregister((struct Event_Void*)(&TabListEvents.Added
), s, (Event_Void_Callback)(TabListOverlay_Add))
;
699 Event_Unregister_(&TabListEvents.Changed, s, TabListOverlay_Update)Event_Unregister((struct Event_Void*)(&TabListEvents.Changed
), s, (Event_Void_Callback)(TabListOverlay_Update))
;
700 Event_Unregister_(&TabListEvents.Removed, s, TabListOverlay_Remove)Event_Unregister((struct Event_Void*)(&TabListEvents.Removed
), s, (Event_Void_Callback)(TabListOverlay_Remove))
;
701}
702
703static void TabListOverlay_Init(void* screen) {
704 struct TabListOverlay* s = (struct TabListOverlay*)screen;
705 s->active = true1;
706 s->classic = Gui.ClassicTabList || !Server.SupportsExtPlayerList;
707 s->elementOffset = s->classic ? 0 : 10;
708 TextWidget_Init(&s->title);
709
710 Event_Register_(&TabListEvents.Added, s, TabListOverlay_Add)Event_Register((struct Event_Void*)(&TabListEvents.Added)
, s, (Event_Void_Callback)(TabListOverlay_Add))
;
711 Event_Register_(&TabListEvents.Changed, s, TabListOverlay_Update)Event_Register((struct Event_Void*)(&TabListEvents.Changed
), s, (Event_Void_Callback)(TabListOverlay_Update))
;
712 Event_Register_(&TabListEvents.Removed, s, TabListOverlay_Remove)Event_Register((struct Event_Void*)(&TabListEvents.Removed
), s, (Event_Void_Callback)(TabListOverlay_Remove))
;
713}
714
715static const struct ScreenVTABLE TabListOverlay_VTABLE = {
716 TabListOverlay_Init, Screen_NullUpdate, TabListOverlay_Free,
717 TabListOverlay_Render, TabListOverlay_BuildMesh,
718 Screen_FInput, TabListOverlay_KeyUp, Screen_FKeyPress, Screen_FText,
719 TabListOverlay_PointerDown, Screen_FPointer, Screen_FPointer, Screen_FMouseScroll,
720 TabListOverlay_Layout, TabListOverlay_ContextLost, TabListOverlay_ContextRecreated
721};
722void TabListOverlay_Show(void) {
723 struct TabListOverlay* s = &TabListOverlay_Instance;
724 s->VTABLE = &TabListOverlay_VTABLE;
725 Gui_Add((struct Screen*)s, GUI_PRIORITY_TABLIST);
726}
727
728
729
730/*########################################################################################################################*
731*--------------------------------------------------------ChatScreen-------------------------------------------------------*
732*#########################################################################################################################*/
733static struct ChatScreen {
734 Screen_Bodyconst struct ScreenVTABLE* VTABLE; cc_bool grabsInput; cc_bool
blocksWorld; cc_bool closable; cc_bool dirty; int maxVertices
; GfxResourceID vb; struct Widget** widgets; int numWidgets;
735 float chatAcc;
736 cc_bool suppressNextPress;
737 int chatIndex, paddingX, paddingY;
738 int lastDownloadStatus;
739 struct FontDesc chatFont, announcementFont;
740 struct TextWidget announcement;
741 struct ChatInputWidget input;
742 struct TextGroupWidget status, bottomRight, chat, clientStatus;
743 struct SpecialInputWidget altText;
744#ifdef CC_BUILD_TOUCH
745 struct ButtonWidget send, cancel;
746#endif
747
748 struct Texture statusTextures[CHAT_MAX_STATUS(sizeof(Chat_Status) / sizeof(Chat_Status[0]))];
749 struct Texture bottomRightTextures[CHAT_MAX_BOTTOMRIGHT(sizeof(Chat_BottomRight) / sizeof(Chat_BottomRight[0]))];
750 struct Texture clientStatusTextures[CHAT_MAX_CLIENTSTATUS(sizeof(Chat_ClientStatus) / sizeof(Chat_ClientStatus[0]))];
751 struct Texture chatTextures[TEXTGROUPWIDGET_MAX_LINES30];
752} ChatScreen_Instance;
753#define CH_EXTENT16 16
754
755static void ChatScreen_UpdateChatYOffsets(struct ChatScreen* s) {
756 int pad, y;
757
758 /* Determining chat Y requires us to know hotbar's position */
759 /* But HUD is lower priority, so it gets laid out AFTER chat */
760 /* Hence use this hack to resize HUD first */
761 HUDScreen_Layout(Gui_HUD);
762
763 y = min(s->input.base.y, Gui_HUD->hotbar.y)((s->input.base.y) < (Gui_HUD->hotbar.y) ? (s->input
.base.y) : (Gui_HUD->hotbar.y))
;
764 y -= s->input.base.yOffset; /* add some padding */
765 s->altText.yOffset = WindowInfo.Height - y;
766 Widget_Layout(&s->altText)(&s->altText)->VTABLE->Reposition(&s->altText
)
;
767
768 pad = s->altText.active ? 5 : 10;
769 s->clientStatus.yOffset = WindowInfo.Height - s->altText.y + pad;
770 Widget_Layout(&s->clientStatus)(&s->clientStatus)->VTABLE->Reposition(&s->
clientStatus)
;
771 s->chat.yOffset = s->clientStatus.yOffset + s->clientStatus.height;
772 Widget_Layout(&s->chat)(&s->chat)->VTABLE->Reposition(&s->chat);
773}
774
775static void ChatScreen_OnInputTextChanged(void* elem) {
776 ChatScreen_UpdateChatYOffsets(Gui_Chat);
777}
778
779static cc_string ChatScreen_GetChat(int i) {
780 i += ChatScreen_Instance.chatIndex;
781
782 if (i >= 0 && i < Chat_Log.count) {
783 return StringsBuffer_UNSAFE_Get(&Chat_Log, i);
784 }
785 return String_Empty;
786}
787
788static cc_string ChatScreen_GetStatus(int i) { return Chat_Status[i]; }
789static cc_string ChatScreen_GetBottomRight(int i) { return Chat_BottomRight[2 - i]; }
790static cc_string ChatScreen_GetClientStatus(int i) { return Chat_ClientStatus[i]; }
791
792static void ChatScreen_FreeChatFonts(struct ChatScreen* s) {
793 Font_Free(&s->chatFont);
794 Font_Free(&s->announcementFont);
795}
796
797static cc_bool ChatScreen_ChatUpdateFont(struct ChatScreen* s) {
798 int size = (int)(8 * Gui_GetChatScale());
799 Math_Clamp(size, 8, 60)size = size < (8) ? (8) : size; size = size > (60) ? (60
) : size;
;
800
801 /* don't recreate font if possible */
802 /* TODO: Add function for this, don't use Display_ScaleY (Drawer2D_SameFontSize ??) */
803 if (Display_ScaleY(size) == s->chatFont.size) return false0;
804 ChatScreen_FreeChatFonts(s);
805 Drawer2D_MakeFont(&s->chatFont, size, FONT_FLAGS_PADDING);
806
807 size = (int)(16 * Gui_GetChatScale());
808 Math_Clamp(size, 8, 60)size = size < (8) ? (8) : size; size = size > (60) ? (60
) : size;
;
809 Drawer2D_MakeFont(&s->announcementFont, size, FONT_FLAGS_NONE);
810
811 ChatInputWidget_SetFont(&s->input, &s->chatFont);
812 TextGroupWidget_SetFont(&s->status, &s->chatFont);
813 TextGroupWidget_SetFont(&s->bottomRight, &s->chatFont);
814 TextGroupWidget_SetFont(&s->chat, &s->chatFont);
815 TextGroupWidget_SetFont(&s->clientStatus, &s->chatFont);
816 return true1;
817}
818
819static void ChatScreen_Redraw(struct ChatScreen* s) {
820 TextGroupWidget_RedrawAll(&s->chat);
821 TextWidget_Set(&s->announcement, &Chat_Announcement, &s->announcementFont);
822 TextGroupWidget_RedrawAll(&s->status);
823 TextGroupWidget_RedrawAll(&s->bottomRight);
824 TextGroupWidget_RedrawAll(&s->clientStatus);
825
826 if (s->grabsInput) InputWidget_UpdateText(&s->input.base);
827 SpecialInputWidget_Redraw(&s->altText);
828}
829
830static int ChatScreen_ClampChatIndex(int index) {
831 int maxIndex = Chat_Log.count - Gui.Chatlines;
832 int minIndex = min(0, maxIndex)((0) < (maxIndex) ? (0) : (maxIndex));
833 Math_Clamp(index, minIndex, maxIndex)index = index < (minIndex) ? (minIndex) : index; index = index
> (maxIndex) ? (maxIndex) : index;
;
834 return index;
835}
836
837static void ChatScreen_ScrollChatBy(struct ChatScreen* s, int delta) {
838 int newIndex = ChatScreen_ClampChatIndex(s->chatIndex + delta);
839 delta = newIndex - s->chatIndex;
840
841 while (delta) {
842 if (delta < 0) {
843 /* scrolling up to oldest */
844 s->chatIndex--; delta++;
845 TextGroupWidget_ShiftDown(&s->chat);
846 } else {
847 /* scrolling down to newest */
848 s->chatIndex++; delta--;
849 TextGroupWidget_ShiftUp(&s->chat);
850 }
851 }
852}
853
854static void ChatScreen_EnterChatInput(struct ChatScreen* s, cc_bool close) {
855 struct InputWidget* input;
856 int defaultIndex;
857
858 s->grabsInput = false0;
859 Camera_CheckFocus();
860 Window_CloseKeyboard();
861 if (close) InputWidget_Clear(&s->input.base);
862
863 input = &s->input.base;
864 input->OnPressedEnter(input);
865 SpecialInputWidget_SetActive(&s->altText, false0);
866 ChatScreen_UpdateChatYOffsets(s);
867
868 /* Reset chat when user has scrolled up in chat history */
869 defaultIndex = Chat_Log.count - Gui.Chatlines;
870 if (s->chatIndex != defaultIndex) {
871 s->chatIndex = defaultIndex;
872 TextGroupWidget_RedrawAll(&s->chat);
873 }
874}
875
876static void ChatScreen_UpdateTexpackStatus(struct ChatScreen* s) {
877 int progress = Http_CheckProgress(TexturePack_ReqID);
878 if (progress == s->lastDownloadStatus) return;
879
880 s->lastDownloadStatus = progress;
881 Chat_Status[0].length = 0;
882
883 if (progress == HTTP_PROGRESS_MAKING_REQUEST) {
884 String_AppendConst(&Chat_Status[0], "&eRetrieving texture pack..");
885 } else if (progress == HTTP_PROGRESS_FETCHING_DATA) {
886 String_AppendConst(&Chat_Status[0], "&eDownloading texture pack");
887 } else if (progress >= 0 && progress <= 100) {
888 String_Format1(&Chat_Status[0], "&eDownloading texture pack (&7%i&e%%)", &progress);
889 }
890 TextGroupWidget_Redraw(&s->status, 0);
891}
892
893static void ChatScreen_ColCodeChanged(void* screen, int code) {
894 struct ChatScreen* s = (struct ChatScreen*)screen;
895 double caretAcc;
896 if (Gfx.LostContext) return;
897
898 SpecialInputWidget_UpdateCols(&s->altText);
899 TextGroupWidget_RedrawAllWithCol(&s->chat, code);
900 TextGroupWidget_RedrawAllWithCol(&s->status, code);
901 TextGroupWidget_RedrawAllWithCol(&s->bottomRight, code);
902 TextGroupWidget_RedrawAllWithCol(&s->clientStatus, code);
903
904 /* Some servers have plugins that redefine colours constantly */
905 /* Preserve caret accumulator so caret blinking stays consistent */
906 caretAcc = s->input.base.caretAccumulator;
907 InputWidget_UpdateText(&s->input.base);
908 s->input.base.caretAccumulator = caretAcc;
909}
910
911static void ChatScreen_ChatReceived(void* screen, const cc_string* msg, int type) {
912 struct ChatScreen* s = (struct ChatScreen*)screen;
913 if (Gfx.LostContext) return;
914
915 if (type == MSG_TYPE_NORMAL) {
916 s->chatIndex++;
917 if (!Gui.Chatlines) return;
918 TextGroupWidget_ShiftUp(&s->chat);
919 } else if (type >= MSG_TYPE_STATUS_1 && type <= MSG_TYPE_STATUS_3) {
920 /* Status[0] is for texture pack downloading message */
921 TextGroupWidget_Redraw(&s->status, 1 + (type - MSG_TYPE_STATUS_1));
922 } else if (type >= MSG_TYPE_BOTTOMRIGHT_1 && type <= MSG_TYPE_BOTTOMRIGHT_3) {
923 /* Bottom3 is top most line, so need to redraw index 0 */
924 TextGroupWidget_Redraw(&s->bottomRight, 2 - (type - MSG_TYPE_BOTTOMRIGHT_1));
925 } else if (type == MSG_TYPE_ANNOUNCEMENT) {
926 TextWidget_Set(&s->announcement, msg, &s->announcementFont);
927 } else if (type >= MSG_TYPE_CLIENTSTATUS_1 && type <= MSG_TYPE_CLIENTSTATUS_2) {
928 TextGroupWidget_Redraw(&s->clientStatus, type - MSG_TYPE_CLIENTSTATUS_1);
929 ChatScreen_UpdateChatYOffsets(s);
930 }
931}
932
933static void ChatScreen_DrawCrosshairs(void) {
934 static struct Texture tex = { 0, Tex_Rect(0,0,0,0)0,0,0,0, Tex_UV(0.0f,0.0f, 15/256.0f,15/256.0f)0.0f,0.0f,15/256.0f,15/256.0f };
935 int extent;
936 if (!Gui.IconsTex) return;
937
938 extent = (int)(CH_EXTENT16 * Gui_Scale(WindowInfo.Height / 480.0f));
939 tex.ID = Gui.IconsTex;
940 tex.X = (WindowInfo.Width / 2) - extent;
941 tex.Y = (WindowInfo.Height / 2) - extent;
942
943 tex.Width = extent * 2;
944 tex.Height = extent * 2;
945 Texture_Render(&tex);
946}
947
948static void ChatScreen_DrawChatBackground(struct ChatScreen* s) {
949 int usedHeight = TextGroupWidget_UsedHeight(&s->chat);
950 int x = s->chat.x;
951 int y = s->chat.y + s->chat.height - usedHeight;
952
953 int width = max(s->clientStatus.width, s->chat.width)((s->clientStatus.width) > (s->chat.width) ? (s->
clientStatus.width) : (s->chat.width))
;
954 int height = usedHeight + s->clientStatus.height;
955
956 if (height > 0) {
957 PackedCol backCol = PackedCol_Make(0, 0, 0, 127)(((cc_uint8)(0) << 0) | ((cc_uint8)(0) << 8) | ((
cc_uint8)(0) << 16) | ((cc_uint8)(127) << 24))
;
958 Gfx_Draw2DFlat( x - s->paddingX, y - s->paddingY,
959 width + s->paddingX * 2, height + s->paddingY * 2, backCol);
960 }
961}
962
963static void ChatScreen_DrawChat(struct ChatScreen* s, double delta) {
964 struct Texture tex;
965 double now;
966 int i, logIdx;
967
968 ChatScreen_UpdateTexpackStatus(s);
969 if (!Game_PureClassic(Game_ClassicMode && !Game_ClassicHacks)) { Elem_Render(&s->status, delta)(&s->status)->VTABLE->Render(&s->status, delta
)
; }
970 Elem_Render(&s->bottomRight, delta)(&s->bottomRight)->VTABLE->Render(&s->bottomRight
, delta)
;
971 Elem_Render(&s->clientStatus, delta)(&s->clientStatus)->VTABLE->Render(&s->clientStatus
, delta)
;
972
973 now = Game.Time;
974 if (s->grabsInput) {
975 Elem_Render(&s->chat, delta)(&s->chat)->VTABLE->Render(&s->chat, delta
)
;
976 } else {
977 /* Only render recent chat */
978 for (i = 0; i < s->chat.lines; i++) {
979 tex = s->chat.textures[i];
980 logIdx = s->chatIndex + i;
981 if (!tex.ID) continue;
982
983 if (logIdx < 0 || logIdx >= Chat_Log.count) continue;
984 if (Chat_LogTime[logIdx] + 10 >= now) Texture_Render(&tex);
985 }
986 }
987
988 /* Destroy announcement texture before even rendering it at all, */
989 /* otherwise changing texture pack shows announcement for one frame */
990 if (s->announcement.tex.ID && now > Chat_AnnouncementReceived + 5) {
991 Elem_Free(&s->announcement)(&s->announcement)->VTABLE->Free(&s->announcement
)
;
992 }
993 Elem_Render(&s->announcement, delta)(&s->announcement)->VTABLE->Render(&s->announcement
, delta)
;
994
995 if (s->grabsInput) {
996 Elem_Render(&s->input.base, delta)(&s->input.base)->VTABLE->Render(&s->input
.base, delta)
;
997 if (s->altText.active) {
998 Elem_Render(&s->altText, delta)(&s->altText)->VTABLE->Render(&s->altText
, delta)
;
999 }
1000
1001#ifdef CC_BUILD_TOUCH
1002 if (!Input_TouchMode0) return;
1003 Elem_Render(&s->send, delta)(&s->send)->VTABLE->Render(&s->send, delta
)
;
1004 Elem_Render(&s->cancel, delta)(&s->cancel)->VTABLE->Render(&s->cancel, delta
)
;
1005#endif
1006 }
1007}
1008
1009static void ChatScreen_ContextLost(void* screen) {
1010 struct ChatScreen* s = (struct ChatScreen*)screen;
1011 ChatScreen_FreeChatFonts(s);
1012
1013 Elem_Free(&s->chat)(&s->chat)->VTABLE->Free(&s->chat);
1014 Elem_Free(&s->input.base)(&s->input.base)->VTABLE->Free(&s->input.
base)
;
1015 Elem_Free(&s->altText)(&s->altText)->VTABLE->Free(&s->altText);
1016 Elem_Free(&s->status)(&s->status)->VTABLE->Free(&s->status);
1017 Elem_Free(&s->bottomRight)(&s->bottomRight)->VTABLE->Free(&s->bottomRight
)
;
1018 Elem_Free(&s->clientStatus)(&s->clientStatus)->VTABLE->Free(&s->clientStatus
)
;
1019 Elem_Free(&s->announcement)(&s->announcement)->VTABLE->Free(&s->announcement
)
;
1020
1021#ifdef CC_BUILD_TOUCH
1022 if (!Input_TouchMode0) return;
1023 Elem_Free(&s->send)(&s->send)->VTABLE->Free(&s->send);
1024 Elem_Free(&s->cancel)(&s->cancel)->VTABLE->Free(&s->cancel);
1025#endif
1026}
1027
1028static void ChatScreen_ContextRecreated(void* screen) {
1029 struct ChatScreen* s = (struct ChatScreen*)screen;
1030 struct FontDesc font;
1031 ChatScreen_ChatUpdateFont(s);
1032 ChatScreen_Redraw(s);
1033
1034#ifdef CC_BUILD_TOUCH
1035 if (!Input_TouchMode0) return;
1036 Gui_MakeTitleFont(&font);
1037 ButtonWidget_SetConst(&s->send, "Send", &font);
1038 ButtonWidget_SetConst(&s->cancel, "Cancel", &font);
1039 Font_Free(&font);
1040#endif
1041}
1042
1043static void ChatScreen_BuildMesh(void* screen) { }
1044
1045static void ChatScreen_Layout(void* screen) {
1046 struct ChatScreen* s = (struct ChatScreen*)screen;
1047 /* See comment in ChatScreen_UpdateChatYOffsets */
1048 HUDScreen_Layout(Gui_HUD);
1049 if (ChatScreen_ChatUpdateFont(s)) ChatScreen_Redraw(s);
1050
1051 s->paddingX = Display_ScaleX(5);
1052 s->paddingY = Display_ScaleY(5);
1053
1054 Widget_SetLocation(&s->input.base, ANCHOR_MIN, ANCHOR_MAX, 5, 5);
1055 Widget_SetLocation(&s->altText, ANCHOR_MIN, ANCHOR_MAX, 5, 5);
1056 Widget_SetLocation(&s->status, ANCHOR_MAX, ANCHOR_MIN, 0, 0);
1057 Widget_SetLocation(&s->bottomRight, ANCHOR_MAX, ANCHOR_MAX, 0, 0);
1058 Widget_SetLocation(&s->chat, ANCHOR_MIN, ANCHOR_MAX, 10, 0);
1059 Widget_SetLocation(&s->clientStatus, ANCHOR_MIN, ANCHOR_MAX, 10, 0);
1060 ChatScreen_UpdateChatYOffsets(s);
1061
1062 /* Can't use Widget_SetLocation because it DPI scales input */
1063 s->bottomRight.yOffset = Gui_HUD->hotbar.height + Display_ScaleY(15);
1064 Widget_Layout(&s->bottomRight)(&s->bottomRight)->VTABLE->Reposition(&s->
bottomRight)
;
1065
1066 Widget_SetLocation(&s->announcement, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 0);
1067 s->announcement.yOffset = -WindowInfo.Height / 4;
1068 Widget_Layout(&s->announcement)(&s->announcement)->VTABLE->Reposition(&s->
announcement)
;
1069
1070#ifdef CC_BUILD_TOUCH
1071 if (!Input_TouchMode0) return;
1072 if (WindowInfo.SoftKeyboard == SOFT_KEYBOARD_SHIFT) {
1073 Widget_SetLocation(&s->send, ANCHOR_MAX, ANCHOR_MAX, 10, 60);
1074 Widget_SetLocation(&s->cancel, ANCHOR_MAX, ANCHOR_MAX, 10, 10);
1075 } else {
1076 Widget_SetLocation(&s->send, ANCHOR_MAX, ANCHOR_MIN, 10, 10);
1077 Widget_SetLocation(&s->cancel, ANCHOR_MAX, ANCHOR_MIN, 10, 60);
1078 }
1079#endif
1080}
1081
1082static int ChatScreen_KeyPress(void* screen, char keyChar) {
1083 struct ChatScreen* s = (struct ChatScreen*)screen;
1084 if (!s->grabsInput) return false0;
1085
1086 if (s->suppressNextPress) {
1087 s->suppressNextPress = false0;
1088 return false0;
1089 }
1090
1091 InputWidget_Append(&s->input.base, keyChar);
1092 return true1;
1093}
1094
1095static int ChatScreen_TextChanged(void* screen, const cc_string* str) {
1096#ifdef CC_BUILD_TOUCH
1097 struct ChatScreen* s = (struct ChatScreen*)screen;
1098 if (!s->grabsInput) return false0;
1099
1100 InputWidget_SetText(&s->input.base, str);
1101#endif
1102 return true1;
1103}
1104
1105static int ChatScreen_KeyDown(void* screen, int key) {
1106 static const cc_string slash = String_FromConst("/"){ "/", (sizeof("/") - 1), (sizeof("/") - 1)};
1107 struct ChatScreen* s = (struct ChatScreen*)screen;
1108 int playerListKey = KeyBinds[KEYBIND_TABLIST];
1109 cc_bool handlesList = playerListKey != KEY_TAB || !Gui.TabAutocomplete || !s->grabsInput;
1110
1111 if (key == playerListKey && handlesList) {
1112 if (!TabListOverlay_Instance.active && !Server.IsSinglePlayer) {
1113 TabListOverlay_Show();
1114 }
1115 return true1;
1116 }
1117
1118 s->suppressNextPress = false0;
1119 /* Handle chat text input */
1120 if (s->grabsInput) {
1121#ifdef CC_BUILD_WEB
1122 /* See reason for this in HandleInputUp */
1123 if (key == KeyBinds[KEYBIND_SEND_CHAT] || key == KEY_KP_ENTER) {
1124 ChatScreen_EnterChatInput(s, false0);
1125#else
1126 if (key == KeyBinds[KEYBIND_SEND_CHAT] || key == KEY_KP_ENTER || key == KEY_ESCAPE) {
1127 ChatScreen_EnterChatInput(s, key == KEY_ESCAPE);
1128#endif
1129 } else if (key == KEY_PAGEUP) {
1130 ChatScreen_ScrollChatBy(s, -Gui.Chatlines);
1131 } else if (key == KEY_PAGEDOWN) {
1132 ChatScreen_ScrollChatBy(s, +Gui.Chatlines);
1133 } else {
1134 Elem_HandlesKeyDown(&s->input.base, key)(&s->input.base)->VTABLE->HandlesKeyDown(&s->
input.base, key)
;
1135 }
1136 return key < KEY_F1 || key > KEY_F24;
1137 }
1138
1139 if (key == KeyBinds[KEYBIND_CHAT]) {
1140 ChatScreen_OpenInput(&String_Empty);
1141 } else if (key == KEY_SLASH) {
1142 ChatScreen_OpenInput(&slash);
1143 } else if (key == KeyBinds[KEYBIND_INVENTORY]) {
1144 InventoryScreen_Show();
1145 } else {
1146 return false0;
1147 }
1148 return true1;
1149}
1150
1151static int ChatScreen_KeyUp(void* screen, int key) {
1152 struct ChatScreen* s = (struct ChatScreen*)screen;
1153 if (!s->grabsInput) return false0;
1154#ifdef CC_BUILD_WEB
1155 /* See reason for this in HandleInputUp */
1156 if (key == KEY_ESCAPE) ChatScreen_EnterChatInput(s, true1);
1157#endif
1158
1159 if (Server.SupportsFullCP437 && key == KeyBinds[KEYBIND_EXT_INPUT]) {
1160 if (!WindowInfo.Focused) return true1;
1161 SpecialInputWidget_SetActive(&s->altText, !s->altText.active);
1162 ChatScreen_UpdateChatYOffsets(s);
1163 }
1164 return true1;
1165}
1166
1167static int ChatScreen_MouseScroll(void* screen, float delta) {
1168 struct ChatScreen* s = (struct ChatScreen*)screen;
1169 int steps;
1170 if (!s->grabsInput) return false0;
1171
1172 steps = Utils_AccumulateWheelDelta(&s->chatAcc, delta);
1173 ChatScreen_ScrollChatBy(s, -steps);
1174 return true1;
1175}
1176
1177static int ChatScreen_PointerDown(void* screen, int id, int x, int y) {
1178 cc_string text; char textBuffer[STRING_SIZE64 * 4];
1179 struct ChatScreen* s = (struct ChatScreen*)screen;
1180 int height, chatY, i;
1181 if (Game_HideGui) return false0;
1182
1183 if (!s->grabsInput) {
1184 if (!Input_TouchMode0) return false0;
1185 String_InitArray(text, textBuffer)text.buffer = textBuffer; text.length = 0; text.capacity = sizeof
(textBuffer);
;
1186
1187 /* Should be able to click on links with touch */
1188 i = TextGroupWidget_GetSelected(&s->chat, &text, x, y);
1189 if (!Utils_IsUrlPrefix(&text)) return false0;
1190
1191 if (Chat_LogTime[s->chatIndex + i] + 10 < Game.Time) return false0;
1192 UrlWarningOverlay_Show(&text); return true1;
1193 }
1194
1195#ifdef CC_BUILD_TOUCH
1196 if (Widget_Contains(&s->send, x, y)) {
1197 ChatScreen_EnterChatInput(s, false0); return true1;
1198 }
1199 if (Widget_Contains(&s->cancel, x, y)) {
1200 ChatScreen_EnterChatInput(s, true1); return true1;
1201 }
1202#endif
1203
1204 if (!Widget_Contains(&s->chat, x, y)) {
1205 if (s->altText.active && Widget_Contains(&s->altText, x, y)) {
1206 Elem_HandlesPointerDown(&s->altText, id, x, y)(&s->altText)->VTABLE->HandlesPointerDown(&s
->altText, id, x, y)
;
1207 ChatScreen_UpdateChatYOffsets(s);
1208 return true1;
1209 }
1210 Elem_HandlesPointerDown(&s->input.base, id, x, y)(&s->input.base)->VTABLE->HandlesPointerDown(&
s->input.base, id, x, y)
;
1211 return true1;
1212 }
1213
1214 height = TextGroupWidget_UsedHeight(&s->chat);
1215 chatY = s->chat.y + s->chat.height - height;
1216 if (!Gui_Contains(s->chat.x, chatY, s->chat.width, height, x, y)) return false0;
1217
1218 String_InitArray(text, textBuffer)text.buffer = textBuffer; text.length = 0; text.capacity = sizeof
(textBuffer);
;
1219 TextGroupWidget_GetSelected(&s->chat, &text, x, y);
1220 if (!text.length) return false0;
1221
1222 if (Utils_IsUrlPrefix(&text)) {
1223 UrlWarningOverlay_Show(&text);
1224 } else if (Gui.ClickableChat) {
1225 ChatScreen_AppendInput(&text);
1226 }
1227 return true1;
1228}
1229
1230static void ChatScreen_Init(void* screen) {
1231 struct ChatScreen* s = (struct ChatScreen*)screen;
1232 ChatInputWidget_Create(&s->input);
1233 s->input.base.OnTextChanged = ChatScreen_OnInputTextChanged;
1234 SpecialInputWidget_Create(&s->altText, &s->chatFont, &s->input.base);
1235
1236 TextGroupWidget_Create(&s->status, CHAT_MAX_STATUS(sizeof(Chat_Status) / sizeof(Chat_Status[0])),
1237 s->statusTextures, ChatScreen_GetStatus);
1238 TextGroupWidget_Create(&s->bottomRight, CHAT_MAX_BOTTOMRIGHT(sizeof(Chat_BottomRight) / sizeof(Chat_BottomRight[0])),
1239 s->bottomRightTextures, ChatScreen_GetBottomRight);
1240 TextGroupWidget_Create(&s->chat, Gui.Chatlines,
1241 s->chatTextures, ChatScreen_GetChat);
1242 TextGroupWidget_Create(&s->clientStatus, CHAT_MAX_CLIENTSTATUS(sizeof(Chat_ClientStatus) / sizeof(Chat_ClientStatus[0])),
1243 s->clientStatusTextures, ChatScreen_GetClientStatus);
1244 TextWidget_Init(&s->announcement);
1245
1246 s->status.collapsible[0] = true1; /* Texture pack download status */
1247 s->clientStatus.collapsible[0] = true1;
1248 s->clientStatus.collapsible[1] = true1;
1249
1250 s->chat.underlineUrls = !Game_ClassicMode;
1251 s->chatIndex = Chat_Log.count - Gui.Chatlines;
1252
1253 Event_Register_(&ChatEvents.ChatReceived, s, ChatScreen_ChatReceived)Event_Register((struct Event_Void*)(&ChatEvents.ChatReceived
), s, (Event_Void_Callback)(ChatScreen_ChatReceived))
;
1254 Event_Register_(&ChatEvents.ColCodeChanged, s, ChatScreen_ColCodeChanged)Event_Register((struct Event_Void*)(&ChatEvents.ColCodeChanged
), s, (Event_Void_Callback)(ChatScreen_ColCodeChanged))
;
1255
1256#ifdef CC_BUILD_TOUCH
1257 if (!Input_TouchMode0) return;
1258 ButtonWidget_Init(&s->send, 100, NULL((void*)0));
1259 ButtonWidget_Init(&s->cancel, 100, NULL((void*)0));
1260#endif
1261}
1262
1263static void ChatScreen_Render(void* screen, double delta) {
1264 struct ChatScreen* s = (struct ChatScreen*)screen;
1265
1266 if (Game_HideGui && s->grabsInput) {
1267 Gfx_SetTexturing(true1);
1268 Elem_Render(&s->input.base, delta)(&s->input.base)->VTABLE->Render(&s->input
.base, delta)
;
1269 Gfx_SetTexturing(false0);
1270 }
1271 if (Game_HideGui) return;
1272
1273 if (!TabListOverlay_Instance.active && !Gui_GetBlocksWorld()) {
1274 Gfx_SetTexturing(true1);
1275 ChatScreen_DrawCrosshairs();
1276 Gfx_SetTexturing(false0);
1277 }
1278 if (s->grabsInput && !Gui.ClassicChat) {
1279 ChatScreen_DrawChatBackground(s);
1280 }
1281
1282 Gfx_SetTexturing(true1);
1283 ChatScreen_DrawChat(s, delta);
1284 Gfx_SetTexturing(false0);
1285}
1286
1287static void ChatScreen_Free(void* screen) {
1288 struct ChatScreen* s = (struct ChatScreen*)screen;
1289 Event_Unregister_(&ChatEvents.ChatReceived, s, ChatScreen_ChatReceived)Event_Unregister((struct Event_Void*)(&ChatEvents.ChatReceived
), s, (Event_Void_Callback)(ChatScreen_ChatReceived))
;
1290 Event_Unregister_(&ChatEvents.ColCodeChanged, s, ChatScreen_ColCodeChanged)Event_Unregister((struct Event_Void*)(&ChatEvents.ColCodeChanged
), s, (Event_Void_Callback)(ChatScreen_ColCodeChanged))
;
1291}
1292
1293static const struct ScreenVTABLE ChatScreen_VTABLE = {
1294 ChatScreen_Init, Screen_NullUpdate, ChatScreen_Free,
1295 ChatScreen_Render, ChatScreen_BuildMesh,
1296 ChatScreen_KeyDown, ChatScreen_KeyUp, ChatScreen_KeyPress, ChatScreen_TextChanged,
1297 ChatScreen_PointerDown, Screen_FPointer, Screen_FPointer, ChatScreen_MouseScroll,
1298 ChatScreen_Layout, ChatScreen_ContextLost, ChatScreen_ContextRecreated
1299};
1300void ChatScreen_Show(void) {
1301 struct ChatScreen* s = &ChatScreen_Instance;
1302 s->lastDownloadStatus = HTTP_PROGRESS_NOT_WORKING_ON;
1303
1304 s->VTABLE = &ChatScreen_VTABLE;
1305 Gui_Chat = s;
1306 Gui_Add((struct Screen*)s, GUI_PRIORITY_CHAT);
1307}
1308
1309void ChatScreen_OpenInput(const cc_string* text) {
1310 struct ChatScreen* s = &ChatScreen_Instance;
1311 s->suppressNextPress = true1;
1312 s->grabsInput = true1;
1313 Camera_CheckFocus();
1314 Window_OpenKeyboard(text, KEYBOARD_TYPE_TEXT);
1315
1316 String_Copy(&s->input.base.text, text);
1317 InputWidget_UpdateText(&s->input.base);
1318}
1319
1320void ChatScreen_AppendInput(const cc_string* text) {
1321 struct ChatScreen* s = &ChatScreen_Instance;
1322 InputWidget_AppendText(&s->input.base, text);
1323}
1324
1325void ChatScreen_SetChatlines(int lines) {
1326 struct ChatScreen* s = &ChatScreen_Instance;
1327 Elem_Free(&s->chat)(&s->chat)->VTABLE->Free(&s->chat);
1328 s->chatIndex += s->chat.lines - lines;
1329 s->chat.lines = lines;
1330 TextGroupWidget_RedrawAll(&s->chat);
1331}
1332
1333
1334/*########################################################################################################################*
1335*-----------------------------------------------------InventoryScreen-----------------------------------------------------*
1336*#########################################################################################################################*/
1337static struct InventoryScreen {
1338 Screen_Bodyconst struct ScreenVTABLE* VTABLE; cc_bool grabsInput; cc_bool
blocksWorld; cc_bool closable; cc_bool dirty; int maxVertices
; GfxResourceID vb; struct Widget** widgets; int numWidgets;
1339 struct FontDesc font;
1340 struct TableWidget table;
1341 cc_bool releasedInv, deferredSelect;
1342} InventoryScreen_Instance;
1343
1344static void InventoryScreen_OnBlockChanged(void* screen) {
1345 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1346 TableWidget_OnInventoryChanged(&s->table);
1347}
1348
1349static void InventoryScreen_ContextLost(void* screen) {
1350 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1351 Font_Free(&s->font);
1352 Elem_Free(&s->table)(&s->table)->VTABLE->Free(&s->table);
1353}
1354
1355static void InventoryScreen_ContextRecreated(void* screen) {
1356 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1357 Gui_MakeBodyFont(&s->font);
1358 TableWidget_Recreate(&s->table);
1359}
1360
1361static void InventoryScreen_BuildMesh(void* screen) { }
1362
1363static void InventoryScreen_MoveToSelected(struct InventoryScreen* s) {
1364 struct TableWidget* table = &s->table;
1365 TableWidget_SetBlockTo(table, Inventory_SelectedBlock(Inventory.Table[Inventory.Offset + (Inventory.SelectedIndex)
])
);
1366 TableWidget_Recreate(table);
1367
1368 s->deferredSelect = false0;
1369 /* User is holding invalid block */
1370 if (table->selectedIndex == -1) {
1371 TableWidget_MakeDescTex(table, Inventory_SelectedBlock(Inventory.Table[Inventory.Offset + (Inventory.SelectedIndex)
])
);
1372 }
1373}
1374
1375static void InventoryScreen_Init(void* screen) {
1376 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1377
1378 TableWidget_Create(&s->table);
1379 s->table.font = &s->font;
1380 s->table.blocksPerRow = Inventory.BlocksPerRow;
1381 TableWidget_RecreateBlocks(&s->table);
1382
1383 /* Can't immediately move to selected here, because cursor grabbed */
1384 /* status might be toggled after InventoryScreen_Init() is called. */
1385 /* That causes the cursor to be moved back to the middle of the window. */
1386 s->deferredSelect = true1;
1387
1388 Event_Register_(&BlockEvents.PermissionsChanged, s, InventoryScreen_OnBlockChanged)Event_Register((struct Event_Void*)(&BlockEvents.PermissionsChanged
), s, (Event_Void_Callback)(InventoryScreen_OnBlockChanged))
;
1389 Event_Register_(&BlockEvents.BlockDefChanged, s, InventoryScreen_OnBlockChanged)Event_Register((struct Event_Void*)(&BlockEvents.BlockDefChanged
), s, (Event_Void_Callback)(InventoryScreen_OnBlockChanged))
;
1390}
1391
1392static void InventoryScreen_Render(void* screen, double delta) {
1393 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1394 if (s->deferredSelect) InventoryScreen_MoveToSelected(s);
1395 Elem_Render(&s->table, delta)(&s->table)->VTABLE->Render(&s->table, delta
)
;
1396}
1397
1398static void InventoryScreen_Layout(void* screen) {
1399 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1400 Widget_Layout(&s->table)(&s->table)->VTABLE->Reposition(&s->table
)
;
1401}
1402
1403static void InventoryScreen_Free(void* screen) {
1404 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1405 Event_Unregister_(&BlockEvents.PermissionsChanged, s, InventoryScreen_OnBlockChanged)Event_Unregister((struct Event_Void*)(&BlockEvents.PermissionsChanged
), s, (Event_Void_Callback)(InventoryScreen_OnBlockChanged))
;
1406 Event_Unregister_(&BlockEvents.BlockDefChanged, s, InventoryScreen_OnBlockChanged)Event_Unregister((struct Event_Void*)(&BlockEvents.BlockDefChanged
), s, (Event_Void_Callback)(InventoryScreen_OnBlockChanged))
;
1407}
1408
1409static int InventoryScreen_KeyDown(void* screen, int key) {
1410 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1411 struct TableWidget* table = &s->table;
1412
1413 if (key == KeyBinds[KEYBIND_INVENTORY] && s->releasedInv) {
1414 Gui_Remove((struct Screen*)s);
1415 } else if (key == KEY_ENTER && table->selectedIndex != -1) {
1416 Inventory_SetSelectedBlock(table->blocks[table->selectedIndex]);
1417 Gui_Remove((struct Screen*)s);
1418 } else if (Elem_HandlesKeyDown(table, key)(table)->VTABLE->HandlesKeyDown(table, key)) {
1419 } else {
1420 return Elem_HandlesKeyDown(&Gui_HUD->hotbar, key)(&Gui_HUD->hotbar)->VTABLE->HandlesKeyDown(&
Gui_HUD->hotbar, key)
;
1421 }
1422 return true1;
1423}
1424
1425static int InventoryScreen_KeyUp(void* screen, int key) {
1426 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1427
1428 if (key == KeyBinds[KEYBIND_INVENTORY]) {
1429 s->releasedInv = true1; return true1;
1430 }
1431 return Elem_HandlesKeyUp(&Gui_HUD->hotbar, key)(&Gui_HUD->hotbar)->VTABLE->HandlesKeyUp(&Gui_HUD
->hotbar, key)
;
1432}
1433
1434static int InventoryScreen_PointerDown(void* screen, int id, int x, int y) {
1435 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1436 struct TableWidget* table = &s->table;
1437 cc_bool handled, hotbar;
1438
1439 if (table->scroll.draggingId == id) return true1;
1440 if (HUDscreen_PointerDown(Gui_HUD, id, x, y)) return true1;
1441 handled = Elem_HandlesPointerDown(table, id, x, y)(table)->VTABLE->HandlesPointerDown(table, id, x, y);
1442
1443 if (!handled || table->pendingClose) {
1444 hotbar = Key_IsControlPressed()(Input_Pressed[KEY_LCTRL] || Input_Pressed[KEY_RCTRL]) || Key_IsShiftPressed()(Input_Pressed[KEY_LSHIFT] || Input_Pressed[KEY_RSHIFT]);
1445 if (!hotbar) Gui_Remove((struct Screen*)s);
1446 }
1447 return true1;
1448}
1449
1450static int InventoryScreen_PointerUp(void* screen, int id, int x, int y) {
1451 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1452 return Elem_HandlesPointerUp(&s->table, id, x, y)(&s->table)->VTABLE->HandlesPointerUp(&s->
table, id, x, y)
;
1453}
1454
1455static int InventoryScreen_PointerMove(void* screen, int id, int x, int y) {
1456 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1457 return Elem_HandlesPointerMove(&s->table, id, x, y)(&s->table)->VTABLE->HandlesPointerMove(&s->
table, id, x, y)
;
1458}
1459
1460static int InventoryScreen_MouseScroll(void* screen, float delta) {
1461 struct InventoryScreen* s = (struct InventoryScreen*)screen;
1462
1463 cc_bool hotbar = Key_IsAltPressed()(Input_Pressed[KEY_LALT] || Input_Pressed[KEY_RALT]) || Key_IsControlPressed()(Input_Pressed[KEY_LCTRL] || Input_Pressed[KEY_RCTRL]) || Key_IsShiftPressed()(Input_Pressed[KEY_LSHIFT] || Input_Pressed[KEY_RSHIFT]);
1464 if (hotbar) return false0;
1465 return Elem_HandlesMouseScroll(&s->table, delta)(&s->table)->VTABLE->HandlesMouseScroll(&s->
table, delta)
;
1466}
1467
1468static const struct ScreenVTABLE InventoryScreen_VTABLE = {
1469 InventoryScreen_Init, Screen_NullUpdate, InventoryScreen_Free,
1470 InventoryScreen_Render, InventoryScreen_BuildMesh,
1471 InventoryScreen_KeyDown, InventoryScreen_KeyUp, Screen_TKeyPress, Screen_TText,
1472 InventoryScreen_PointerDown, InventoryScreen_PointerUp, InventoryScreen_PointerMove, InventoryScreen_MouseScroll,
1473 InventoryScreen_Layout, InventoryScreen_ContextLost, InventoryScreen_ContextRecreated
1474};
1475void InventoryScreen_Show(void) {
1476 struct InventoryScreen* s = &InventoryScreen_Instance;
1477 s->grabsInput = true1;
1478 s->closable = true1;
1479
1480 s->VTABLE = &InventoryScreen_VTABLE;
1481 Gui_Add((struct Screen*)s, GUI_PRIORITY_INVENTORY);
1482}
1483
1484
1485/*########################################################################################################################*
1486*------------------------------------------------------LoadingScreen------------------------------------------------------*
1487*#########################################################################################################################*/
1488static struct LoadingScreen {
1489 Screen_Bodyconst struct ScreenVTABLE* VTABLE; cc_bool grabsInput; cc_bool
blocksWorld; cc_bool closable; cc_bool dirty; int maxVertices
; GfxResourceID vb; struct Widget** widgets; int numWidgets;
1490 struct FontDesc font;
1491 float progress;
1492 int rows;
1493
1494 int progX, progY, progWidth, progHeight;
1495 struct TextWidget title, message;
1496 cc_string titleStr, messageStr;
1497 const char* lastState;
1498
1499 char _titleBuffer[STRING_SIZE64];
1500 char _messageBuffer[STRING_SIZE64];
1501} LoadingScreen;
1502#define LOADING_MAX_VERTICES(2 * 4) (2 * TEXTWIDGET_MAX4)
1503#define LOADING_TILE_SIZE64 64
1504
1505static struct Widget* loading_widgets[2] = {
1506 (struct Widget*)&LoadingScreen.title, (struct Widget*)&LoadingScreen.message
1507};
1508
1509static void LoadingScreen_SetTitle(struct LoadingScreen* s) {
1510 TextWidget_Set(&s->title, &s->titleStr, &s->font);
1511 s->dirty = true1;
1512}
1513static void LoadingScreen_SetMessage(struct LoadingScreen* s) {
1514 TextWidget_Set(&s->message, &s->messageStr, &s->font);
1515 s->dirty = true1;
1516}
1517
1518static void LoadingScreen_CalcMaxVertices(struct LoadingScreen* s) {
1519 s->rows = Math_CeilDiv(WindowInfo.Height, LOADING_TILE_SIZE64);
1520 s->maxVertices = LOADING_MAX_VERTICES(2 * 4) + s->rows * 4;
1521}
1522
1523static void LoadingScreen_Layout(void* screen) {
1524 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1525 int oldRows, y;
1526 Widget_SetLocation(&s->title, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, -31);
1527 Widget_SetLocation(&s->message, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 17);
1528 y = Display_ScaleY(34);
1529
1530 s->progWidth = Display_ScaleX(200);
1531 s->progX = Gui_CalcPos(ANCHOR_CENTRE, 0, s->progWidth, WindowInfo.Width);
1532 s->progHeight = Display_ScaleY(4);
1533 s->progY = Gui_CalcPos(ANCHOR_CENTRE, y, s->progHeight, WindowInfo.Height);
1534
1535 oldRows = s->rows;
1536 LoadingScreen_CalcMaxVertices(s);
1537 if (oldRows == s->rows) return;
1538 Screen_UpdateVb(s);
1539}
1540
1541static void LoadingScreen_ContextLost(void* screen) {
1542 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1543 Font_Free(&s->font);
1544 Screen_ContextLost(screen);
1545}
1546
1547static void LoadingScreen_ContextRecreated(void* screen) {
1548 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1549 Gui_MakeBodyFont(&s->font);
1550 LoadingScreen_SetTitle(s);
1551 LoadingScreen_SetMessage(s);
1552 Screen_UpdateVb(s);
1553}
1554
1555static void LoadingScreen_BuildMesh(void* screen) {
1556 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1557 struct VertexTextured* data;
1558 struct VertexTextured** ptr;
1559 struct Texture tex;
1560 TextureLoc loc;
1561 int atlasIndex, i;
1562
1563 data = Screen_LockVb(s);
1564 ptr = &data;
1565
1566 loc = Block_Tex(BLOCK_DIRT, FACE_YMAX)Blocks.Textures[(BLOCK_DIRT) * FACE_COUNT + (FACE_YMAX)];
1567 Tex_SetRect(tex, 0,0, WindowInfo.Width,LOADING_TILE_SIZE)tex.X = 0; tex.Y = 0; tex.Width = WindowInfo.Width; tex.Height
= 64;
;
1568 tex.uv = Atlas1D_TexRec(loc, 1, &atlasIndex);
1569 tex.uv.U2 = (float)WindowInfo.Width / LOADING_TILE_SIZE64;
1570
1571 for (i = 0; i < s->rows; i++) {
1572 tex.Y = i * LOADING_TILE_SIZE64;
1573 Gfx_Make2DQuad(&tex, PackedCol_Make(64, 64, 64, 255)(((cc_uint8)(64) << 0) | ((cc_uint8)(64) << 8) | (
(cc_uint8)(64) << 16) | ((cc_uint8)(255) << 24))
, ptr);
1574 }
1575
1576 Widget_BuildMesh(&s->title, ptr)(&s->title)->VTABLE->BuildMesh(&s->title,
ptr)
;
1577 Widget_BuildMesh(&s->message, ptr)(&s->message)->VTABLE->BuildMesh(&s->message
, ptr)
;
1578 Gfx_UnlockDynamicVb(s->vb);
1579}
1580
1581static void LoadingScreen_MapLoading(void* screen, float progress) {
1582 ((struct LoadingScreen*)screen)->progress = progress;
1583}
1584
1585static void LoadingScreen_MapLoaded(void* screen) {
1586 Gui_Remove((struct Screen*)screen);
1587}
1588
1589static void LoadingScreen_Init(void* screen) {
1590 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1591 TextWidget_Init(&s->title);
1592 TextWidget_Init(&s->message);
1593 s->widgets = loading_widgets;
1594 s->numWidgets = Array_Elems(loading_widgets)(sizeof(loading_widgets) / sizeof(loading_widgets[0]));
1595
1596 LoadingScreen_CalcMaxVertices(s);
1597 Gfx_SetFog(false0);
1598 Event_Register_(&WorldEvents.Loading, s, LoadingScreen_MapLoading)Event_Register((struct Event_Void*)(&WorldEvents.Loading)
, s, (Event_Void_Callback)(LoadingScreen_MapLoading))
;
1599 Event_Register_(&WorldEvents.MapLoaded, s, LoadingScreen_MapLoaded)Event_Register((struct Event_Void*)(&WorldEvents.MapLoaded
), s, (Event_Void_Callback)(LoadingScreen_MapLoaded))
;
1600}
1601
1602static void LoadingScreen_Render(void* screen, double delta) {
1603 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1604 int offset, filledWidth;
1605 TextureLoc loc;
1606
1607 Gfx_SetTexturing(true1);
1608 Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
1609 Gfx_BindDynamicVbGfx_BindVb(s->vb);
1610
1611 /* Draw background dirt */
1612 offset = 0;
1613 if (s->rows) {
1614 loc = Block_Tex(BLOCK_DIRT, FACE_YMAX)Blocks.Textures[(BLOCK_DIRT) * FACE_COUNT + (FACE_YMAX)];
1615 Gfx_BindTexture(Atlas1D.TexIds[Atlas1D_Index(loc)((loc) >> Atlas1D.Shift)]);
1616 Gfx_DrawVb_IndexedTris(s->rows * 4);
1617 offset = s->rows * 4;
1618 }
1619
1620 offset = Widget_Render2(&s->title, offset)(&s->title)->VTABLE->Render2(&s->title, offset
)
;
1621 offset = Widget_Render2(&s->message, offset)(&s->message)->VTABLE->Render2(&s->message
, offset)
;
Value stored to 'offset' is never read
1622 Gfx_SetTexturing(false0);
1623
1624 filledWidth = (int)(s->progWidth * s->progress);
1625 Gfx_Draw2DFlat(s->progX, s->progY, s->progWidth,
1626 s->progHeight, PackedCol_Make(128, 128, 128, 255)(((cc_uint8)(128) << 0) | ((cc_uint8)(128) << 8) |
((cc_uint8)(128) << 16) | ((cc_uint8)(255) << 24
))
);
1627 Gfx_Draw2DFlat(s->progX, s->progY, filledWidth,
1628 s->progHeight, PackedCol_Make(128, 255, 128, 255)(((cc_uint8)(128) << 0) | ((cc_uint8)(255) << 8) |
((cc_uint8)(128) << 16) | ((cc_uint8)(255) << 24
))
);
1629}
1630
1631static void LoadingScreen_Free(void* screen) {
1632 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1633 Event_Unregister_(&WorldEvents.Loading, s, LoadingScreen_MapLoading)Event_Unregister((struct Event_Void*)(&WorldEvents.Loading
), s, (Event_Void_Callback)(LoadingScreen_MapLoading))
;
1634 Event_Unregister_(&WorldEvents.MapLoaded, s, LoadingScreen_MapLoaded)Event_Unregister((struct Event_Void*)(&WorldEvents.MapLoaded
), s, (Event_Void_Callback)(LoadingScreen_MapLoaded))
;
1635}
1636
1637CC_NOINLINE__attribute__((noinline)) static void LoadingScreen_ShowCommon(const cc_string* title, const cc_string* message) {
1638 struct LoadingScreen* s = &LoadingScreen;
1639 s->lastState = NULL((void*)0);
1640 s->progress = 0.0f;
1641
1642 String_InitArray(s->titleStr, s->_titleBuffer)s->titleStr.buffer = s->_titleBuffer; s->titleStr.length
= 0; s->titleStr.capacity = sizeof(s->_titleBuffer);
;
1643 String_AppendString(&s->titleStr, title);
1644 String_InitArray(s->messageStr, s->_messageBuffer)s->messageStr.buffer = s->_messageBuffer; s->messageStr
.length = 0; s->messageStr.capacity = sizeof(s->_messageBuffer
);
;
1645 String_AppendString(&s->messageStr, message);
1646
1647 s->grabsInput = true1;
1648 s->blocksWorld = true1;
1649 Gui_Add((struct Screen*)s,
1650 Game_ClassicMode ? GUI_PRIORITY_OLDLOADING : GUI_PRIORITY_LOADING);
1651}
1652
1653static const struct ScreenVTABLE LoadingScreen_VTABLE = {
1654 LoadingScreen_Init, Screen_NullUpdate, LoadingScreen_Free,
1655 LoadingScreen_Render, LoadingScreen_BuildMesh,
1656 Screen_TInput, Screen_TInput, Screen_TKeyPress, Screen_TText,
1657 Screen_TPointer, Screen_FPointer, Screen_TPointer, Screen_TMouseScroll,
1658 LoadingScreen_Layout, LoadingScreen_ContextLost, LoadingScreen_ContextRecreated
1659};
1660void LoadingScreen_Show(const cc_string* title, const cc_string* message) {
1661 LoadingScreen.VTABLE = &LoadingScreen_VTABLE;
1662 LoadingScreen_ShowCommon(title, message);
1663}
1664
1665
1666/*########################################################################################################################*
1667*--------------------------------------------------GeneratingMapScreen----------------------------------------------------*
1668*#########################################################################################################################*/
1669static void GeneratingScreen_AtlasChanged(void* obj) {
1670 LoadingScreen.dirty = true1; /* Dirt texture may have changed */
1671}
1672
1673static void GeneratingScreen_Init(void* screen) {
1674 Gen_Done = false0;
1675 LoadingScreen_Init(screen);
1676
1677 Gen_Blocks = (BlockRaw*)Mem_TryAlloc(World.Volume, 1);
1678 if (!Gen_Blocks) {
1679 Window_ShowDialog("Out of memory", "Not enough free memory to generate a map that large.\nTry a smaller size.");
1680 Gen_Done = true1;
1681 } else if (Gen_Vanilla) {
1682 Thread_Start(NotchyGen_Generate, true1);
1683 } else {
1684 Thread_Start(FlatgrassGen_Generate, true1);
1685 }
1686 Event_Register_(&TextureEvents.AtlasChanged, NULL, GeneratingScreen_AtlasChanged)Event_Register((struct Event_Void*)(&TextureEvents.AtlasChanged
), ((void*)0), (Event_Void_Callback)(GeneratingScreen_AtlasChanged
))
;
1687}
1688static void GeneratingScreen_Free(void* screen) {
1689 LoadingScreen_Free(screen);
1690 Event_Unregister_(&TextureEvents.AtlasChanged, NULL, GeneratingScreen_AtlasChanged)Event_Unregister((struct Event_Void*)(&TextureEvents.AtlasChanged
), ((void*)0), (Event_Void_Callback)(GeneratingScreen_AtlasChanged
))
;
1691}
1692
1693static void GeneratingScreen_EndGeneration(void) {
1694 struct LocalPlayer* p = &LocalPlayer_Instance;
1695 float x, z;
1696
1697 Gen_Done = false0;
1698 World_SetNewMap(Gen_Blocks, World.Width, World.Height, World.Length);
1699 if (!Gen_Blocks) { Chat_AddRaw("&cFailed to generate the map."); return; }
1700 Gen_Blocks = NULL((void*)0);
1701
1702 x = (World.Width / 2) + 0.5f; z = (World.Length / 2) + 0.5f;
1703 p->Spawn = Respawn_FindSpawnPosition(x, z, p->Base.Size);
1704
1705 p->SpawnYaw = 0.0f;
1706 p->SpawnPitch = 0.0f;
1707 LocalPlayer_MoveToSpawn();
1708}
1709
1710static void GeneratingScreen_Update(void* screen, double delta) {
1711 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1712 const char* state = (const char*)Gen_CurrentState;
1713 if (state == s->lastState) return;
1714 s->lastState = state;
1715
1716 s->messageStr.length = 0;
1717 String_AppendConst(&s->messageStr, state);
1718 LoadingScreen_SetMessage(s);
1719}
1720
1721static void GeneratingScreen_Render(void* screen, double delta) {
1722 struct LoadingScreen* s = (struct LoadingScreen*)screen;
1723 s->progress = Gen_CurrentProgress;
1724 LoadingScreen_Render(s, delta);
1725 if (Gen_Done) GeneratingScreen_EndGeneration();
1726}
1727
1728static const struct ScreenVTABLE GeneratingScreen_VTABLE = {
1729 GeneratingScreen_Init, GeneratingScreen_Update, GeneratingScreen_Free,
1730 GeneratingScreen_Render, LoadingScreen_BuildMesh,
1731 Screen_TInput, Screen_TInput, Screen_TKeyPress, Screen_TText,
1732 Screen_TPointer, Screen_FPointer, Screen_FPointer, Screen_TMouseScroll,
1733 LoadingScreen_Layout, LoadingScreen_ContextLost, LoadingScreen_ContextRecreated
1734};
1735void GeneratingScreen_Show(void) {
1736 static const cc_string title = String_FromConst("Generating level"){ "Generating level", (sizeof("Generating level") - 1), (sizeof
("Generating level") - 1)}
;
1737 static const cc_string message = String_FromConst("Generating.."){ "Generating..", (sizeof("Generating..") - 1), (sizeof("Generating.."
) - 1)}
;
1738
1739 LoadingScreen.VTABLE = &GeneratingScreen_VTABLE;
1740 LoadingScreen_ShowCommon(&title, &message);
1741}
1742
1743
1744/*########################################################################################################################*
1745*----------------------------------------------------DisconnectScreen-----------------------------------------------------*
1746*#########################################################################################################################*/
1747static struct DisconnectScreen {
1748 Screen_Bodyconst struct ScreenVTABLE* VTABLE; cc_bool grabsInput; cc_bool
blocksWorld; cc_bool closable; cc_bool dirty; int maxVertices
; GfxResourceID vb; struct Widget** widgets; int numWidgets;
1749 double initTime;
1750 cc_bool canReconnect, lastActive;
1751 int lastSecsLeft;
1752 struct ButtonWidget reconnect, quit;
1753
1754 struct FontDesc titleFont, messageFont;
1755 struct TextWidget title, message;
1756 char _titleBuffer[STRING_SIZE64];
1757 char _messageBuffer[STRING_SIZE64];
1758 cc_string titleStr, messageStr;
1759} DisconnectScreen;
1760
1761static struct Widget* disconnect_widgets[4] = {
1762 (struct Widget*)&DisconnectScreen.title,
1763 (struct Widget*)&DisconnectScreen.message,
1764 (struct Widget*)&DisconnectScreen.reconnect,
1765 (struct Widget*)&DisconnectScreen.quit
1766};
1767#define DISCONNECT_MAX_VERTICES(2 * 4 + 2 * 12) (2 * TEXTWIDGET_MAX4 + 2 * BUTTONWIDGET_MAX12)
1768#define DISCONNECT_DELAY_SECS5 5
1769
1770static void DisconnectScreen_Layout(void* screen) {
1771 struct DisconnectScreen* s = (struct DisconnectScreen*)screen;
1772 Widget_SetLocation(&s->title, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, -30);
1773 Widget_SetLocation(&s->message, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 10);
1774 Widget_SetLocation(&s->reconnect, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 80);
1775 Widget_SetLocation(&s->quit, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 130);
1776}
1777
1778static void DisconnectScreen_UpdateReconnect(struct DisconnectScreen* s) {
1779 cc_string msg; char msgBuffer[STRING_SIZE64];
1780 int elapsed, secsLeft;
1781 String_InitArray(msg, msgBuffer)msg.buffer = msgBuffer; msg.length = 0; msg.capacity = sizeof
(msgBuffer);
;
1782
1783 if (s->canReconnect) {
1784 elapsed = (int)(Game.Time - s->initTime);
1785 secsLeft = DISCONNECT_DELAY_SECS5 - elapsed;
1786
1787 if (secsLeft > 0) {
1788 String_Format1(&msg, "Reconnect in %i", &secsLeft);
1789 }
1790 s->reconnect.disabled = secsLeft > 0;
1791 }
1792
1793 if (!msg.length) String_AppendConst(&msg, "Reconnect");
1794 ButtonWidget_Set(&s->reconnect, &msg, &s->titleFont);
1795}
1796
1797static void DisconnectScreen_ContextLost(void* screen) {
1798 struct DisconnectScreen* s = (struct DisconnectScreen*)screen;
1799 Font_Free(&s->titleFont);
1800 Font_Free(&s->messageFont);
1801 Screen_ContextLost(screen);
1802}
1803
1804static void DisconnectScreen_ContextRecreated(void* screen) {
1805 struct DisconnectScreen* s = (struct DisconnectScreen*)screen;
1806 Screen_UpdateVb(screen);
1807
1808 Gui_MakeTitleFont(&s->titleFont);
1809 Gui_MakeBodyFont(&s->messageFont);
1810 TextWidget_Set(&s->title, &s->titleStr, &s->titleFont);
1811 TextWidget_Set(&s->message, &s->messageStr, &s->messageFont);
1812
1813 DisconnectScreen_UpdateReconnect(s);
1814 ButtonWidget_SetConst(&s->quit, "Quit game", &s->titleFont);
1815}
1816
1817static void DisconnectScreen_OnReconnect(void* s, void* w) {
1818 Gui_Remove((struct Screen*)s);
1819 Gui_ShowDefault();
1820 Server.BeginConnect();
1821}
1822static void DisconnectScreen_OnQuit(void* s, void* w) { Window_Close(); }
1823
1824static void DisconnectScreen_Init(void* screen) {
1825 struct DisconnectScreen* s = (struct DisconnectScreen*)screen;
1826 TextWidget_Init(&s->title);
1827 TextWidget_Init(&s->message);
1828
1829 ButtonWidget_Init(&s->reconnect, 300, DisconnectScreen_OnReconnect);
1830 ButtonWidget_Init(&s->quit, 300, DisconnectScreen_OnQuit);
1831 s->reconnect.disabled = !s->canReconnect;
1832 s->maxVertices = DISCONNECT_MAX_VERTICES(2 * 4 + 2 * 12);
1833
1834 /* NOTE: changing VSync can't be done within frame, causes crash on some GPUs */
1835 Gfx_SetFpsLimit(Game_FpsLimit == FPS_LIMIT_VSYNC, 1000 / 5.0f);
1836
1837 s->initTime = Game.Time;
1838 s->lastSecsLeft = DISCONNECT_DELAY_SECS5;
1839 s->widgets = disconnect_widgets;
1840 s->numWidgets = Array_Elems(disconnect_widgets)(sizeof(disconnect_widgets) / sizeof(disconnect_widgets[0]));
1841}
1842
1843static void DisconnectScreen_Update(void* screen, double delta) {
1844 struct DisconnectScreen* s = (struct DisconnectScreen*)screen;
1845 int elapsed, secsLeft;
1846
1847 if (!s->canReconnect) return;
1848 elapsed = (int)(Game.Time - s->initTime);
1849 secsLeft = DISCONNECT_DELAY_SECS5 - elapsed;
1850
1851 if (secsLeft < 0) secsLeft = 0;
1852 if (s->lastSecsLeft == secsLeft && s->reconnect.active == s->lastActive) return;
1853 DisconnectScreen_UpdateReconnect(s);
1854
1855 s->lastSecsLeft = secsLeft;
1856 s->lastActive = s->reconnect.active;
1857 s->dirty = true1;
1858}
1859
1860static void DisconnectScreen_Render(void* screen, double delta) {
1861 PackedCol top = PackedCol_Make(64, 32, 32, 255)(((cc_uint8)(64) << 0) | ((cc_uint8)(32) << 8) | (
(cc_uint8)(32) << 16) | ((cc_uint8)(255) << 24))
;
1862 PackedCol bottom = PackedCol_Make(80, 16, 16, 255)(((cc_uint8)(80) << 0) | ((cc_uint8)(16) << 8) | (
(cc_uint8)(16) << 16) | ((cc_uint8)(255) << 24))
;
1863 Gfx_Draw2DGradient(0, 0, WindowInfo.Width, WindowInfo.Height, top, bottom);
1864
1865 Gfx_SetTexturing(true1);
1866 Screen_Render2Widgets(screen, delta);
1867 Gfx_SetTexturing(false0);
1868}
1869
1870static void DisconnectScreen_Free(void* screen) { Game_SetFpsLimit(Game_FpsLimit); }
1871
1872static const struct ScreenVTABLE DisconnectScreen_VTABLE = {
1873 DisconnectScreen_Init, DisconnectScreen_Update, DisconnectScreen_Free,
1874 DisconnectScreen_Render, Screen_BuildMesh,
1875 Screen_InputDown, Screen_TInput, Screen_TKeyPress, Screen_TText,
1876 Menu_PointerDown, Screen_FPointer, Menu_PointerMove, Screen_TMouseScroll,
1877 DisconnectScreen_Layout, DisconnectScreen_ContextLost, DisconnectScreen_ContextRecreated
1878};
1879void DisconnectScreen_Show(const cc_string* title, const cc_string* message) {
1880 static const cc_string kick = String_FromConst("Kicked "){ "Kicked ", (sizeof("Kicked ") - 1), (sizeof("Kicked ") - 1)
}
;
1881 static const cc_string ban = String_FromConst("Banned "){ "Banned ", (sizeof("Banned ") - 1), (sizeof("Banned ") - 1)
}
;
1882 cc_string why; char whyBuffer[STRING_SIZE64];
1883 struct DisconnectScreen* s = &DisconnectScreen;
1884
1885 s->grabsInput = true1;
1886 s->blocksWorld = true1;
1887
1888 String_InitArray(s->titleStr, s->_titleBuffer)s->titleStr.buffer = s->_titleBuffer; s->titleStr.length
= 0; s->titleStr.capacity = sizeof(s->_titleBuffer);
;
1889 String_AppendString(&s->titleStr, title);
1890 String_InitArray(s->messageStr, s->_messageBuffer)s->messageStr.buffer = s->_messageBuffer; s->messageStr
.length = 0; s->messageStr.capacity = sizeof(s->_messageBuffer
);
;
1891 String_AppendString(&s->messageStr, message);
1892
1893 String_InitArray(why, whyBuffer)why.buffer = whyBuffer; why.length = 0; why.capacity = sizeof
(whyBuffer);
;
1894 String_AppendColorless(&why, message);
1895
1896 s->canReconnect = !(String_CaselessStarts(&why, &kick) || String_CaselessStarts(&why, &ban));
1897 s->VTABLE = &DisconnectScreen_VTABLE;
1898
1899 /* Remove all screens instead of just drawing over them to reduce GPU usage */
1900 Gui_RemoveAll();
1901 Gui_Add((struct Screen*)s, GUI_PRIORITY_DISCONNECT);
1902}
1903
1904
1905/*########################################################################################################################*
1906*--------------------------------------------------------TouchScreen------------------------------------------------------*
1907*#########################################################################################################################*/
1908#ifdef CC_BUILD_TOUCH
1909#define TOUCH_MAX_BTNS (ONSCREEN_MAX_BTNS9 + 3)
1910struct TouchButtonDesc {
1911 const char* text;
1912 cc_uint8 bind;
1913 cc_int16 x, y;
1914 Widget_LeftClick OnClick;
1915 cc_bool* enabled;
1916};
1917
1918static struct TouchScreen {
1919 Screen_Bodyconst struct ScreenVTABLE* VTABLE; cc_bool grabsInput; cc_bool
blocksWorld; cc_bool closable; cc_bool dirty; int maxVertices
; GfxResourceID vb; struct Widget** widgets; int numWidgets;
1920 const struct TouchButtonDesc* descs;
1921 int numOnscreen, numBtns;
1922 struct FontDesc font;
1923 struct ThumbstickWidget thumbstick;
1924 const struct TouchButtonDesc* onscreenDescs[ONSCREEN_MAX_BTNS9];
1925 struct ButtonWidget onscreen[ONSCREEN_MAX_BTNS9];
1926 struct ButtonWidget btns[3];
1927} TouchScreen;
1928
1929static struct Widget* touch_widgets[1 + TOUCH_MAX_BTNS] = {
1930 NULL((void*)0),NULL((void*)0),NULL((void*)0),NULL((void*)0), NULL((void*)0),NULL((void*)0),NULL((void*)0),NULL((void*)0),
1931 NULL((void*)0),
1932 NULL((void*)0),NULL((void*)0),NULL((void*)0), (struct Widget*)&TouchScreen.thumbstick
1933};
1934#define TOUCH_MAX_VERTICES (THUMBSTICKWIDGET_MAX + TOUCH_MAX_BTNS * BUTTONWIDGET_MAX12)
1935
1936static void TouchScreen_OnscreenClick(void* screen, void* widget) {
1937 struct TouchScreen* s = (struct TouchScreen*)screen;
1938 int i = Screen_Index(screen, widget);
1939 int key = KeyBinds[s->onscreenDescs[i]->bind];
1940 Input_Set(key, !Input_Pressed[key]);
1941}
1942
1943static void TouchScreen_ChatClick(void* s, void* w) { ChatScreen_OpenInput(&String_Empty); }
1944static void TouchScreen_RespawnClick(void* s, void* w) { LocalPlayer_HandleRespawn(); }
1945static void TouchScreen_SetSpawnClick(void* s, void* w) { LocalPlayer_HandleSetSpawn(); }
1946static void TouchScreen_FlyClick(void* s, void* w) { LocalPlayer_HandleFly(); }
1947static void TouchScreen_NoclipClick(void* s, void* w) { LocalPlayer_HandleNoclip(); }
1948static void TouchScreen_CameraClick(void* s, void* w) { Camera_CycleActive(); }
1949static void TouchScreen_MoreClick(void* s, void* w) { TouchMoreScreen_Show(); }
1950
1951static void TouchScreen_TabClick(void* s, void* w) {
1952 if (TabListOverlay_Instance.active) {
1953 Gui_Remove((struct Screen*)&TabListOverlay_Instance);
1954 } else {
1955 TabListOverlay_Show();
1956 }
1957}
1958
1959static void TouchScreen_BindClick(void* screen, void* widget) {
1960 struct TouchScreen* s = (struct TouchScreen*)screen;
1961 int i = Screen_Index(screen, widget) - ONSCREEN_MAX_BTNS9;
1962 Input_Set(KeyBinds[s->descs[i].bind], true1);
1963}
1964
1965static const struct TouchButtonDesc onscreenDescs[ONSCREEN_MAX_BTNS9] = {
1966 { "Chat", 0,0,0, TouchScreen_ChatClick },
1967 { "Tablist", 0,0,0, TouchScreen_TabClick },
1968 { "Respawn", 0,0,0, TouchScreen_RespawnClick, &LocalPlayer_Instance.Hacks.CanRespawn },
1969 { "Set spawn", 0,0,0, TouchScreen_SetSpawnClick, &LocalPlayer_Instance.Hacks.CanRespawn },
1970 { "Fly", 0,0,0, TouchScreen_FlyClick, &LocalPlayer_Instance.Hacks.CanFly },
1971 { "Noclip", 0,0,0, TouchScreen_NoclipClick, &LocalPlayer_Instance.Hacks.CanNoclip },
1972 { "Speed", KEYBIND_SPEED, 0,0, TouchScreen_OnscreenClick, &LocalPlayer_Instance.Hacks.CanSpeed },
1973 { "\xabSpeed", KEYBIND_HALF_SPEED, 0,0, TouchScreen_OnscreenClick, &LocalPlayer_Instance.Hacks.CanSpeed },
1974 { "Camera", 0,0,0, TouchScreen_CameraClick, &LocalPlayer_Instance.Hacks.CanUseThirdPerson }
1975};
1976static const struct TouchButtonDesc normDescs[2] = {
1977 { "...", KEYBIND_COUNT, 0, 0, TouchScreen_MoreClick },
1978 { "\x1E", KEYBIND_JUMP, 50, 20, TouchScreen_BindClick }
1979};
1980static const struct TouchButtonDesc hackDescs[3] = {
1981 { "...", KEYBIND_COUNT, 0, 0, TouchScreen_MoreClick },
1982 { "\x1E", KEYBIND_FLY_UP, 50, 60, TouchScreen_BindClick },
1983 { "\x1F", KEYBIND_FLY_DOWN, 50, 20, TouchScreen_BindClick }
1984};
1985
1986static void TouchScreen_InitButtons(struct TouchScreen* s) {
1987 struct HacksComp* hacks = &LocalPlayer_Instance.Hacks;
1988 const struct TouchButtonDesc* desc;
1989 int i, j;
1990 for (i = 0; i < TOUCH_MAX_BTNS; i++) s->widgets[i] = NULL((void*)0);
1991
1992 for (i = 0, j = 0; i < ONSCREEN_MAX_BTNS9; i++) {
1993 if (!(Gui._onscreenButtons & (1 << i))) continue;
1994 desc = &onscreenDescs[i];
1995
1996 ButtonWidget_Init(&s->onscreen[j], 100, desc->OnClick);
1997 if (desc->enabled) s->onscreen[j].disabled = !(*desc->enabled);
1998 s->onscreenDescs[j] = desc;
1999 s->widgets[j] = (struct Widget*)&s->onscreen[j];
2000 j++;
2001 }
2002
2003 s->numOnscreen = j;
2004 if (hacks->Flying || hacks->Noclip) {
2005 s->descs = hackDescs;
2006 s->numBtns = Array_Elems(hackDescs)(sizeof(hackDescs) / sizeof(hackDescs[0]));
2007 } else {
2008 s->descs = normDescs;
2009 s->numBtns = Array_Elems(normDescs)(sizeof(normDescs) / sizeof(normDescs[0]));
2010 }
2011
2012 for (i = 0; i < s->numBtns; i++) {
2013 s->widgets[i + ONSCREEN_MAX_BTNS9] = (struct Widget*)&s->btns[i];
2014 desc = &s->descs[i];
2015 ButtonWidget_Init(&s->btns[i], 40, desc->OnClick);
2016 s->btns[i].col = PackedCol_Make(255, 255, 255, 220)(((cc_uint8)(255) << 0) | ((cc_uint8)(255) << 8) |
((cc_uint8)(255) << 16) | ((cc_uint8)(220) << 24
))
;
2017 }
2018}
2019
2020void TouchScreen_Refresh(void) {
2021 struct TouchScreen* s = &TouchScreen;
2022 /* InitButtons changes number of widgets, hence */
2023 /* must destroy graphics resources BEFORE that */
2024 Screen_ContextLost(s);
2025 TouchScreen_InitButtons(s);
2026 Gui_Refresh((struct Screen*)s);
2027}
2028static void TouchScreen_HacksChanged(void* s) { TouchScreen_Refresh(); }
2029
2030static void TouchScreen_ContextLost(void* screen) {
2031 struct TouchScreen* s = (struct TouchScreen*)screen;
2032 Font_Free(&s->font);
2033 Screen_ContextLost(screen);
2034}
2035
2036static void TouchScreen_ContextRecreated(void* screen) {
2037 struct TouchScreen* s = (struct TouchScreen*)screen;
2038 const struct TouchButtonDesc* desc;
2039 int i;
2040 Screen_UpdateVb(screen);
2041 Gui_MakeTitleFont(&s->font);
2042
2043 for (i = 0; i < s->numOnscreen; i++) {
2044 desc = s->onscreenDescs[i];
2045 ButtonWidget_SetConst(&s->onscreen[i], desc->text, &s->font);
2046 }
2047 for (i = 0; i < s->numBtns; i++) {
2048 desc = &s->descs[i];
2049 ButtonWidget_SetConst(&s->btns[i], desc->text, &s->font);
2050 }
2051}
2052
2053static void TouchScreen_Render(void* screen, double delta) {
2054 if (Gui_GetInputGrab()) return;
2055
2056 Gfx_SetTexturing(true1);
2057 Screen_Render2Widgets(screen, delta);
2058 Gfx_SetTexturing(false0);
2059}
2060
2061static int TouchScreen_PointerDown(void* screen, int id, int x, int y) {
2062 struct TouchScreen* s = (struct TouchScreen*)screen;
2063 int i;
2064 //Chat_Add1("POINTER DOWN: %i", &id);
2065 if (Gui_GetInputGrab()) return false0;
2066
2067 i = Screen_DoPointerDown(screen, id, x, y);
2068 if (i >= ONSCREEN_MAX_BTNS9) s->widgets[i]->active |= id;
2069 return i >= 0;
2070}
2071
2072static int TouchScreen_PointerUp(void* screen, int id, int x, int y) {
2073 struct TouchScreen* s = (struct TouchScreen*)screen;
2074 int i;
2075 //Chat_Add1("POINTER UP: %i", &id);
2076 s->thumbstick.active &= ~id;
2077
2078 for (i = 0; i < s->numBtns; i++) {
2079 if (!(s->btns[i].active & id)) continue;
2080
2081 if (s->descs[i].bind < KEYBIND_COUNT) {
2082 Input_Set(KeyBinds[s->descs[i].bind], false0);
2083 }
2084 s->btns[i].active &= ~id;
2085 return true1;
2086 }
2087 return false0;
2088}
2089
2090static void TouchScreen_Layout(void* screen) {
2091 struct TouchScreen* s = (struct TouchScreen*)screen;
2092 const struct TouchButtonDesc* desc;
2093 int i, height;
2094
2095 for (i = 0; i < s->numOnscreen; i++) {
2096 Widget_SetLocation(&s->onscreen[i], ANCHOR_MAX, ANCHOR_MIN, 10, 10 + i * 40);
2097 }
2098 Widget_SetLocation(&s->btns[0], ANCHOR_CENTRE, ANCHOR_MIN, 0, 10);
2099
2100 /* Need to align these relative to the hotbar */
2101 HUDScreen_Layout(Gui_HUD);
2102 height = Gui_HUD->hotbar.height;
2103
2104 for (i = 1; i < s->numBtns; i++) {
2105 desc = &s->descs[i];
2106 Widget_SetLocation(&s->btns[i], ANCHOR_MAX, ANCHOR_MAX, desc->x, desc->y);
2107 s->btns[i].yOffset += height;
2108 Widget_Layout(&s->btns[i])(&s->btns[i])->VTABLE->Reposition(&s->btns
[i])
;
2109 }
2110
2111 Widget_SetLocation(&s->thumbstick, ANCHOR_MIN, ANCHOR_MAX, 30, 5);
2112 s->thumbstick.yOffset += height;
2113 Widget_Layout(&s->thumbstick)(&s->thumbstick)->VTABLE->Reposition(&s->
thumbstick)
;
2114}
2115
2116struct LocalPlayerInput touchInput;
2117static void TouchScreen_GetMovement(float* xMoving, float* zMoving) {
2118 ThumbstickWidget_GetMovement(&TouchScreen.thumbstick, xMoving, zMoving);
2119}
2120
2121static void TouchScreen_Init(void* screen) {
2122 struct TouchScreen* s = (struct TouchScreen*)screen;
2123
2124 s->widgets = touch_widgets;
2125 s->numWidgets = Array_Elems(touch_widgets)(sizeof(touch_widgets) / sizeof(touch_widgets[0]));
2126 s->maxVertices = TOUCH_MAX_VERTICES;
2127 Event_Register_(&UserEvents.HacksStateChanged, screen, TouchScreen_HacksChanged)Event_Register((struct Event_Void*)(&UserEvents.HacksStateChanged
), screen, (Event_Void_Callback)(TouchScreen_HacksChanged))
;
2128 Event_Register_(&UserEvents.HackPermsChanged, screen, TouchScreen_HacksChanged)Event_Register((struct Event_Void*)(&UserEvents.HackPermsChanged
), screen, (Event_Void_Callback)(TouchScreen_HacksChanged))
;
2129
2130 TouchScreen_InitButtons(s);
2131 ThumbstickWidget_Init(&s->thumbstick);
2132 touchInput.GetMovement = TouchScreen_GetMovement;
2133 LocalPlayer_Instance.input.next = &touchInput;
2134}
2135
2136static void TouchScreen_Free(void* s) {
2137 Event_Unregister_(&UserEvents.HacksStateChanged, s, TouchScreen_HacksChanged)Event_Unregister((struct Event_Void*)(&UserEvents.HacksStateChanged
), s, (Event_Void_Callback)(TouchScreen_HacksChanged))
;
2138 Event_Unregister_(&UserEvents.HackPermsChanged, s, TouchScreen_HacksChanged)Event_Unregister((struct Event_Void*)(&UserEvents.HackPermsChanged
), s, (Event_Void_Callback)(TouchScreen_HacksChanged))
;
2139}
2140
2141static const struct ScreenVTABLE TouchScreen_VTABLE = {
2142 TouchScreen_Init, Screen_NullUpdate, TouchScreen_Free,
2143 TouchScreen_Render, Screen_BuildMesh,
2144 Screen_FInput, Screen_FInput, Screen_FKeyPress, Screen_FText,
2145 TouchScreen_PointerDown, TouchScreen_PointerUp, Screen_FPointer, Screen_FMouseScroll,
2146 TouchScreen_Layout, TouchScreen_ContextLost, TouchScreen_ContextRecreated
2147};
2148void TouchScreen_Show(void) {
2149 struct TouchScreen* s = &TouchScreen;
2150 s->VTABLE = &TouchScreen_VTABLE;
2151
2152 if (!Input_TouchMode0) return;
2153 Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCH);
2154}
2155#endif