Path: blob/master/SonicMania/Objects/Menu/CompetitionMenu.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: CompetitionMenu Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89#if MANIA_USE_PLUS10ObjectCompetitionMenu *CompetitionMenu;1112void CompetitionMenu_Update(void) {}1314void CompetitionMenu_LateUpdate(void) {}1516void CompetitionMenu_StaticUpdate(void) { CompetitionMenu_HandleStartCompPrompt(); }1718void CompetitionMenu_Draw(void) {}1920void CompetitionMenu_Create(void *data) {}2122void CompetitionMenu_StageLoad(void) { CompetitionMenu->timer = 120; }2324void CompetitionMenu_Initialize(void)25{26String tag;27INIT_STRING(tag);2829foreach_all(UIControl, control)30{31RSDK.SetString(&tag, "Competition");32if (RSDK.CompareStrings(&tag, &control->tag, false))33CompetitionMenu->competitionControl = control;3435RSDK.SetString(&tag, "Competition Legacy");36if (RSDK.CompareStrings(&tag, &control->tag, false))37CompetitionMenu->competitionControl_Legacy = control;3839RSDK.SetString(&tag, "Competition Rules");40if (RSDK.CompareStrings(&tag, &control->tag, false)) {41CompetitionMenu->compRulesControl = control;42control->backPressCB = CompetitionMenu_CompRules_BackPressCB;43}4445RSDK.SetString(&tag, "Competition Zones");46if (RSDK.CompareStrings(&tag, &control->tag, false)) {47CompetitionMenu->compZoneControl = control;48control->backPressCB = CompetitionMenu_CompZones_BackPressCB;49}5051RSDK.SetString(&tag, "Competition Round");52if (RSDK.CompareStrings(&tag, &control->tag, false))53CompetitionMenu->compRoundControl = control;5455RSDK.SetString(&tag, "Competition Total");56if (RSDK.CompareStrings(&tag, &control->tag, false))57CompetitionMenu->compTotalControl = control;58}5960foreach_all(UIInfoLabel, label)61{62EntityUIControl *roundControl = CompetitionMenu->compRoundControl;63EntityUIControl *totalControl = CompetitionMenu->compTotalControl;6465if (UIControl_ContainsPos(roundControl, &label->position))66CompetitionMenu->resultsLabel_Round = label;6768if (UIControl_ContainsPos(totalControl, &label->position))69CompetitionMenu->resultsLabel_Total = label;70}7172foreach_all(UIButtonPrompt, prompt)73{74EntityUIControl *compControl = CompetitionMenu->competitionControl;75EntityUIControl *compControl_Legacy = CompetitionMenu->competitionControl_Legacy;7677if (UIControl_ContainsPos(compControl, &prompt->position) && prompt->buttonID == 5)78CompetitionMenu->startCompPrompt = prompt;7980if (UIControl_ContainsPos(compControl_Legacy, &prompt->position) && prompt->buttonID == 5)81CompetitionMenu->startCompPrompt_Legacy = prompt;82}83}8485void CompetitionMenu_SetupActions(void)86{87EntityUIControl *compControl = CompetitionMenu->competitionControl;88EntityUIControl *compControl_Legacy = CompetitionMenu->competitionControl_Legacy;89EntityUIControl *rulesControl = CompetitionMenu->compRulesControl;90EntityUIControl *roundControl = CompetitionMenu->compRoundControl;91EntityUIControl *totalControl = CompetitionMenu->compTotalControl;9293foreach_all(UIButton, button)94{95if (UIControl_ContainsPos(rulesControl, &button->position) && button->listID == 9 && button->frameID == 2)96button->actionCB = CompetitionMenu_RulesButton_ActionCB;97}9899compControl->processButtonInputCB = CompetitionMenu_VS_ProcessInputCB;100compControl->menuSetupCB = CompetitionMenu_VS_MenuSetupCB;101if (compControl->active == ACTIVE_ALWAYS)102CompetitionMenu_VS_MenuSetupCB();103104compControl_Legacy->processButtonInputCB = CompetitionMenu_VS_ProcessInputCB;105compControl_Legacy->menuSetupCB = CompetitionMenu_VS_MenuSetupCB;106if (compControl_Legacy->active == ACTIVE_ALWAYS)107CompetitionMenu_VS_MenuSetupCB();108109rulesControl->menuSetupCB = CompetitionMenu_Rules_MenuSetupCB;110if (rulesControl->active == ACTIVE_ALWAYS)111CompetitionMenu_Rules_MenuSetupCB();112113roundControl->processButtonInputCB = CompetitionMenu_Round_ProcessInputCB;114roundControl->menuSetupCB = CompetitionMenu_Round_MenuSetupCB;115if (roundControl->active == ACTIVE_ALWAYS)116CompetitionMenu_Round_MenuSetupCB();117118totalControl->processButtonInputCB = CompetitionMenu_Results_ProcessInputCB;119totalControl->menuSetupCB = CompetitionMenu_Results_MenuSetupCB;120totalControl->menuUpdateCB = CompetitionMenu_Results_MenuUpdateCB;121totalControl->targetPos.y = totalControl->startPos.y;122totalControl->position.y = totalControl->startPos.y;123if (totalControl->active == ACTIVE_ALWAYS)124CompetitionMenu_Results_MenuSetupCB();125126foreach_all(UIVsZoneButton, zoneButton) { zoneButton->actionCB = CompetitionMenu_ZoneButtonActionCB; }127}128129void CompetitionMenu_HandleMenuReturn(void)130{131EntityCompetitionSession *session = CompetitionSession_GetSession();132133if (session->inMatch) {134foreach_all(UIControl, control)135{136EntityUIControl *compControl = CompetitionMenu->competitionControl;137if (!API.CheckDLC(DLC_PLUS))138compControl = CompetitionMenu->competitionControl_Legacy;139140if (control == compControl) {141foreach_all(UIVsCharSelector, selector)142{143switch (session->playerID[selector->playerID]) {144case ID_SONIC: selector->frameID = 0; break;145case ID_TAILS: selector->frameID = 1; break;146case ID_KNUCKLES: selector->frameID = 2; break;147case ID_MIGHTY: selector->frameID = 3; break;148case ID_RAY: selector->frameID = 4; break;149default: break;150}151}152}153154if (control == CompetitionMenu->compRulesControl) {155switch (session->itemMode) {156case ITEMS_FIXED: UIButton_SetChoiceSelection(control->buttons[0], 0); break;157case ITEMS_RANDOM: UIButton_SetChoiceSelection(control->buttons[0], 2); break;158case ITEMS_TELEPORT: UIButton_SetChoiceSelection(control->buttons[0], 1); break;159}160161EntityUIVsRoundPicker *picker = (EntityUIVsRoundPicker *)UIButton_GetChoicePtr(control->buttons[1], control->buttons[1]->selection);162if (picker)163picker->val = session->matchCount;164165UIButton_SetChoiceSelectionWithCB(control->buttons[2], session->screenBorderType[2]);166CompetitionMenu_SetupSplitScreenChoices(session->playerCount);167}168169if (control == CompetitionMenu->compZoneControl) {170for (int32 i = 0; i < 12; ++i) {171EntityUIVsZoneButton *button = (EntityUIVsZoneButton *)control->buttons[i];172if (button && session->completedStages[i])173button->xOut = true;174}175}176}177}178}179180int32 CompetitionMenu_HandleUnlocks(void)181{182int32 maxRounds = 0;183184foreach_all(UIVsZoneButton, zoneButton)185{186zoneButton->xOut = !GameProgress_GetZoneUnlocked(zoneButton->zoneID);187zoneButton->obfuscate = zoneButton->xOut;188189if (!zoneButton->xOut)190++maxRounds;191}192193return maxRounds;194}195196void CompetitionMenu_HandleStartCompPrompt(void)197{198int32 readyCount = CompetitionMenu_GetReadyPlayerCount();199int32 activeCount = CompetitionMenu_GetTotalPlayerCount();200201EntityUIButtonPrompt *startComp = CompetitionMenu->startCompPrompt;202if (startComp)203startComp->visible = readyCount > 1 && readyCount == activeCount;204205EntityUIButtonPrompt *startCompLegacy = CompetitionMenu->startCompPrompt_Legacy;206if (startCompLegacy)207startCompLegacy->visible = readyCount > 1 && readyCount == activeCount;208}209210int32 CompetitionMenu_GetReadyPlayerCount(void)211{212EntityUIControl *control = CompetitionMenu->competitionControl;213if (!API.CheckDLC(DLC_PLUS))214control = CompetitionMenu->competitionControl_Legacy;215216if (!control)217return 0;218219int32 readyPlayers = 0;220for (int32 i = 0; i < control->buttonCount; ++i) {221EntityUIVsCharSelector *button = (EntityUIVsCharSelector *)control->buttons[i];222if (button->ready && !button->isSelected)223++readyPlayers;224}225226return readyPlayers;227}228229int32 CompetitionMenu_GetTotalPlayerCount(void)230{231EntityUIControl *control = CompetitionMenu->competitionControl;232if (!API.CheckDLC(DLC_PLUS))233control = CompetitionMenu->competitionControl_Legacy;234235if (!control)236return 0;237238int32 activePlayers = 0;239for (int32 i = 0; i < control->buttonCount; ++i) {240EntityUIVsCharSelector *button = (EntityUIVsCharSelector *)control->buttons[i];241if (button->ready || button->isSelected)242++activePlayers;243}244245return activePlayers;246}247248void CompetitionMenu_ResetControllerAssignments(void)249{250EntityUIVsCharSelector *buttons[PLAYER_COUNT];251EntityUIControl *control = CompetitionMenu->competitionControl;252253int32 playerID = 0;254for (int32 p = 0; p < PLAYER_COUNT; ++p) buttons[p] = (EntityUIVsCharSelector *)control->buttons[p];255256for (int32 p = 0; p < PLAYER_COUNT; ++p) {257EntityUIVsCharSelector *selector = buttons[p];258int32 id = API_GetInputDeviceID(p + 1);259260if (id && id != INPUT_AUTOASSIGN) {261if (playerID < p)262API_AssignInputSlotToDevice(p, INPUT_NONE);263264API_AssignInputSlotToDevice(CONT_P1 + playerID, id);265266buttons[playerID]->frameID = selector->frameID;267if (playerID < p)268selector->frameID = selector->playerID;269270++playerID;271}272}273274for (; playerID < PLAYER_COUNT; ++playerID) API_AssignInputSlotToDevice(CONT_P1 + playerID, INPUT_NONE);275}276277void CompetitionMenu_SetupSplitScreenChoices(int32 playerCount)278{279EntityUIButton *screenLayoutChoice = CompetitionMenu->compRulesControl->buttons[2];280281bool32 choices[5];282283choices[0] = playerCount == 2;284choices[1] = playerCount == 2;285286choices[2] = playerCount == 3;287choices[3] = playerCount == 3;288289choices[4] = playerCount == 4;290291for (int32 c = 0; c < screenLayoutChoice->choiceCount; ++c) {292EntityUIChoice *choice = (EntityUIChoice *)UIButton_GetChoicePtr(screenLayoutChoice, c);293294if (choice)295choice->disabled = !choices[c];296}297298EntityUIChoice *choice = (EntityUIChoice *)UIButton_GetChoicePtr(screenLayoutChoice, screenLayoutChoice->selection);299if (choice->disabled) {300if (playerCount == 2)301UIButton_SetChoiceSelectionWithCB(screenLayoutChoice, 0);302else if (playerCount == 3)303UIButton_SetChoiceSelectionWithCB(screenLayoutChoice, 2);304else305UIButton_SetChoiceSelectionWithCB(screenLayoutChoice, 4);306307UIButton_ManageChoices(screenLayoutChoice);308}309}310void CompetitionMenu_SetupSplitScreen(int32 mode)311{312EntityCompetitionSession *session = CompetitionSession_GetSession();313int32 startVert_3P[15];314uint8 startVert_2P[10];315316memset(startVert_2P, 0, sizeof(startVert_2P));317memset(startVert_3P, 0, sizeof(startVert_3P));318319startVert_2P[(0 * 5) + 0] = 18;320startVert_2P[(0 * 5) + 1] = 6;321startVert_2P[(0 * 5) + 2] = 0;322startVert_2P[(0 * 5) + 3] = 0;323startVert_2P[(0 * 5) + 4] = 0;324325startVert_2P[(1 * 5) + 0] = 24;326startVert_2P[(1 * 5) + 1] = 12;327startVert_2P[(1 * 5) + 2] = 0;328startVert_2P[(1 * 5) + 3] = 0;329startVert_2P[(1 * 5) + 4] = 0;330331startVert_3P[(0 * 5) + 0] = 0;332startVert_3P[(0 * 5) + 1] = 0;333startVert_3P[(0 * 5) + 2] = 30;334startVert_3P[(0 * 5) + 3] = 6;335startVert_3P[(0 * 5) + 4] = 0;336337startVert_3P[(1 * 5) + 0] = 0;338startVert_3P[(1 * 5) + 1] = 0;339startVert_3P[(1 * 5) + 2] = 36;340startVert_3P[(1 * 5) + 3] = 42;341startVert_3P[(1 * 5) + 4] = 0;342343startVert_3P[(2 * 5) + 0] = 0;344startVert_3P[(2 * 5) + 1] = 0;345startVert_3P[(2 * 5) + 2] = 12;346startVert_3P[(2 * 5) + 3] = 48;347startVert_3P[(2 * 5) + 4] = 0;348349RSDK.SetScreenVertices(startVert_2P[mode], startVert_2P[5 + mode], startVert_3P[mode], startVert_3P[5 + mode], startVert_3P[10 + mode]);350351switch (mode) {352case 0: // 2P (Streched)353case 1: // 2P (Bordered)354session->screenBorderType[0] = VS_BORDER_BOTTOM;355session->screenBorderType[1] = VS_BORDER_TOP;356break;357358case 2: // 3P (P1 & P2 top, P3 bottom)359session->screenBorderType[0] = VS_BORDER_BOTTOMRIGHT;360session->screenBorderType[1] = VS_BORDER_BOTTOMLEFT;361session->screenBorderType[2] = VS_BORDER_TOP;362break;363364case 3: // 3P (P1 top, P2 & P3 bottom)365session->screenBorderType[0] = VS_BORDER_BOTTOM;366session->screenBorderType[1] = VS_BORDER_TOPRIGHT;367session->screenBorderType[2] = VS_BORDER_TOPLEFT;368break;369370case 4: // 4P371session->screenBorderType[0] = VS_BORDER_BOTTOMRIGHT;372session->screenBorderType[1] = VS_BORDER_BOTTOMLEFT;373session->screenBorderType[2] = VS_BORDER_TOPRIGHT;374session->screenBorderType[3] = VS_BORDER_TOPLEFT;375break;376377default: break;378}379}380381void CompetitionMenu_SetupResultsUI(EntityUIControl *roundControl)382{383EntityCompetitionSession *session = CompetitionSession_GetSession();384385int32 offsets[] = { -580000, 0x580000, 0x0, 0x0, -0x7A0000, 0x000000, 0x7A0000, 0x000000, -0x9C0000, -0x340000, 0x340000, 0x9C0000 };386387int32 offsetPtr = 4 * (session->playerCount - 2);388for (int32 p = 0; p < PLAYER_COUNT; ++p) {389EntityUIButton *button = roundControl->buttons[p];390if (session->playerCount <= p) {391button->visible = false;392}393else {394button->visible = true;395button->position.x = roundControl->position.x + offsets[offsetPtr + p];396}397}398}399400void CompetitionMenu_GotoCompRules(void)401{402CompetitionMenu_SetupSplitScreenChoices(CompetitionMenu_GetTotalPlayerCount());403UIControl_MatchMenuTag("Competition Rules");404}405406void CompetitionMenu_GotoCompZones(void) { UIControl_MatchMenuTag("Competition Zones"); }407408void CompetitionMenu_VS_ProcessInputCB(void)409{410EntityUIControl *control = CompetitionMenu->competitionControl;411if (!API.CheckDLC(DLC_PLUS))412control = CompetitionMenu->competitionControl_Legacy;413414if (control) {415for (int32 i = 0; i < control->buttonCount; ++i) {416EntityUIVsCharSelector *charSel = (EntityUIVsCharSelector *)control->buttons[i];417418Entity *entStore = SceneInfo->entity;419SceneInfo->entity = (Entity *)charSel;420StateMachine_Run(charSel->processButtonCB);421SceneInfo->entity = entStore;422423API_GetInputDeviceID(charSel->playerID + 1);424}425426EntityUIButtonPrompt *goPrompt = NULL;427for (int32 i = 0; i < control->promptCount; ++i) {428EntityUIButtonPrompt *prompt = control->prompts[i];429430if (prompt->buttonID == 4)431goPrompt = prompt;432}433434int32 readyPlayers = CompetitionMenu_GetReadyPlayerCount();435if (readyPlayers > 1 && readyPlayers == CompetitionMenu_GetTotalPlayerCount()) {436if (UIControl->startPress[0] || UIControl->startPress[1] || UIControl->startPress[2] || UIControl->startPress[3]) {437control->selectionDisabled = true;438UITransition_StartTransition(CompetitionMenu_GotoCompRules, 0);439}440441goPrompt->visible = true;442}443else {444goPrompt->visible = false;445}446}447}448449void CompetitionMenu_VS_MenuSetupCB(void)450{451RSDK_THIS(UIControl);452453self->childHasFocus = false;454for (int32 i = 0; i < self->buttonCount; ++i) {455EntityUIVsCharSelector *charSel = (EntityUIVsCharSelector *)self->buttons[i];456457charSel->isSelected = true;458charSel->ready = false;459charSel->processButtonCB = UIVsCharSelector_ProcessButtonCB;460461if (!API_GetInputDeviceID(CONT_P1 + charSel->playerID))462API_AssignInputSlotToDevice(CONT_P1 + charSel->playerID, INPUT_AUTOASSIGN);463}464465for (int32 i = 0; i < self->promptCount; ++i) {466EntityUIButtonPrompt *prompt = self->prompts[i];467468if (prompt->buttonID == 4)469prompt->visible = false;470}471}472473void CompetitionMenu_Rules_MenuSetupCB(void)474{475if (API.CheckDLC(DLC_PLUS))476CompetitionMenu_ResetControllerAssignments();477}478479void CompetitionMenu_StartMatch(void)480{481EntityCompetitionSession *session = CompetitionSession_GetSession();482EntityMenuParam *param = MenuParam_GetParam();483484sprintf_s(param->menuTag, (int32)sizeof(param->menuTag), "Competition Round");485session->stageIndex = CompetitionMenu->compZoneControl->buttonID;486session->zoneID = param->vsZoneID;487session->actID = param->vsActID;488session->prevMatchID = session->matchID;489490for (int32 p = 0; p < session->playerCount; ++p) {491if (!session->lives[p])492session->lives[p] = 1;493}494495if (globals->gameMode == MODE_ENCORE)496RSDK.SetScene("Encore Mode", "");497else498RSDK.SetScene("Mania Mode", "");499SceneInfo->listPos += TimeAttackData_GetManiaListPos(param->vsZoneID, param->vsActID, CHAR_SONIC);500501SaveGame_ResetPlayerState();502503// Bug Details(?):504// sizeof(globals->noSaveSlot) and sizeof(saveData) is 4096 (sizeof(int32) * 0x400)505// but the memset size is only 1024 (sizeof(uint8) * 0x400)506// so only about 1/4th of the save slot is cleared, though nothin uses the extra space so it's not a big deal507memset(globals->noSaveSlot, 0, 0x400);508509globals->continues = 0;510globals->saveSlotID = NO_SAVE_SLOT;511globals->gameMode = MODE_COMPETITION;512globals->medalMods = 0;513514globals->playerID = ID_NONE;515for (int32 p = 0; p < session->playerCount; ++p) globals->playerID |= session->playerID[p] << (8 * p);516517globals->itemMode = session->itemMode;518519RSDK.LoadScene();520}521522void CompetitionMenu_ZoneButtonActionCB(void) { MenuSetup_StartTransition(CompetitionMenu_StartMatch, 32); }523524void CompetitionMenu_RulesButton_ActionCB(void)525{526EntityUIControl *control = CompetitionMenu->competitionControl;527if (!API.CheckDLC(DLC_PLUS))528control = CompetitionMenu->competitionControl_Legacy;529530EntityUIControl *rulesControl = CompetitionMenu->compRulesControl;531EntityCompetitionSession *session = CompetitionSession_GetSession();532533int32 matchCount = 0;534foreach_all(UIVsRoundPicker, picker)535{536matchCount = picker->val;537foreach_break;538}539540int32 itemMode = ITEMS_FIXED;541switch (rulesControl->buttons[0]->selection) {542default: break;543case 0: itemMode = ITEMS_FIXED; break;544case 1: itemMode = ITEMS_TELEPORT; break;545case 2: itemMode = ITEMS_RANDOM; break;546}547548Competition_ResetOptions();549550session->matchCount = matchCount;551session->inMatch = true;552session->itemMode = itemMode;553554CompetitionMenu_SetupSplitScreen(rulesControl->buttons[2]->selection);555session->displayMode = rulesControl->buttons[2]->selection;556557session->playerCount = 0;558for (int32 i = 0; i < control->buttonCount; ++i) {559EntityUIVsCharSelector *charSel = (EntityUIVsCharSelector *)control->buttons[i];560int32 id = API_GetInputDeviceID(CONT_P1 + i);561if (id && id != INPUT_UNASSIGNED) {562switch (charSel->frameID) {563case 0: session->playerID[i] = ID_SONIC; break;564case 1: session->playerID[i] = ID_TAILS; break;565case 2: session->playerID[i] = ID_KNUCKLES; break;566#if MANIA_USE_PLUS567case 3: session->playerID[i] = ID_MIGHTY; break;568case 4: session->playerID[i] = ID_RAY; break;569#endif570default: break;571}572573session->inputSlots[i] = id;574session->playerCount++;575}576}577578EntityUIControl *zoneControl = CompetitionMenu->compZoneControl;579zoneControl->position = zoneControl->startPos;580zoneControl->targetPos.x = zoneControl->startPos.x;581zoneControl->targetPos.y = zoneControl->startPos.y;582zoneControl->buttonID = 0;583584CompetitionMenu_HandleUnlocks();585586UIControl_MatchMenuTag("Competition Zones");587}588589void CompetitionMenu_GotoCompTotal(void) { UIControl_MatchMenuTag("Competition Total"); }590591void CompetitionMenu_Round_ProcessInputCB(void)592{593EntityCompetitionSession *session = CompetitionSession_GetSession();594if (UIControl->anyConfirmPress) {595bool32 toCompTotal = false;596597int32 activePlayers = 0;598for (int32 p = 0; p < session->playerCount; ++p) {599if (session->lives[p] > 0)600activePlayers++;601602if (session->wins[p] > (session->matchCount >> 1))603toCompTotal = true;604}605606EntityUIControl *zoneControl = CompetitionMenu->compZoneControl;607int32 remainingZones = 0;608for (int32 i = 0; i < 12; ++i) {609if (zoneControl->buttons[i]) {610EntityUIVsZoneButton *zoneButton = (EntityUIVsZoneButton *)zoneControl->buttons[i];611if (!session->completedStages[i] && GameProgress_GetZoneUnlocked(zoneButton->zoneID))612++remainingZones;613}614}615616if (toCompTotal || activePlayers < 2 || session->matchID >= session->matchCount || !remainingZones)617UITransition_StartTransition(CompetitionMenu_GotoCompTotal, 0);618else619UITransition_StartTransition(CompetitionMenu_GotoCompZones, 0);620621RSDK.PlaySfx(UIWidgets->sfxAccept, false, 255);622UIControl->inputLocked = true;623}624}625626void CompetitionMenu_Round_MenuSetupCB(void)627{628EntityCompetitionSession *session = CompetitionSession_GetSession();629EntityUIControl *roundControl = CompetitionMenu->compRoundControl;630CompetitionMenu_SetupResultsUI(roundControl);631632String roundLabelStr;633INIT_STRING(roundLabelStr);634635char roundLabel[0x100];636memset(roundLabel, 0, sizeof(roundLabel));637638Localization_GetZoneName(&roundLabelStr, session->zoneID);639if (session->zoneID < 12) {640char buf[16];641sprintf_s(buf, (int32)sizeof(buf), " ZONE %d", session->actID + 1);642RSDK.AppendText(&roundLabelStr, buf);643}644645RSDK.GetCString(roundLabel, &roundLabelStr);646UIInfoLabel_SetText(CompetitionMenu->resultsLabel_Round, roundLabel);647648int32 bestRings = 0;649int32 bestTotalRings = 0;650int32 bestScore = 0;651int32 bestItems = 0;652uint32 bestTime = 0xFFFFFFFF;653uint32 times[PLAYER_COUNT];654655for (int32 p = 0; p < session->playerCount; ++p) {656if (session->rings[p] > bestRings)657bestRings = session->rings[p];658659if (session->totalRings[p] > bestTotalRings)660bestTotalRings = session->totalRings[p];661662if (session->score[p] > bestScore)663bestScore = session->score[p];664665if (session->items[p] > bestItems)666bestItems = session->items[p];667668times[p] = session->time[p].milliseconds + 100 * (session->time[p].seconds + 4 * (16 * session->time[p].minutes - session->time[p].minutes));669if (times[p] < bestTime)670bestTime = times[p];671}672673char buffer[0x40];674int32 winnerCount = 0;675int32 match = session->matchID - 1;676677for (int32 p = 0; p < session->playerCount; ++p) {678EntityUIVsResults *results = (EntityUIVsResults *)roundControl->buttons[p];679680results->isWinner = session->matchWinner[match] & (1 << p);681results->isLoser = session->matchWinner[match] & (1 << p);682683if (session->matchWinner[match] & (1 << p))684winnerCount++;685686results->trophyCount = session->wins[p];687memset(buffer, 0, sizeof(buffer));688689sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->rings[p]);690if (!SceneInfo->inEditor) {691RSDK.InitString(&results->rowText[0], buffer, 0);692RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[0]);693}694695sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->totalRings[p]);696if (!SceneInfo->inEditor) {697RSDK.InitString(&results->rowText[1], buffer, 0);698RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[1]);699}700701sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->score[p]);702if (!SceneInfo->inEditor) {703RSDK.InitString(&results->rowText[2], buffer, 0);704RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[2]);705}706707sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->items[p]);708if (!SceneInfo->inEditor) {709RSDK.InitString(&results->rowText[3], buffer, 0);710RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[3]);711}712713sprintf_s(buffer, (int32)sizeof(buffer), "%d'%02d\"%02d", session->time[p].minutes, session->time[p].seconds, session->time[p].milliseconds);714if (!SceneInfo->inEditor) {715RSDK.InitString(&results->rowText[4], buffer, 0);716RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[4]);717}718719if (session->finishState[p] != FINISHTYPE_GAMEOVER) {720results->row0Highlight = session->rings[p] == bestRings;721results->row1Highlight = session->totalRings[p] == bestTotalRings;722results->row2Highlight = session->score[p] == bestScore;723results->row3Highlight = session->items[p] == bestItems;724results->row4Highlight = times[p] > 0 && times[p] == bestTime;725}726}727728if (winnerCount == 1) {729int32 winner = -1;730for (int32 p = 0; p < session->playerCount; ++p) {731if ((1 << p) & session->matchWinner[match]) {732winner = p;733break;734}735}736737LogHelpers_Print("Announce_CharWins(%d)", session->playerID[winner]);738739EntityAnnouncer *announcer = CREATE_ENTITY(Announcer, NULL, 0, 0);740announcer->state = Announcer_State_AnnounceWinPlayer;741announcer->playerID = session->playerID[winner];742}743else {744LogHelpers_Print("Announce_ItsADraw(%d)", 0);745746EntityAnnouncer *announcer = CREATE_ENTITY(Announcer, NULL, 0, 0);747announcer->state = Announcer_State_AnnounceDraw;748announcer->playerID = 0;749announcer->timer = 0;750}751}752753void CompetitionMenu_GotoCompetition(void) { UIControl_MatchMenuTag(API.CheckDLC(DLC_PLUS) ? "Competition" : "Competition Legacy"); }754755void CompetitionMenu_Results_ProcessInputCB(void)756{757EntityCompetitionSession *session = CompetitionSession_GetSession();758if (UIControl->anyConfirmPress) {759int32 mostWins = 0;760for (int32 p = 0; p < session->playerCount; ++p) {761if (session->wins[p] > mostWins)762mostWins = session->wins[p];763}764765int32 winnerCount = 0;766for (int32 p = 0; p < session->playerCount; ++p) {767if (session->wins[p] == mostWins)768winnerCount++;769}770771if (winnerCount > 1 && session->playerCount == 2) {772MenuSetup_StartTransition(CompetitionMenu_GotoPuyoVS, 32);773}774else {775Competition_ResetOptions();776UITransition_StartTransition(CompetitionMenu_GotoCompetition, 0);777}778779RSDK.PlaySfx(UIWidgets->sfxAccept, false, 255);780UIControl->inputLocked = true;781}782}783784void CompetitionMenu_Results_MenuSetupCB(void)785{786EntityUIControl *totalControl = CompetitionMenu->compTotalControl;787EntityCompetitionSession *session = CompetitionSession_GetSession();788789CompetitionMenu_SetupResultsUI(totalControl);790CompetitionMenu->timer = 120;791792totalControl->targetPos.y = totalControl->startPos.y;793totalControl->position.y = totalControl->startPos.y;794795String message;796INIT_STRING(message);797798EntityUIInfoLabel *label = CompetitionMenu->resultsLabel_Total;799Localization_GetString(&message, STR_COMPTOTAL);800UIInfoLabel_SetString(label, &message);801802int32 highestScore = 0;803for (int32 p = 0; p < session->playerCount; ++p) {804if (session->wins[p] > highestScore)805highestScore = session->wins[p];806}807808int32 winnerCount = 0;809int32 winnerID = -1;810for (int32 p = 0; p < session->playerCount; ++p) {811if (session->wins[p] == highestScore) {812winnerID = p;813++winnerCount;814}815}816817if (winnerCount >= 2) {818LogHelpers_Print("Announce_ItsADraw(%d)", 1);819820EntityAnnouncer *announcer = CREATE_ENTITY(Announcer, NULL, 0, 0);821announcer->state = Announcer_State_AnnounceDraw;822announcer->playerID = 1;823announcer->timer = 0;824}825else {826LogHelpers_Print("Announce_WinnerIs(%d)", winnerID);827828EntityAnnouncer *announcer = CREATE_ENTITY(Announcer, NULL, 0, 0);829announcer->state = Announcer_State_AnnounceWinner;830announcer->playerID = winnerID;831}832833for (int32 p = 0; p < session->playerCount; ++p) {834EntityUIVsResults *results = (EntityUIVsResults *)totalControl->buttons[p];835bool32 *highlight = &results->row0Highlight;836837results->numRows = session->matchCount;838results->isWinner = session->wins[p] == highestScore;839results->trophyCount = session->wins[p];840841for (int32 r = 0; r < results->numRows; ++r) {842char buffer[0x40];843sprintf_s(buffer, (int32)sizeof(buffer), "%d", session->matchWinner[r]);844845if (!SceneInfo->inEditor) {846RSDK.InitString(&results->rowText[r], buffer, 0);847RSDK.SetSpriteString(UIVsResults->aniFrames, 18, &results->rowText[r]);848}849850highlight[r] = ((1 << p) & session->matchWinner[r]);851}852}853}854855void CompetitionMenu_Results_MenuUpdateCB(void)856{857EntityUIControl *totalControl = CompetitionMenu->compTotalControl;858859if (totalControl->active == ACTIVE_ALWAYS) {860if (totalControl->position.y == totalControl->targetPos.y) {861if (CompetitionMenu->timer <= 0) {862int32 targetPos = totalControl->startPos.y;863if (totalControl->targetPos.y == totalControl->startPos.y) {864EntityUIVsResults *button = (EntityUIVsResults *)totalControl->buttons[0];865866if (button && button->size.y + button->position.y - 0x708000 > totalControl->startPos.y) {867targetPos = button->size.y + button->position.y - 0x708000;868}869}870871totalControl->targetPos.y = targetPos;872CompetitionMenu->timer = 120;873}874else {875CompetitionMenu->timer--;876}877}878}879}880881void CompetitionMenu_ExitComp_TransitionCB(void)882{883EntityUIControl *zoneControl = CompetitionMenu->compZoneControl;884EntityUIControl *control = CompetitionMenu->competitionControl;885if (!API.CheckDLC(DLC_PLUS))886control = CompetitionMenu->competitionControl_Legacy;887888UIControl_SetInactiveMenu(zoneControl);889UIControl_SetActiveMenu(control);890Competition_ResetOptions();891892zoneControl->childHasFocus = false;893894CompetitionMenu_HandleUnlocks();895}896897void CompetitionMenu_ExitComp_YesCB(void) { UITransition_StartTransition(CompetitionMenu_ExitComp_TransitionCB, 0); }898899bool32 CompetitionMenu_CompRules_BackPressCB(void)900{901if (API.CheckDLC(DLC_PLUS))902UITransition_SetNewTag("Competition");903else904UITransition_SetNewTag("Competition Legacy");905906return true;907}908909bool32 CompetitionMenu_CompZones_BackPressCB(void)910{911String message;912INIT_STRING(message);913914Localization_GetString(&message, STR_EXITCOMP);915UIDialog_CreateDialogYesNo(&message, CompetitionMenu_ExitComp_YesCB, StateMachine_None, true, true);916return true;917}918919void CompetitionMenu_GotoPuyoVS(void)920{921EntityMenuParam *param = MenuParam_GetParam();922923TimeAttackData_Clear();924925param->puyoSelection = PUYO_SELECTION_TIE_BREAKER;926globals->gameMode = MODE_COMPETITION;927strcpy(param->menuTag, "Competition Total");928param->menuSelection = 0;929930RSDK.SetScene("Extras", "Puyo Puyo");931RSDK.LoadScene();932}933934#if GAME_INCLUDE_EDITOR935void CompetitionMenu_EditorDraw(void) {}936937void CompetitionMenu_EditorLoad(void) {}938#endif939940void CompetitionMenu_Serialize(void) {}941#endif942943944