Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/Menu/CompetitionMenu.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: CompetitionMenu Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
#if MANIA_USE_PLUS
11
ObjectCompetitionMenu *CompetitionMenu;
12
13
void CompetitionMenu_Update(void) {}
14
15
void CompetitionMenu_LateUpdate(void) {}
16
17
void CompetitionMenu_StaticUpdate(void) { CompetitionMenu_HandleStartCompPrompt(); }
18
19
void CompetitionMenu_Draw(void) {}
20
21
void CompetitionMenu_Create(void *data) {}
22
23
void CompetitionMenu_StageLoad(void) { CompetitionMenu->timer = 120; }
24
25
void CompetitionMenu_Initialize(void)
26
{
27
String tag;
28
INIT_STRING(tag);
29
30
foreach_all(UIControl, control)
31
{
32
RSDK.SetString(&tag, "Competition");
33
if (RSDK.CompareStrings(&tag, &control->tag, false))
34
CompetitionMenu->competitionControl = control;
35
36
RSDK.SetString(&tag, "Competition Legacy");
37
if (RSDK.CompareStrings(&tag, &control->tag, false))
38
CompetitionMenu->competitionControl_Legacy = control;
39
40
RSDK.SetString(&tag, "Competition Rules");
41
if (RSDK.CompareStrings(&tag, &control->tag, false)) {
42
CompetitionMenu->compRulesControl = control;
43
control->backPressCB = CompetitionMenu_CompRules_BackPressCB;
44
}
45
46
RSDK.SetString(&tag, "Competition Zones");
47
if (RSDK.CompareStrings(&tag, &control->tag, false)) {
48
CompetitionMenu->compZoneControl = control;
49
control->backPressCB = CompetitionMenu_CompZones_BackPressCB;
50
}
51
52
RSDK.SetString(&tag, "Competition Round");
53
if (RSDK.CompareStrings(&tag, &control->tag, false))
54
CompetitionMenu->compRoundControl = control;
55
56
RSDK.SetString(&tag, "Competition Total");
57
if (RSDK.CompareStrings(&tag, &control->tag, false))
58
CompetitionMenu->compTotalControl = control;
59
}
60
61
foreach_all(UIInfoLabel, label)
62
{
63
EntityUIControl *roundControl = CompetitionMenu->compRoundControl;
64
EntityUIControl *totalControl = CompetitionMenu->compTotalControl;
65
66
if (UIControl_ContainsPos(roundControl, &label->position))
67
CompetitionMenu->resultsLabel_Round = label;
68
69
if (UIControl_ContainsPos(totalControl, &label->position))
70
CompetitionMenu->resultsLabel_Total = label;
71
}
72
73
foreach_all(UIButtonPrompt, prompt)
74
{
75
EntityUIControl *compControl = CompetitionMenu->competitionControl;
76
EntityUIControl *compControl_Legacy = CompetitionMenu->competitionControl_Legacy;
77
78
if (UIControl_ContainsPos(compControl, &prompt->position) && prompt->buttonID == 5)
79
CompetitionMenu->startCompPrompt = prompt;
80
81
if (UIControl_ContainsPos(compControl_Legacy, &prompt->position) && prompt->buttonID == 5)
82
CompetitionMenu->startCompPrompt_Legacy = prompt;
83
}
84
}
85
86
void CompetitionMenu_SetupActions(void)
87
{
88
EntityUIControl *compControl = CompetitionMenu->competitionControl;
89
EntityUIControl *compControl_Legacy = CompetitionMenu->competitionControl_Legacy;
90
EntityUIControl *rulesControl = CompetitionMenu->compRulesControl;
91
EntityUIControl *roundControl = CompetitionMenu->compRoundControl;
92
EntityUIControl *totalControl = CompetitionMenu->compTotalControl;
93
94
foreach_all(UIButton, button)
95
{
96
if (UIControl_ContainsPos(rulesControl, &button->position) && button->listID == 9 && button->frameID == 2)
97
button->actionCB = CompetitionMenu_RulesButton_ActionCB;
98
}
99
100
compControl->processButtonInputCB = CompetitionMenu_VS_ProcessInputCB;
101
compControl->menuSetupCB = CompetitionMenu_VS_MenuSetupCB;
102
if (compControl->active == ACTIVE_ALWAYS)
103
CompetitionMenu_VS_MenuSetupCB();
104
105
compControl_Legacy->processButtonInputCB = CompetitionMenu_VS_ProcessInputCB;
106
compControl_Legacy->menuSetupCB = CompetitionMenu_VS_MenuSetupCB;
107
if (compControl_Legacy->active == ACTIVE_ALWAYS)
108
CompetitionMenu_VS_MenuSetupCB();
109
110
rulesControl->menuSetupCB = CompetitionMenu_Rules_MenuSetupCB;
111
if (rulesControl->active == ACTIVE_ALWAYS)
112
CompetitionMenu_Rules_MenuSetupCB();
113
114
roundControl->processButtonInputCB = CompetitionMenu_Round_ProcessInputCB;
115
roundControl->menuSetupCB = CompetitionMenu_Round_MenuSetupCB;
116
if (roundControl->active == ACTIVE_ALWAYS)
117
CompetitionMenu_Round_MenuSetupCB();
118
119
totalControl->processButtonInputCB = CompetitionMenu_Results_ProcessInputCB;
120
totalControl->menuSetupCB = CompetitionMenu_Results_MenuSetupCB;
121
totalControl->menuUpdateCB = CompetitionMenu_Results_MenuUpdateCB;
122
totalControl->targetPos.y = totalControl->startPos.y;
123
totalControl->position.y = totalControl->startPos.y;
124
if (totalControl->active == ACTIVE_ALWAYS)
125
CompetitionMenu_Results_MenuSetupCB();
126
127
foreach_all(UIVsZoneButton, zoneButton) { zoneButton->actionCB = CompetitionMenu_ZoneButtonActionCB; }
128
}
129
130
void CompetitionMenu_HandleMenuReturn(void)
131
{
132
EntityCompetitionSession *session = CompetitionSession_GetSession();
133
134
if (session->inMatch) {
135
foreach_all(UIControl, control)
136
{
137
EntityUIControl *compControl = CompetitionMenu->competitionControl;
138
if (!API.CheckDLC(DLC_PLUS))
139
compControl = CompetitionMenu->competitionControl_Legacy;
140
141
if (control == compControl) {
142
foreach_all(UIVsCharSelector, selector)
143
{
144
switch (session->playerID[selector->playerID]) {
145
case ID_SONIC: selector->frameID = 0; break;
146
case ID_TAILS: selector->frameID = 1; break;
147
case ID_KNUCKLES: selector->frameID = 2; break;
148
case ID_MIGHTY: selector->frameID = 3; break;
149
case ID_RAY: selector->frameID = 4; break;
150
default: break;
151
}
152
}
153
}
154
155
if (control == CompetitionMenu->compRulesControl) {
156
switch (session->itemMode) {
157
case ITEMS_FIXED: UIButton_SetChoiceSelection(control->buttons[0], 0); break;
158
case ITEMS_RANDOM: UIButton_SetChoiceSelection(control->buttons[0], 2); break;
159
case ITEMS_TELEPORT: UIButton_SetChoiceSelection(control->buttons[0], 1); break;
160
}
161
162
EntityUIVsRoundPicker *picker = (EntityUIVsRoundPicker *)UIButton_GetChoicePtr(control->buttons[1], control->buttons[1]->selection);
163
if (picker)
164
picker->val = session->matchCount;
165
166
UIButton_SetChoiceSelectionWithCB(control->buttons[2], session->screenBorderType[2]);
167
CompetitionMenu_SetupSplitScreenChoices(session->playerCount);
168
}
169
170
if (control == CompetitionMenu->compZoneControl) {
171
for (int32 i = 0; i < 12; ++i) {
172
EntityUIVsZoneButton *button = (EntityUIVsZoneButton *)control->buttons[i];
173
if (button && session->completedStages[i])
174
button->xOut = true;
175
}
176
}
177
}
178
}
179
}
180
181
int32 CompetitionMenu_HandleUnlocks(void)
182
{
183
int32 maxRounds = 0;
184
185
foreach_all(UIVsZoneButton, zoneButton)
186
{
187
zoneButton->xOut = !GameProgress_GetZoneUnlocked(zoneButton->zoneID);
188
zoneButton->obfuscate = zoneButton->xOut;
189
190
if (!zoneButton->xOut)
191
++maxRounds;
192
}
193
194
return maxRounds;
195
}
196
197
void CompetitionMenu_HandleStartCompPrompt(void)
198
{
199
int32 readyCount = CompetitionMenu_GetReadyPlayerCount();
200
int32 activeCount = CompetitionMenu_GetTotalPlayerCount();
201
202
EntityUIButtonPrompt *startComp = CompetitionMenu->startCompPrompt;
203
if (startComp)
204
startComp->visible = readyCount > 1 && readyCount == activeCount;
205
206
EntityUIButtonPrompt *startCompLegacy = CompetitionMenu->startCompPrompt_Legacy;
207
if (startCompLegacy)
208
startCompLegacy->visible = readyCount > 1 && readyCount == activeCount;
209
}
210
211
int32 CompetitionMenu_GetReadyPlayerCount(void)
212
{
213
EntityUIControl *control = CompetitionMenu->competitionControl;
214
if (!API.CheckDLC(DLC_PLUS))
215
control = CompetitionMenu->competitionControl_Legacy;
216
217
if (!control)
218
return 0;
219
220
int32 readyPlayers = 0;
221
for (int32 i = 0; i < control->buttonCount; ++i) {
222
EntityUIVsCharSelector *button = (EntityUIVsCharSelector *)control->buttons[i];
223
if (button->ready && !button->isSelected)
224
++readyPlayers;
225
}
226
227
return readyPlayers;
228
}
229
230
int32 CompetitionMenu_GetTotalPlayerCount(void)
231
{
232
EntityUIControl *control = CompetitionMenu->competitionControl;
233
if (!API.CheckDLC(DLC_PLUS))
234
control = CompetitionMenu->competitionControl_Legacy;
235
236
if (!control)
237
return 0;
238
239
int32 activePlayers = 0;
240
for (int32 i = 0; i < control->buttonCount; ++i) {
241
EntityUIVsCharSelector *button = (EntityUIVsCharSelector *)control->buttons[i];
242
if (button->ready || button->isSelected)
243
++activePlayers;
244
}
245
246
return activePlayers;
247
}
248
249
void CompetitionMenu_ResetControllerAssignments(void)
250
{
251
EntityUIVsCharSelector *buttons[PLAYER_COUNT];
252
EntityUIControl *control = CompetitionMenu->competitionControl;
253
254
int32 playerID = 0;
255
for (int32 p = 0; p < PLAYER_COUNT; ++p) buttons[p] = (EntityUIVsCharSelector *)control->buttons[p];
256
257
for (int32 p = 0; p < PLAYER_COUNT; ++p) {
258
EntityUIVsCharSelector *selector = buttons[p];
259
int32 id = API_GetInputDeviceID(p + 1);
260
261
if (id && id != INPUT_AUTOASSIGN) {
262
if (playerID < p)
263
API_AssignInputSlotToDevice(p, INPUT_NONE);
264
265
API_AssignInputSlotToDevice(CONT_P1 + playerID, id);
266
267
buttons[playerID]->frameID = selector->frameID;
268
if (playerID < p)
269
selector->frameID = selector->playerID;
270
271
++playerID;
272
}
273
}
274
275
for (; playerID < PLAYER_COUNT; ++playerID) API_AssignInputSlotToDevice(CONT_P1 + playerID, INPUT_NONE);
276
}
277
278
void CompetitionMenu_SetupSplitScreenChoices(int32 playerCount)
279
{
280
EntityUIButton *screenLayoutChoice = CompetitionMenu->compRulesControl->buttons[2];
281
282
bool32 choices[5];
283
284
choices[0] = playerCount == 2;
285
choices[1] = playerCount == 2;
286
287
choices[2] = playerCount == 3;
288
choices[3] = playerCount == 3;
289
290
choices[4] = playerCount == 4;
291
292
for (int32 c = 0; c < screenLayoutChoice->choiceCount; ++c) {
293
EntityUIChoice *choice = (EntityUIChoice *)UIButton_GetChoicePtr(screenLayoutChoice, c);
294
295
if (choice)
296
choice->disabled = !choices[c];
297
}
298
299
EntityUIChoice *choice = (EntityUIChoice *)UIButton_GetChoicePtr(screenLayoutChoice, screenLayoutChoice->selection);
300
if (choice->disabled) {
301
if (playerCount == 2)
302
UIButton_SetChoiceSelectionWithCB(screenLayoutChoice, 0);
303
else if (playerCount == 3)
304
UIButton_SetChoiceSelectionWithCB(screenLayoutChoice, 2);
305
else
306
UIButton_SetChoiceSelectionWithCB(screenLayoutChoice, 4);
307
308
UIButton_ManageChoices(screenLayoutChoice);
309
}
310
}
311
void CompetitionMenu_SetupSplitScreen(int32 mode)
312
{
313
EntityCompetitionSession *session = CompetitionSession_GetSession();
314
int32 startVert_3P[15];
315
uint8 startVert_2P[10];
316
317
memset(startVert_2P, 0, sizeof(startVert_2P));
318
memset(startVert_3P, 0, sizeof(startVert_3P));
319
320
startVert_2P[(0 * 5) + 0] = 18;
321
startVert_2P[(0 * 5) + 1] = 6;
322
startVert_2P[(0 * 5) + 2] = 0;
323
startVert_2P[(0 * 5) + 3] = 0;
324
startVert_2P[(0 * 5) + 4] = 0;
325
326
startVert_2P[(1 * 5) + 0] = 24;
327
startVert_2P[(1 * 5) + 1] = 12;
328
startVert_2P[(1 * 5) + 2] = 0;
329
startVert_2P[(1 * 5) + 3] = 0;
330
startVert_2P[(1 * 5) + 4] = 0;
331
332
startVert_3P[(0 * 5) + 0] = 0;
333
startVert_3P[(0 * 5) + 1] = 0;
334
startVert_3P[(0 * 5) + 2] = 30;
335
startVert_3P[(0 * 5) + 3] = 6;
336
startVert_3P[(0 * 5) + 4] = 0;
337
338
startVert_3P[(1 * 5) + 0] = 0;
339
startVert_3P[(1 * 5) + 1] = 0;
340
startVert_3P[(1 * 5) + 2] = 36;
341
startVert_3P[(1 * 5) + 3] = 42;
342
startVert_3P[(1 * 5) + 4] = 0;
343
344
startVert_3P[(2 * 5) + 0] = 0;
345
startVert_3P[(2 * 5) + 1] = 0;
346
startVert_3P[(2 * 5) + 2] = 12;
347
startVert_3P[(2 * 5) + 3] = 48;
348
startVert_3P[(2 * 5) + 4] = 0;
349
350
RSDK.SetScreenVertices(startVert_2P[mode], startVert_2P[5 + mode], startVert_3P[mode], startVert_3P[5 + mode], startVert_3P[10 + mode]);
351
352
switch (mode) {
353
case 0: // 2P (Streched)
354
case 1: // 2P (Bordered)
355
session->screenBorderType[0] = VS_BORDER_BOTTOM;
356
session->screenBorderType[1] = VS_BORDER_TOP;
357
break;
358
359
case 2: // 3P (P1 & P2 top, P3 bottom)
360
session->screenBorderType[0] = VS_BORDER_BOTTOMRIGHT;
361
session->screenBorderType[1] = VS_BORDER_BOTTOMLEFT;
362
session->screenBorderType[2] = VS_BORDER_TOP;
363
break;
364
365
case 3: // 3P (P1 top, P2 & P3 bottom)
366
session->screenBorderType[0] = VS_BORDER_BOTTOM;
367
session->screenBorderType[1] = VS_BORDER_TOPRIGHT;
368
session->screenBorderType[2] = VS_BORDER_TOPLEFT;
369
break;
370
371
case 4: // 4P
372
session->screenBorderType[0] = VS_BORDER_BOTTOMRIGHT;
373
session->screenBorderType[1] = VS_BORDER_BOTTOMLEFT;
374
session->screenBorderType[2] = VS_BORDER_TOPRIGHT;
375
session->screenBorderType[3] = VS_BORDER_TOPLEFT;
376
break;
377
378
default: break;
379
}
380
}
381
382
void CompetitionMenu_SetupResultsUI(EntityUIControl *roundControl)
383
{
384
EntityCompetitionSession *session = CompetitionSession_GetSession();
385
386
int32 offsets[] = { -580000, 0x580000, 0x0, 0x0, -0x7A0000, 0x000000, 0x7A0000, 0x000000, -0x9C0000, -0x340000, 0x340000, 0x9C0000 };
387
388
int32 offsetPtr = 4 * (session->playerCount - 2);
389
for (int32 p = 0; p < PLAYER_COUNT; ++p) {
390
EntityUIButton *button = roundControl->buttons[p];
391
if (session->playerCount <= p) {
392
button->visible = false;
393
}
394
else {
395
button->visible = true;
396
button->position.x = roundControl->position.x + offsets[offsetPtr + p];
397
}
398
}
399
}
400
401
void CompetitionMenu_GotoCompRules(void)
402
{
403
CompetitionMenu_SetupSplitScreenChoices(CompetitionMenu_GetTotalPlayerCount());
404
UIControl_MatchMenuTag("Competition Rules");
405
}
406
407
void CompetitionMenu_GotoCompZones(void) { UIControl_MatchMenuTag("Competition Zones"); }
408
409
void CompetitionMenu_VS_ProcessInputCB(void)
410
{
411
EntityUIControl *control = CompetitionMenu->competitionControl;
412
if (!API.CheckDLC(DLC_PLUS))
413
control = CompetitionMenu->competitionControl_Legacy;
414
415
if (control) {
416
for (int32 i = 0; i < control->buttonCount; ++i) {
417
EntityUIVsCharSelector *charSel = (EntityUIVsCharSelector *)control->buttons[i];
418
419
Entity *entStore = SceneInfo->entity;
420
SceneInfo->entity = (Entity *)charSel;
421
StateMachine_Run(charSel->processButtonCB);
422
SceneInfo->entity = entStore;
423
424
API_GetInputDeviceID(charSel->playerID + 1);
425
}
426
427
EntityUIButtonPrompt *goPrompt = NULL;
428
for (int32 i = 0; i < control->promptCount; ++i) {
429
EntityUIButtonPrompt *prompt = control->prompts[i];
430
431
if (prompt->buttonID == 4)
432
goPrompt = prompt;
433
}
434
435
int32 readyPlayers = CompetitionMenu_GetReadyPlayerCount();
436
if (readyPlayers > 1 && readyPlayers == CompetitionMenu_GetTotalPlayerCount()) {
437
if (UIControl->startPress[0] || UIControl->startPress[1] || UIControl->startPress[2] || UIControl->startPress[3]) {
438
control->selectionDisabled = true;
439
UITransition_StartTransition(CompetitionMenu_GotoCompRules, 0);
440
}
441
442
goPrompt->visible = true;
443
}
444
else {
445
goPrompt->visible = false;
446
}
447
}
448
}
449
450
void CompetitionMenu_VS_MenuSetupCB(void)
451
{
452
RSDK_THIS(UIControl);
453
454
self->childHasFocus = false;
455
for (int32 i = 0; i < self->buttonCount; ++i) {
456
EntityUIVsCharSelector *charSel = (EntityUIVsCharSelector *)self->buttons[i];
457
458
charSel->isSelected = true;
459
charSel->ready = false;
460
charSel->processButtonCB = UIVsCharSelector_ProcessButtonCB;
461
462
if (!API_GetInputDeviceID(CONT_P1 + charSel->playerID))
463
API_AssignInputSlotToDevice(CONT_P1 + charSel->playerID, INPUT_AUTOASSIGN);
464
}
465
466
for (int32 i = 0; i < self->promptCount; ++i) {
467
EntityUIButtonPrompt *prompt = self->prompts[i];
468
469
if (prompt->buttonID == 4)
470
prompt->visible = false;
471
}
472
}
473
474
void CompetitionMenu_Rules_MenuSetupCB(void)
475
{
476
if (API.CheckDLC(DLC_PLUS))
477
CompetitionMenu_ResetControllerAssignments();
478
}
479
480
void CompetitionMenu_StartMatch(void)
481
{
482
EntityCompetitionSession *session = CompetitionSession_GetSession();
483
EntityMenuParam *param = MenuParam_GetParam();
484
485
sprintf_s(param->menuTag, (int32)sizeof(param->menuTag), "Competition Round");
486
session->stageIndex = CompetitionMenu->compZoneControl->buttonID;
487
session->zoneID = param->vsZoneID;
488
session->actID = param->vsActID;
489
session->prevMatchID = session->matchID;
490
491
for (int32 p = 0; p < session->playerCount; ++p) {
492
if (!session->lives[p])
493
session->lives[p] = 1;
494
}
495
496
if (globals->gameMode == MODE_ENCORE)
497
RSDK.SetScene("Encore Mode", "");
498
else
499
RSDK.SetScene("Mania Mode", "");
500
SceneInfo->listPos += TimeAttackData_GetManiaListPos(param->vsZoneID, param->vsActID, CHAR_SONIC);
501
502
SaveGame_ResetPlayerState();
503
504
// Bug Details(?):
505
// sizeof(globals->noSaveSlot) and sizeof(saveData) is 4096 (sizeof(int32) * 0x400)
506
// but the memset size is only 1024 (sizeof(uint8) * 0x400)
507
// so only about 1/4th of the save slot is cleared, though nothin uses the extra space so it's not a big deal
508
memset(globals->noSaveSlot, 0, 0x400);
509
510
globals->continues = 0;
511
globals->saveSlotID = NO_SAVE_SLOT;
512
globals->gameMode = MODE_COMPETITION;
513
globals->medalMods = 0;
514
515
globals->playerID = ID_NONE;
516
for (int32 p = 0; p < session->playerCount; ++p) globals->playerID |= session->playerID[p] << (8 * p);
517
518
globals->itemMode = session->itemMode;
519
520
RSDK.LoadScene();
521
}
522
523
void CompetitionMenu_ZoneButtonActionCB(void) { MenuSetup_StartTransition(CompetitionMenu_StartMatch, 32); }
524
525
void CompetitionMenu_RulesButton_ActionCB(void)
526
{
527
EntityUIControl *control = CompetitionMenu->competitionControl;
528
if (!API.CheckDLC(DLC_PLUS))
529
control = CompetitionMenu->competitionControl_Legacy;
530
531
EntityUIControl *rulesControl = CompetitionMenu->compRulesControl;
532
EntityCompetitionSession *session = CompetitionSession_GetSession();
533
534
int32 matchCount = 0;
535
foreach_all(UIVsRoundPicker, picker)
536
{
537
matchCount = picker->val;
538
foreach_break;
539
}
540
541
int32 itemMode = ITEMS_FIXED;
542
switch (rulesControl->buttons[0]->selection) {
543
default: break;
544
case 0: itemMode = ITEMS_FIXED; break;
545
case 1: itemMode = ITEMS_TELEPORT; break;
546
case 2: itemMode = ITEMS_RANDOM; break;
547
}
548
549
Competition_ResetOptions();
550
551
session->matchCount = matchCount;
552
session->inMatch = true;
553
session->itemMode = itemMode;
554
555
CompetitionMenu_SetupSplitScreen(rulesControl->buttons[2]->selection);
556
session->displayMode = rulesControl->buttons[2]->selection;
557
558
session->playerCount = 0;
559
for (int32 i = 0; i < control->buttonCount; ++i) {
560
EntityUIVsCharSelector *charSel = (EntityUIVsCharSelector *)control->buttons[i];
561
int32 id = API_GetInputDeviceID(CONT_P1 + i);
562
if (id && id != INPUT_UNASSIGNED) {
563
switch (charSel->frameID) {
564
case 0: session->playerID[i] = ID_SONIC; break;
565
case 1: session->playerID[i] = ID_TAILS; break;
566
case 2: session->playerID[i] = ID_KNUCKLES; break;
567
#if MANIA_USE_PLUS
568
case 3: session->playerID[i] = ID_MIGHTY; break;
569
case 4: session->playerID[i] = ID_RAY; break;
570
#endif
571
default: break;
572
}
573
574
session->inputSlots[i] = id;
575
session->playerCount++;
576
}
577
}
578
579
EntityUIControl *zoneControl = CompetitionMenu->compZoneControl;
580
zoneControl->position = zoneControl->startPos;
581
zoneControl->targetPos.x = zoneControl->startPos.x;
582
zoneControl->targetPos.y = zoneControl->startPos.y;
583
zoneControl->buttonID = 0;
584
585
CompetitionMenu_HandleUnlocks();
586
587
UIControl_MatchMenuTag("Competition Zones");
588
}
589
590
void CompetitionMenu_GotoCompTotal(void) { UIControl_MatchMenuTag("Competition Total"); }
591
592
void CompetitionMenu_Round_ProcessInputCB(void)
593
{
594
EntityCompetitionSession *session = CompetitionSession_GetSession();
595
if (UIControl->anyConfirmPress) {
596
bool32 toCompTotal = false;
597
598
int32 activePlayers = 0;
599
for (int32 p = 0; p < session->playerCount; ++p) {
600
if (session->lives[p] > 0)
601
activePlayers++;
602
603
if (session->wins[p] > (session->matchCount >> 1))
604
toCompTotal = true;
605
}
606
607
EntityUIControl *zoneControl = CompetitionMenu->compZoneControl;
608
int32 remainingZones = 0;
609
for (int32 i = 0; i < 12; ++i) {
610
if (zoneControl->buttons[i]) {
611
EntityUIVsZoneButton *zoneButton = (EntityUIVsZoneButton *)zoneControl->buttons[i];
612
if (!session->completedStages[i] && GameProgress_GetZoneUnlocked(zoneButton->zoneID))
613
++remainingZones;
614
}
615
}
616
617
if (toCompTotal || activePlayers < 2 || session->matchID >= session->matchCount || !remainingZones)
618
UITransition_StartTransition(CompetitionMenu_GotoCompTotal, 0);
619
else
620
UITransition_StartTransition(CompetitionMenu_GotoCompZones, 0);
621
622
RSDK.PlaySfx(UIWidgets->sfxAccept, false, 255);
623
UIControl->inputLocked = true;
624
}
625
}
626
627
void CompetitionMenu_Round_MenuSetupCB(void)
628
{
629
EntityCompetitionSession *session = CompetitionSession_GetSession();
630
EntityUIControl *roundControl = CompetitionMenu->compRoundControl;
631
CompetitionMenu_SetupResultsUI(roundControl);
632
633
String roundLabelStr;
634
INIT_STRING(roundLabelStr);
635
636
char roundLabel[0x100];
637
memset(roundLabel, 0, sizeof(roundLabel));
638
639
Localization_GetZoneName(&roundLabelStr, session->zoneID);
640
if (session->zoneID < 12) {
641
char buf[16];
642
sprintf_s(buf, (int32)sizeof(buf), " ZONE %d", session->actID + 1);
643
RSDK.AppendText(&roundLabelStr, buf);
644
}
645
646
RSDK.GetCString(roundLabel, &roundLabelStr);
647
UIInfoLabel_SetText(CompetitionMenu->resultsLabel_Round, roundLabel);
648
649
int32 bestRings = 0;
650
int32 bestTotalRings = 0;
651
int32 bestScore = 0;
652
int32 bestItems = 0;
653
uint32 bestTime = 0xFFFFFFFF;
654
uint32 times[PLAYER_COUNT];
655
656
for (int32 p = 0; p < session->playerCount; ++p) {
657
if (session->rings[p] > bestRings)
658
bestRings = session->rings[p];
659
660
if (session->totalRings[p] > bestTotalRings)
661
bestTotalRings = session->totalRings[p];
662
663
if (session->score[p] > bestScore)
664
bestScore = session->score[p];
665
666
if (session->items[p] > bestItems)
667
bestItems = session->items[p];
668
669
times[p] = session->time[p].milliseconds + 100 * (session->time[p].seconds + 4 * (16 * session->time[p].minutes - session->time[p].minutes));
670
if (times[p] < bestTime)
671
bestTime = times[p];
672
}
673
674
char buffer[0x40];
675
int32 winnerCount = 0;
676
int32 match = session->matchID - 1;
677
678
for (int32 p = 0; p < session->playerCount; ++p) {
679
EntityUIVsResults *results = (EntityUIVsResults *)roundControl->buttons[p];
680
681
results->isWinner = session->matchWinner[match] & (1 << p);
682
results->isLoser = session->matchWinner[match] & (1 << p);
683
684
if (session->matchWinner[match] & (1 << p))
685
winnerCount++;
686
687
results->trophyCount = session->wins[p];
688
memset(buffer, 0, sizeof(buffer));
689
690
sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->rings[p]);
691
if (!SceneInfo->inEditor) {
692
RSDK.InitString(&results->rowText[0], buffer, 0);
693
RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[0]);
694
}
695
696
sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->totalRings[p]);
697
if (!SceneInfo->inEditor) {
698
RSDK.InitString(&results->rowText[1], buffer, 0);
699
RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[1]);
700
}
701
702
sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->score[p]);
703
if (!SceneInfo->inEditor) {
704
RSDK.InitString(&results->rowText[2], buffer, 0);
705
RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[2]);
706
}
707
708
sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->items[p]);
709
if (!SceneInfo->inEditor) {
710
RSDK.InitString(&results->rowText[3], buffer, 0);
711
RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[3]);
712
}
713
714
sprintf_s(buffer, (int32)sizeof(buffer), "%d'%02d\"%02d", session->time[p].minutes, session->time[p].seconds, session->time[p].milliseconds);
715
if (!SceneInfo->inEditor) {
716
RSDK.InitString(&results->rowText[4], buffer, 0);
717
RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[4]);
718
}
719
720
if (session->finishState[p] != FINISHTYPE_GAMEOVER) {
721
results->row0Highlight = session->rings[p] == bestRings;
722
results->row1Highlight = session->totalRings[p] == bestTotalRings;
723
results->row2Highlight = session->score[p] == bestScore;
724
results->row3Highlight = session->items[p] == bestItems;
725
results->row4Highlight = times[p] > 0 && times[p] == bestTime;
726
}
727
}
728
729
if (winnerCount == 1) {
730
int32 winner = -1;
731
for (int32 p = 0; p < session->playerCount; ++p) {
732
if ((1 << p) & session->matchWinner[match]) {
733
winner = p;
734
break;
735
}
736
}
737
738
LogHelpers_Print("Announce_CharWins(%d)", session->playerID[winner]);
739
740
EntityAnnouncer *announcer = CREATE_ENTITY(Announcer, NULL, 0, 0);
741
announcer->state = Announcer_State_AnnounceWinPlayer;
742
announcer->playerID = session->playerID[winner];
743
}
744
else {
745
LogHelpers_Print("Announce_ItsADraw(%d)", 0);
746
747
EntityAnnouncer *announcer = CREATE_ENTITY(Announcer, NULL, 0, 0);
748
announcer->state = Announcer_State_AnnounceDraw;
749
announcer->playerID = 0;
750
announcer->timer = 0;
751
}
752
}
753
754
void CompetitionMenu_GotoCompetition(void) { UIControl_MatchMenuTag(API.CheckDLC(DLC_PLUS) ? "Competition" : "Competition Legacy"); }
755
756
void CompetitionMenu_Results_ProcessInputCB(void)
757
{
758
EntityCompetitionSession *session = CompetitionSession_GetSession();
759
if (UIControl->anyConfirmPress) {
760
int32 mostWins = 0;
761
for (int32 p = 0; p < session->playerCount; ++p) {
762
if (session->wins[p] > mostWins)
763
mostWins = session->wins[p];
764
}
765
766
int32 winnerCount = 0;
767
for (int32 p = 0; p < session->playerCount; ++p) {
768
if (session->wins[p] == mostWins)
769
winnerCount++;
770
}
771
772
if (winnerCount > 1 && session->playerCount == 2) {
773
MenuSetup_StartTransition(CompetitionMenu_GotoPuyoVS, 32);
774
}
775
else {
776
Competition_ResetOptions();
777
UITransition_StartTransition(CompetitionMenu_GotoCompetition, 0);
778
}
779
780
RSDK.PlaySfx(UIWidgets->sfxAccept, false, 255);
781
UIControl->inputLocked = true;
782
}
783
}
784
785
void CompetitionMenu_Results_MenuSetupCB(void)
786
{
787
EntityUIControl *totalControl = CompetitionMenu->compTotalControl;
788
EntityCompetitionSession *session = CompetitionSession_GetSession();
789
790
CompetitionMenu_SetupResultsUI(totalControl);
791
CompetitionMenu->timer = 120;
792
793
totalControl->targetPos.y = totalControl->startPos.y;
794
totalControl->position.y = totalControl->startPos.y;
795
796
String message;
797
INIT_STRING(message);
798
799
EntityUIInfoLabel *label = CompetitionMenu->resultsLabel_Total;
800
Localization_GetString(&message, STR_COMPTOTAL);
801
UIInfoLabel_SetString(label, &message);
802
803
int32 highestScore = 0;
804
for (int32 p = 0; p < session->playerCount; ++p) {
805
if (session->wins[p] > highestScore)
806
highestScore = session->wins[p];
807
}
808
809
int32 winnerCount = 0;
810
int32 winnerID = -1;
811
for (int32 p = 0; p < session->playerCount; ++p) {
812
if (session->wins[p] == highestScore) {
813
winnerID = p;
814
++winnerCount;
815
}
816
}
817
818
if (winnerCount >= 2) {
819
LogHelpers_Print("Announce_ItsADraw(%d)", 1);
820
821
EntityAnnouncer *announcer = CREATE_ENTITY(Announcer, NULL, 0, 0);
822
announcer->state = Announcer_State_AnnounceDraw;
823
announcer->playerID = 1;
824
announcer->timer = 0;
825
}
826
else {
827
LogHelpers_Print("Announce_WinnerIs(%d)", winnerID);
828
829
EntityAnnouncer *announcer = CREATE_ENTITY(Announcer, NULL, 0, 0);
830
announcer->state = Announcer_State_AnnounceWinner;
831
announcer->playerID = winnerID;
832
}
833
834
for (int32 p = 0; p < session->playerCount; ++p) {
835
EntityUIVsResults *results = (EntityUIVsResults *)totalControl->buttons[p];
836
bool32 *highlight = &results->row0Highlight;
837
838
results->numRows = session->matchCount;
839
results->isWinner = session->wins[p] == highestScore;
840
results->trophyCount = session->wins[p];
841
842
for (int32 r = 0; r < results->numRows; ++r) {
843
char buffer[0x40];
844
sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->matchWinner[r]);
845
846
if (!SceneInfo->inEditor) {
847
RSDK.InitString(&results->rowText[r], buffer, 0);
848
RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[r]);
849
}
850
851
highlight[r] = ((1 << p) & session->matchWinner[r]);
852
}
853
}
854
}
855
856
void CompetitionMenu_Results_MenuUpdateCB(void)
857
{
858
EntityUIControl *totalControl = CompetitionMenu->compTotalControl;
859
860
if (totalControl->active == ACTIVE_ALWAYS) {
861
if (totalControl->position.y == totalControl->targetPos.y) {
862
if (CompetitionMenu->timer <= 0) {
863
int32 targetPos = totalControl->startPos.y;
864
if (totalControl->targetPos.y == totalControl->startPos.y) {
865
EntityUIVsResults *button = (EntityUIVsResults *)totalControl->buttons[0];
866
867
if (button && button->size.y + button->position.y - 0x708000 > totalControl->startPos.y) {
868
targetPos = button->size.y + button->position.y - 0x708000;
869
}
870
}
871
872
totalControl->targetPos.y = targetPos;
873
CompetitionMenu->timer = 120;
874
}
875
else {
876
CompetitionMenu->timer--;
877
}
878
}
879
}
880
}
881
882
void CompetitionMenu_ExitComp_TransitionCB(void)
883
{
884
EntityUIControl *zoneControl = CompetitionMenu->compZoneControl;
885
EntityUIControl *control = CompetitionMenu->competitionControl;
886
if (!API.CheckDLC(DLC_PLUS))
887
control = CompetitionMenu->competitionControl_Legacy;
888
889
UIControl_SetInactiveMenu(zoneControl);
890
UIControl_SetActiveMenu(control);
891
Competition_ResetOptions();
892
893
zoneControl->childHasFocus = false;
894
895
CompetitionMenu_HandleUnlocks();
896
}
897
898
void CompetitionMenu_ExitComp_YesCB(void) { UITransition_StartTransition(CompetitionMenu_ExitComp_TransitionCB, 0); }
899
900
bool32 CompetitionMenu_CompRules_BackPressCB(void)
901
{
902
if (API.CheckDLC(DLC_PLUS))
903
UITransition_SetNewTag("Competition");
904
else
905
UITransition_SetNewTag("Competition Legacy");
906
907
return true;
908
}
909
910
bool32 CompetitionMenu_CompZones_BackPressCB(void)
911
{
912
String message;
913
INIT_STRING(message);
914
915
Localization_GetString(&message, STR_EXITCOMP);
916
UIDialog_CreateDialogYesNo(&message, CompetitionMenu_ExitComp_YesCB, StateMachine_None, true, true);
917
return true;
918
}
919
920
void CompetitionMenu_GotoPuyoVS(void)
921
{
922
EntityMenuParam *param = MenuParam_GetParam();
923
924
TimeAttackData_Clear();
925
926
param->puyoSelection = PUYO_SELECTION_TIE_BREAKER;
927
globals->gameMode = MODE_COMPETITION;
928
strcpy(param->menuTag, "Competition Total");
929
param->menuSelection = 0;
930
931
RSDK.SetScene("Extras", "Puyo Puyo");
932
RSDK.LoadScene();
933
}
934
935
#if GAME_INCLUDE_EDITOR
936
void CompetitionMenu_EditorDraw(void) {}
937
938
void CompetitionMenu_EditorLoad(void) {}
939
#endif
940
941
void CompetitionMenu_Serialize(void) {}
942
#endif
943
944