diff --git a/include/text_strings.h.in b/include/text_strings.h.in index 749179b1..0f28e668 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -40,9 +40,6 @@ #define TEXT_SOUND_SELECT TEXT_JPHUD_SOUND_SELECT #define TEXT_FILE_MARIO_A _("マリオA") -#define TEXT_FILE_MARIO_B _("マリオB") -#define TEXT_FILE_MARIO_C _("マリオC") -#define TEXT_FILE_MARIO_D _("マリオD") // Menu Options #define TEXT_SCORE _("スコア") @@ -68,9 +65,6 @@ #define TEXT_HI_SCORE _("ハイスコア") #define TEXT_MY_SCORE _("マイスコア") #define TEXT_SCORE_MARIO_A _("マリオA") -#define TEXT_SCORE_MARIO_B _("マリオB") -#define TEXT_SCORE_MARIO_C _("マリオC") -#define TEXT_SCORE_MARIO_D _("マリオD") // Copy Menu #define TEXT_COPY_IT_TO_WHERE _("どこにコピーしますか?") @@ -137,9 +131,6 @@ #define TEXT_ERASE_FILE _("ERASE FILE") #define TEXT_SOUND_SELECT _("SOUND SELECT") #define TEXT_FILE_MARIO_A _("MARIO A") -#define TEXT_FILE_MARIO_B _("MARIO B") -#define TEXT_FILE_MARIO_C _("MARIO C") -#define TEXT_FILE_MARIO_D _("MARIO D") // Menu Options #define TEXT_SCORE _("SCORE") @@ -166,9 +157,6 @@ #define TEXT_MY_SCORE _("MY SCORE") // Score Mario Text ("☺" is the Mario face defined in the US/EU menu char table) #define TEXT_SCORE_MARIO_A _("☺A") -#define TEXT_SCORE_MARIO_B _("☺B") -#define TEXT_SCORE_MARIO_C _("☺C") -#define TEXT_SCORE_MARIO_D _("☺D") // Copy Menu #define TEXT_COPY_IT_TO_WHERE _("COPY IT TO WHERE?") diff --git a/src/game/hud.c b/src/game/hud.c index fd66f596..fc6d35ad 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -317,42 +317,47 @@ void render_hud_keys(void) { } } +s32 get_y_pos(u8 hudIdx) { + return 24 * hudIdx; +} + /** - * Renders the timer when Mario start sliding in PSS. + * Displays a timer in the top-right */ -void render_hud_timer(void) { +void render_hud_timer(u16 timeInFrames, u8 timerIdx, const char *prefix, u32 distFromRightEdge) { u8 *(*hudLUT)[58] = segmented_to_virtual(&main_hud_lut); - u16 timerValFrames = gHudDisplay.timer; - u16 timerMins = timerValFrames / (30 * 60); - u16 timerSecs = (timerValFrames - (timerMins * 1800)) / 30; - u16 timerFracSecs = ((timerValFrames - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) / 3; -#ifdef VERSION_EU - switch (eu_get_language()) { - case LANGUAGE_ENGLISH: - print_text(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(150), 185, "TIME"); - break; - case LANGUAGE_FRENCH: - print_text(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(155), 185, "TEMPS"); - break; - case LANGUAGE_GERMAN: - print_text(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(150), 185, "ZEIT"); - break; - } -#else - print_text(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(150), 185, "TIME"); -#endif + struct TimerDisplay time = frames_to_display_time(timeInFrames); + s32 yPos = 184 - get_y_pos(timerIdx); + s32 yPosApostropes = 32 + get_y_pos(timerIdx); - print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(91), 185, "%0d", timerMins); - print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(71), 185, "%02d", timerSecs); - print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(37), 185, "%d", timerFracSecs); + print_text(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(distFromRightEdge), yPos, prefix); + + print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(91), yPos, "%0d", time.mins); + print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(71), yPos, "%02d", time.secs); + print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(37), yPos, "%02d", time.fracSecs); gSPDisplayList(gDisplayListHead++, dl_hud_img_begin); - render_hud_tex_lut(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(81), 32, (*hudLUT)[GLYPH_APOSTROPHE]); - render_hud_tex_lut(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(46), 32, (*hudLUT)[GLYPH_DOUBLE_QUOTE]); + render_hud_tex_lut(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(81), yPosApostropes, + (*hudLUT)[GLYPH_APOSTROPHE]); + render_hud_tex_lut(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(45), yPosApostropes, + (*hudLUT)[GLYPH_DOUBLE_QUOTE]); gSPDisplayList(gDisplayListHead++, dl_hud_img_end); } +/** + * Displays a rank in the top-left + */ +void render_hud_rank(struct RankDisplay rank, u8 timerIdx, u32 distFromLeftEdge, const char *prefix, + u32 prefixLength) { + s32 yPos; + char rankStr[2] = { '\0', '\0' }; + rankStr[0] = rank.asChar; + yPos = 184 - get_y_pos(timerIdx); + print_text(GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(distFromLeftEdge), yPos, prefix); + print_text(GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(distFromLeftEdge + prefixLength), yPos, rankStr); +} + /** * Sets HUD status camera value depending of the actions * defined in update_camera_status. @@ -407,6 +412,7 @@ void render_hud_camera_status(void) { */ void render_hud(void) { s16 hudDisplayFlags = gHudDisplay.flags; + u16 best_time; if (hudDisplayFlags == HUD_DISPLAY_NONE) { sPowerMeterHUD.animation = POWER_METER_HIDDEN; @@ -456,7 +462,41 @@ void render_hud(void) { } if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER) { - render_hud_timer(); + render_hud_timer(gTimer.time, 0, "", 100); + if (gTimer.collectedStarId >= 0) { + best_time = save_file_get_best_time(COURSE_NUM_TO_INDEX(gCurrCourseNum), + gTimer.collectedStarId); + render_hud_timer(best_time, 1, "PB", 120); + render_hud_rank(time_to_rank(gTimer.time, COURSE_NUM_TO_INDEX(gCurrCourseNum), + gTimer.collectedStarId), + 0, 10, "RANK", 60); + render_hud_rank(time_to_rank(best_time, COURSE_NUM_TO_INDEX(gCurrCourseNum), + gTimer.collectedStarId), + 1, 35, "PB", 35); + } + } else if (hudDisplayFlags & HUD_DISPLAY_FLAG_PSS_TIMER) { + char *prefix; + u32 distFromRightEdge; +#ifdef VERSION_EU + switch (eu_get_language()) { + case LANGUAGE_ENGLISH: + str = "TIME"; + distFromRightEdge = 150; + break; + case LANGUAGE_FRENCH: + str = "TEMPS"; + distFromRightEdge = 155; + break; + case LANGUAGE_GERMAN: + str = "ZEIT"; + distFromRightEdge = 150; + break; + } +#else + prefix = "ZEIT"; + distFromRightEdge = 150; +#endif + render_hud_timer(gHudDisplay.timer, 0, prefix, distFromRightEdge); } #ifdef DEBUG diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 5c74037f..b764129d 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -813,25 +813,28 @@ s16 get_string_width(u8 *str) { } #endif -u8 gHudSymCoin[] = { GLYPH_COIN, GLYPH_SPACE }; -u8 gHudSymX[] = { GLYPH_MULTIPLY, GLYPH_SPACE }; +u8 gHudSymApostrophe[] = { GLYPH_APOSTROPHE, GLYPH_SPACE }; +u8 gHudSymDoubleQuote[] = { GLYPH_DOUBLE_QUOTE, GLYPH_SPACE }; +u8 textSOB[] = { 0x1C, 0x18, 0x0B, GLOBAR_CHAR_TERMINATOR }; -void print_hud_my_score_coins(s32 useCourseCoinScore, s8 fileIndex, s8 courseIndex, s16 x, s16 y) { - u8 strNumCoins[4]; - s16 numCoins; +void print_hud_my_sob(s8 courseIndex, s16 x, s16 y) { + struct TimerDisplay time; + u8 strMins[4]; + u8 strSecs[4]; + u8 strFracSecs[4]; + u32 sob; - if (!useCourseCoinScore) { - numCoins = (u16)(save_file_get_max_coin_score(courseIndex) & 0xFFFF); - } else { - numCoins = save_file_get_course_coin_score(fileIndex, courseIndex); - } - - if (numCoins != 0) { - print_hud_lut_string(HUD_LUT_GLOBAL, x, y, gHudSymCoin); - print_hud_lut_string(HUD_LUT_GLOBAL, x + 16, y, gHudSymX); - int_to_str(numCoins, strNumCoins); - print_hud_lut_string(HUD_LUT_GLOBAL, x + 32, y, strNumCoins); - } + sob = save_file_get_course_sob(courseIndex); + time = frames_to_display_time(sob); + print_hud_lut_string(HUD_LUT_GLOBAL, x + 6, y, textSOB); + int_to_str(time.mins, strMins); + print_hud_lut_string(HUD_LUT_GLOBAL, x + 50, y, strMins); + print_hud_lut_string(HUD_LUT_GLOBAL, x + 60, y - 8, gHudSymApostrophe); + int_to_str(time.secs, strSecs); + print_hud_lut_string(HUD_LUT_GLOBAL, x + 70, y, strSecs); + print_hud_lut_string(HUD_LUT_GLOBAL, x + 94, y - 8, gHudSymDoubleQuote); + int_to_str(time.fracSecs, strFracSecs); + print_hud_lut_string(HUD_LUT_GLOBAL, x + 104, y, strFracSecs); } void print_hud_my_score_stars(s8 fileIndex, s8 courseIndex, s16 x, s16 y) { @@ -2211,7 +2214,25 @@ u8 gTextCourse[][7] = { #define MYSCORE_X 62 #endif -void render_pause_my_score_coins(void) { +void render_scores_hud_lut(u8 courseIndex) { + int i; + u8 rankText[2] = { 0xFF, 0xFF }; + print_hud_my_sob(courseIndex, 178, 103); + print_hud_my_score_stars(gCurrSaveFileNum - 1, courseIndex, 118, 103); + for (i = 0; i < 7; i++) { + const s16 x = 30 + i * 40; + const s16 y = 32; + if (save_file_best_time_exists(courseIndex, i)) { + rankText[0] = time_to_rank(save_file_get_best_time(courseIndex, i), courseIndex, i) + .asU8; // TODO use couseIndex or num everywhere + } else { + rankText[0] = RANK_NONE_2; + } + print_hud_lut_string(HUD_LUT_GLOBAL, x, y, rankText); + } +} + +void render_pause_scores(void) { #ifdef VERSION_EU u8 textMyScore[][10] = { { TEXT_MY_SCORE }, @@ -2262,8 +2283,7 @@ void render_pause_my_score_coins(void) { gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); if (courseIndex <= COURSE_NUM_TO_INDEX(COURSE_STAGES_MAX)) { - print_hud_my_score_coins(1, gCurrSaveFileNum - 1, courseIndex, 178, 103); - print_hud_my_score_stars(gCurrSaveFileNum - 1, courseIndex, 118, 103); + render_scores_hud_lut(courseIndex); } gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); @@ -2418,7 +2438,7 @@ void render_pause_course_options(s16 x, s16 y, s8 *index, s16 yIndex) { void render_pause_castle_menu_box(s16 x, s16 y) { create_dl_translation_matrix(MENU_MTX_PUSH, x - 78, y - 32, 0); - create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.2f, 0.8f, 1.0f); + create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.2f, 1.0f, 1.0f); gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 105); gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); @@ -2429,7 +2449,7 @@ void render_pause_castle_menu_box(s16 x, s16 y) { gSPDisplayList(gDisplayListHead++, dl_draw_triangle); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); - create_dl_translation_matrix(MENU_MTX_PUSH, x - 9, y - 101, 0); + create_dl_translation_matrix(MENU_MTX_PUSH, x - 9, y - 118, 0); create_dl_rotation_matrix(MENU_MTX_NOPUSH, 270.0f, 0, 0, 1.0f); gSPDisplayList(gDisplayListHead++, dl_draw_triangle); gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); @@ -2469,46 +2489,47 @@ void print_hud_pause_colorful_str(void) { } void render_pause_castle_course_stars(s16 x, s16 y, s16 fileIndex, s16 courseIndex) { - s16 hasStar = 0; - - u8 str[COURSE_STAGES_COUNT * 2]; - - u8 textStar[] = { TEXT_STAR }; + u16 starIdx = 0; + u8 starStr[COURSE_STAGES_COUNT * 2]; + u8 rankStr[NUM_SCORES_PER_STAGE * 3]; u8 starFlags = save_file_get_star_flags(fileIndex, courseIndex); - u16 starCount = save_file_get_course_star_count(fileIndex, courseIndex); - u16 nextStar = 0; - - if (starFlags & (1 << 6)) { - starCount--; - print_generic_string(x + 89, y - 5, textStar); - } - - while (hasStar != starCount) { - if (starFlags & (1 << nextStar)) { - str[nextStar * 2] = DIALOG_CHAR_STAR_FILLED; - hasStar++; + for (starIdx = 0; starIdx < NUM_SCORES_PER_STAGE; starIdx++) { + if (starFlags & (1 << starIdx)) { + starStr[starIdx * 2] = DIALOG_CHAR_STAR_FILLED; } else { - str[nextStar * 2] = DIALOG_CHAR_STAR_OPEN; + starStr[starIdx * 2] = DIALOG_CHAR_STAR_OPEN; + } + if (save_file_best_time_exists(courseIndex, starIdx)) { + rankStr[starIdx * 3] = + time_to_rank(save_file_get_best_time(courseIndex, starIdx), courseIndex, starIdx).asU8; + } else { + rankStr[starIdx * 3] = RANK_NONE; } - str[nextStar * 2 + 1] = DIALOG_CHAR_SPACE; - nextStar++; + starStr[starIdx * 2 + 1] = DIALOG_CHAR_SPACE; + rankStr[starIdx * 3 + 1] = DIALOG_CHAR_SPACE; + rankStr[starIdx * 3 + 2] = DIALOG_CHAR_SPACE; } - if (starCount == nextStar && starCount != 6) { - str[nextStar * 2] = DIALOG_CHAR_STAR_OPEN; - str[nextStar * 2 + 1] = DIALOG_CHAR_SPACE; - nextStar++; - } + starStr[starIdx * 2] = DIALOG_CHAR_TERMINATOR; + rankStr[starIdx * 3] = DIALOG_CHAR_TERMINATOR; - str[nextStar * 2] = DIALOG_CHAR_TERMINATOR; - - print_generic_string(x + 14, y + 13, str); + print_generic_string(x + 5, y, starStr); + print_generic_string(x + 3, y - 16, rankStr); } +u8 hudDialogApostrophe[] = { 0x3E, 0xFF }; +u8 hudDialogDoubleQuote[] = { 0xF6, 0xFF }; + void render_pause_castle_main_strings(s16 x, s16 y) { + struct TimerDisplay time; + u8 strMins[4]; + u8 strSecs[4]; + u8 strFracSecs[4]; + u32 sob; + #ifdef VERSION_EU void **courseNameTbl; #else @@ -2574,14 +2595,21 @@ void render_pause_castle_main_strings(s16 x, s16 y) { gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); if (gDialogLineNum <= COURSE_NUM_TO_INDEX(COURSE_STAGES_MAX)) { // Main courses + const s16 ySob = y - 25; courseName = segmented_to_virtual(courseNameTbl[gDialogLineNum]); - render_pause_castle_course_stars(x, y, gCurrSaveFileNum - 1, gDialogLineNum); - print_generic_string(x + 34, y - 5, textCoin); -#ifdef VERSION_EU - print_generic_string(x + 44, y - 5, textX); -#endif - int_to_str(save_file_get_course_coin_score(gCurrSaveFileNum - 1, gDialogLineNum), strVal); - print_generic_string(x + 54, y - 5, strVal); + render_pause_castle_course_stars(x, y + 10, gCurrSaveFileNum - 1, gDialogLineNum); + + sob = save_file_get_course_sob(gDialogLineNum); + time = frames_to_display_time(sob); + print_generic_string(x + 20, ySob, textSOB); + int_to_str(time.mins, strMins); + print_generic_string(x + 43, ySob, strMins); + print_generic_string(x + 51, ySob, hudDialogApostrophe); + int_to_str(time.secs, strSecs); + print_generic_string(x + 56, ySob, strSecs); + print_generic_string(x + 71, ySob, hudDialogDoubleQuote); + int_to_str(time.fracSecs, strFracSecs); + print_generic_string(x + 78, ySob, strFracSecs); #ifdef VERSION_EU print_generic_string(x - 17, y + 30, courseName); #endif @@ -2633,7 +2661,7 @@ s16 render_pause_courses_and_castle(void) { case DIALOG_STATE_VERTICAL: shade_screen(); - render_pause_my_score_coins(); + render_pause_scores(); render_pause_red_coins(); if (gMarioStates[0].action & ACT_FLAG_PAUSE_EXIT) { diff --git a/src/game/ingame_menu.h b/src/game/ingame_menu.h index d341855e..d3f71737 100644 --- a/src/game/ingame_menu.h +++ b/src/game/ingame_menu.h @@ -148,7 +148,7 @@ s16 get_str_x_pos_from_center(s16 centerPos, u8 *str, f32 scale); #if defined(VERSION_JP) || defined(VERSION_EU) || defined(VERSION_SH) s16 get_str_x_pos_from_center_scale(s16 centerPos, u8 *str, f32 scale); #endif -void print_hud_my_score_coins(s32 useCourseCoinScore, s8 fileIndex, s8 courseIndex, s16 x, s16 y); +void print_hud_my_sob(s8 courseIndex, s16 x, s16 y); void int_to_str(s32 num, u8 *dst); s16 get_dialog_id(void); void create_dialog_box(s16 dialog); diff --git a/src/game/interaction.c b/src/game/interaction.c index c35d1b3e..1154654e 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -130,6 +130,7 @@ static u32 sBackwardKnockbackActions[][3] = { static u8 sDisplayingDoorText = FALSE; static u8 sJustTeleported = FALSE; static u8 sPssSlideStarted = FALSE; +static u8 timerStarted = FALSE; /** * Returns the type of cap Mario is wearing. @@ -808,6 +809,7 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O m->usedObj = o; starIndex = (o->oBehParams >> 24) & 0x1F; + gTimer.collectedStarId = starIndex; save_file_collect_star_or_key(m->numCoins, starIndex); m->numStars = @@ -1835,7 +1837,7 @@ void check_lava_boost(struct MarioState *m) { } void pss_begin_slide(UNUSED struct MarioState *m) { - if (!(gHudDisplay.flags & HUD_DISPLAY_FLAG_TIMER)) { + if (!(gHudDisplay.flags & HUD_DISPLAY_FLAG_PSS_TIMER)) { level_control_timer(TIMER_CONTROL_SHOW); level_control_timer(TIMER_CONTROL_START); sPssSlideStarted = TRUE; @@ -1854,6 +1856,25 @@ void pss_end_slide(struct MarioState *m) { } } +void begin_timer(UNUSED struct MarioState *m) { + reset_gtimer(); + show_gtimer(); + start_gtimer(); +} + +void end_timer(struct MarioState *m) { + if (sTimerRunning) { + stop_gtimer(); + if (gTimer.collectedStarId >= 0) { + bool isPb = save_file_register_new_time(COURSE_NUM_TO_INDEX(gCurrCourseNum), + gTimer.collectedStarId, gTimer.time); + if (isPb) { + save_file_do_save(gCurrSaveFileNum - 1); + } + } + } +} + void mario_handle_special_floors(struct MarioState *m) { if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_CUTSCENE) { return; diff --git a/src/game/interaction.h b/src/game/interaction.h index 9d063a81..ddeeb22a 100644 --- a/src/game/interaction.h +++ b/src/game/interaction.h @@ -120,5 +120,7 @@ u32 mario_check_object_grab(struct MarioState *m); u32 get_door_save_file_flag(struct Object *door); void mario_process_interactions(struct MarioState *m); void mario_handle_special_floors(struct MarioState *m); +void begin_timer(UNUSED struct MarioState *m); +void end_timer(struct MarioState *m); #endif // INTERACTION_H diff --git a/src/game/level_update.c b/src/game/level_update.c index c5bfee33..e350bc38 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -161,6 +161,9 @@ struct CreditsEntry sCreditsSequence[] = { struct MarioState gMarioStates[1]; struct HudDisplay gHudDisplay; +struct Timer gTimer; +s8 sTimerRunning; + s16 sCurrPlayMode; u16 D_80339ECA; s16 sTransitionTimer; @@ -176,7 +179,7 @@ s32 sDelayedWarpArg; #if defined(VERSION_EU) || defined(VERSION_SH) s16 unusedEULevelUpdateBss1; #endif -s8 sTimerRunning; +s8 sPssTimerRunning; s8 gNeverEnteredCastle; struct MarioState *gMarioState = &gMarioStates[0]; @@ -188,22 +191,22 @@ u8 unused3[2]; u16 level_control_timer(s32 timerOp) { switch (timerOp) { case TIMER_CONTROL_SHOW: - gHudDisplay.flags |= HUD_DISPLAY_FLAG_TIMER; - sTimerRunning = FALSE; + gHudDisplay.flags |= HUD_DISPLAY_FLAG_PSS_TIMER; + sPssTimerRunning = FALSE; gHudDisplay.timer = 0; break; case TIMER_CONTROL_START: - sTimerRunning = TRUE; + sPssTimerRunning = TRUE; break; case TIMER_CONTROL_STOP: - sTimerRunning = FALSE; + sPssTimerRunning = FALSE; break; case TIMER_CONTROL_HIDE: - gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIMER; - sTimerRunning = FALSE; + gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_PSS_TIMER; + sPssTimerRunning = FALSE; gHudDisplay.timer = 0; break; } @@ -211,6 +214,31 @@ u16 level_control_timer(s32 timerOp) { return gHudDisplay.timer; } +void start_gtimer(void) { + sTimerRunning = TRUE; +} + +void stop_gtimer(void) { + sTimerRunning = FALSE; +} + +void show_gtimer(void) { + gHudDisplay.flags |= HUD_DISPLAY_FLAG_TIMER; +} + +void hide_gtimer(void) { + gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIMER; +} + +void reset_gtimer(void) { + gTimer.time = 0; + gTimer.collectedStarId = -1; +} + +u16 get_timer_val(void) { + return gHudDisplay.timer; +} + u32 pressed_pause(void) { u32 dialogActive = get_dialog_id() >= 0; u32 intangible = (gMarioState->action & ACT_FLAG_INTANGIBLE) != 0; @@ -1019,9 +1047,12 @@ s32 play_mode_normal(void) { warp_area(); check_instant_warp(); - if (sTimerRunning && gHudDisplay.timer < 17999) { + if (sPssTimerRunning && gHudDisplay.timer < 17999) { gHudDisplay.timer++; } + if (sTimerRunning && gTimer.time < 17999) { + gTimer.time++; + } area_update_objects(); update_hud_values(); @@ -1214,7 +1245,7 @@ s32 init_level(void) { gHudDisplay.flags = HUD_DISPLAY_NONE; } - sTimerRunning = FALSE; + sPssTimerRunning = FALSE; if (sWarpDest.type != WARP_TYPE_NOT_WARPING) { if (sWarpDest.nodeId >= WARP_NODE_CREDITS_MIN) { diff --git a/src/game/level_update.h b/src/game/level_update.h index c020d5d1..34820d03 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -87,7 +87,7 @@ extern s16 sDelayedWarpTimer; extern s16 sSourceWarpNodeId; extern s32 sDelayedWarpArg; extern u8 unused3[2]; -extern s8 sTimerRunning; +extern s8 sPssTimerRunning; struct HudDisplay { /*0x00*/ s16 lives; @@ -102,6 +102,14 @@ struct HudDisplay { extern struct HudDisplay gHudDisplay; extern s8 gNeverEnteredCastle; +struct Timer { + u16 time; + s8 collectedStarId; /* ID of the star that has just been collected or -1 otherwise */ +}; + +extern struct Timer gTimer; +extern s8 sTimerRunning; + enum HUDDisplayFlag { HUD_DISPLAY_FLAG_LIVES = 0x0001, HUD_DISPLAY_FLAG_COIN_COUNT = 0x0002, @@ -109,15 +117,24 @@ enum HUDDisplayFlag { HUD_DISPLAY_FLAG_CAMERA_AND_POWER = 0x0008, HUD_DISPLAY_FLAG_KEYS = 0x0010, HUD_DISPLAY_FLAG_UNKNOWN_0020 = 0x0020, - HUD_DISPLAY_FLAG_TIMER = 0x0040, + HUD_DISPLAY_FLAG_PSS_TIMER = 0x0040, + HUD_DISPLAY_FLAG_TIMER = 0x0080, HUD_DISPLAY_FLAG_EMPHASIZE_POWER = 0x8000, HUD_DISPLAY_NONE = 0x0000, - HUD_DISPLAY_DEFAULT = HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_COIN_COUNT | HUD_DISPLAY_FLAG_STAR_COUNT | HUD_DISPLAY_FLAG_CAMERA_AND_POWER | HUD_DISPLAY_FLAG_KEYS | HUD_DISPLAY_FLAG_UNKNOWN_0020 + HUD_DISPLAY_DEFAULT = HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_COIN_COUNT + | HUD_DISPLAY_FLAG_STAR_COUNT | HUD_DISPLAY_FLAG_CAMERA_AND_POWER + | HUD_DISPLAY_FLAG_KEYS | HUD_DISPLAY_FLAG_UNKNOWN_0020 }; - u16 level_control_timer(s32 timerOp); +void start_gtimer(void); +void stop_gtimer(void); +void show_gtimer(void); +void hide_gtimer(void); +void reset_gtimer(void); +u16 get_timer_val(void); + void fade_into_special_warp(u32 arg, u32 color); void load_level_init_text(u32 arg); s16 level_trigger_warp(struct MarioState *m, s32 warpOp); diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index c31dc95d..86e40ecd 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -638,7 +638,7 @@ void general_star_dance_handler(struct MarioState *m, s32 isInWater) { } s32 act_star_dance(struct MarioState *m) { - // TODO end timer + end_timer(m); m->faceAngle[1] = m->area->camera->yaw; set_mario_animation(m, m->actionState == 2 ? MARIO_ANIM_RETURN_FROM_STAR_DANCE : MARIO_ANIM_STAR_DANCE); @@ -651,7 +651,7 @@ s32 act_star_dance(struct MarioState *m) { } s32 act_star_dance_water(struct MarioState *m) { - // TODO end timer + end_timer(m); m->faceAngle[1] = m->area->camera->yaw; set_mario_animation(m, m->actionState == 2 ? MARIO_ANIM_RETURN_FROM_WATER_STAR_DANCE : MARIO_ANIM_WATER_STAR_DANCE); @@ -998,6 +998,7 @@ s32 act_emerge_from_pipe(struct MarioState *m) { } s32 act_spawn_spin_airborne(struct MarioState *m) { + begin_timer(m); // entered water, exit action if (m->pos[1] < m->waterLevel - 100) { load_level_init_text(0); @@ -1030,6 +1031,7 @@ s32 act_spawn_spin_airborne(struct MarioState *m) { } s32 act_spawn_spin_landing(struct MarioState *m) { + begin_timer(m); stop_and_set_height_to_floor(m); set_mario_animation(m, MARIO_ANIM_GENERAL_LAND); if (is_anim_at_end(m)) { @@ -1177,7 +1179,7 @@ s32 act_death_exit(struct MarioState *m) { /** (Ab-)used as a life-restoring level entry with no control downtime **/ s32 act_unused_death_exit(struct MarioState *m) { - // TODO begin timer + begin_timer(m); if (launch_mario_until_land(m, ACT_FREEFALL_LAND_STOP, MARIO_ANIM_GENERAL_FALL, 0.0f)) { #ifdef VERSION_JP @@ -1261,6 +1263,7 @@ s32 act_special_death_exit(struct MarioState *m) { } s32 act_spawn_no_spin_airborne(struct MarioState *m) { + begin_timer(m); launch_mario_until_land(m, ACT_SPAWN_NO_SPIN_LANDING, MARIO_ANIM_GENERAL_FALL, 0.0f); if (m->pos[1] < m->waterLevel - 100) { set_water_plunge_action(m); @@ -1269,6 +1272,7 @@ s32 act_spawn_no_spin_airborne(struct MarioState *m) { } s32 act_spawn_no_spin_landing(struct MarioState *m) { + begin_timer(m); play_mario_landing_sound_once(m, SOUND_ACTION_TERRAIN_LANDING); set_mario_animation(m, MARIO_ANIM_GENERAL_LAND); stop_and_set_height_to_floor(m); diff --git a/src/game/print.c b/src/game/print.c index c804cb4a..04ca6f44 100644 --- a/src/game/print.c +++ b/src/game/print.c @@ -6,6 +6,7 @@ #include "memory.h" #include "print.h" #include "segment2.h" +#include "course_table.h" /** * This file handles printing and formatting the colorful text that @@ -457,3 +458,78 @@ void render_text_labels(void) { sTextLabelsCount = 0; } + +struct TimerDisplay frames_to_display_time(u16 timeInFrames) { + u16 timerMins = timeInFrames / (30 * 60); + u16 timerSecs = (timeInFrames - (timerMins * 1800)) / 30; + u16 timerFracSecs = + (u16) (((timeInFrames - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) * 3.34f); + struct TimerDisplay t; + t.mins = timerMins; + t.secs = timerSecs; + t.fracSecs = timerFracSecs; + return t; +} + +// Hardcoded Rank Definitions +u32 course_idx_to_rank_idx_map[2][2] = { { COURSE_NUM_TO_INDEX(1) /*COURSE_BOB*/, 1 }, + { COURSE_NUM_TO_INDEX(2) /*COURSE_WF*/, 2 } }; + +u32 course_idx_to_rank_idx(u32 courseIdx) { + u32 i; + for (i = 0; i < sizeof(course_idx_to_rank_idx_map) / sizeof(course_idx_to_rank_idx_map[0]); i++) { + if (courseIdx == course_idx_to_rank_idx_map[i][0]) { + return course_idx_to_rank_idx_map[i][1]; + } + } + return 0; +} + +short rank_times[3][7][4] = { + // fallback + { { _40s(0), _40s(0), _40s(0), _40s(0) }, + { _40s(0), _40s(0), _40s(0), _40s(0) }, + { _40s(0), _40s(0), _40s(0), _40s(0) }, + { _40s(0), _40s(0), _40s(0), _40s(0) }, + { _40s(0), _40s(0), _40s(0), _40s(0) }, + { _40s(0), _40s(0), _40s(0), _40s(0) }, + { _40s(0), _40s(0), _40s(0), _40s(0) } }, + // level 1 + { { _7s(6), _8s(0), _10s(20), _12s(0) }, + { _4s(22), _6s(0), _8s(0), _10s(0) }, + { _7s(28), _8s(0), _9s(0), _12s(0) }, + { _14s(27), _16s(0), _20s(0), _25s(0) }, + { _20s(0), _22s(0), _25s(0), _30s(0) }, + { _30s(0), _32s(0), _35s(0), _40s(0) }, + { _25s(0), _28s(0), _30s(0), _35s(0) } }, + // level 2 + { { _1s(0), _10s(0), _20s(0), _30s(0) }, + { _1s(0), _10s(0), _20s(0), _30s(0) }, + { _1s(0), _10s(0), _20s(0), _30s(0) }, + { _1s(0), _10s(0), _20s(0), _30s(0) }, + { _1s(0), _10s(0), _20s(0), _30s(0) }, + { _1s(0), _10s(0), _20s(0), _30s(0) }, + { _1s(0), _10s(0), _20s(0), _30s(0) } } +}; + +struct RankDisplay time_to_rank(u16 timeInFrames, s16 courseIdx, s8 starId) { + struct RankDisplay rank; + short *scores = rank_times[course_idx_to_rank_idx(courseIdx)][starId]; + if (timeInFrames < scores[0]) { + rank.asChar = 'S'; + rank.asU8 = 0x1C; + } else if (timeInFrames < scores[1]) { + rank.asChar = 'A'; + rank.asU8 = 0x0A; + } else if (timeInFrames < scores[2]) { + rank.asChar = 'B'; + rank.asU8 = 0x0B; + } else if (timeInFrames < scores[3]) { + rank.asChar = 'C'; + rank.asU8 = 0x0C; + } else { + rank.asChar = 'D'; + rank.asU8 = 0x0D; + } + return rank; +} diff --git a/src/game/print.h b/src/game/print.h index 95597e8a..5b6e72f1 100644 --- a/src/game/print.h +++ b/src/game/print.h @@ -25,9 +25,67 @@ #define GLYPH_DOUBLE_QUOTE 57 #define GLYPH_UMLAUT 58 +#define FPS 30 +#define _1s(frames) (FPS * 1 + frames) +#define _2s(frames) (FPS * 2 + frames) +#define _3s(frames) (FPS * 3 + frames) +#define _4s(frames) (FPS * 4 + frames) +#define _5s(frames) (FPS * 5 + frames) +#define _6s(frames) (FPS * 6 + frames) +#define _7s(frames) (FPS * 7 + frames) +#define _8s(frames) (FPS * 8 + frames) +#define _9s(frames) (FPS * 9 + frames) +#define _10s(frames) (FPS * 10 + frames) +#define _11s(frames) (FPS * 11 + frames) +#define _12s(frames) (FPS * 12 + frames) +#define _13s(frames) (FPS * 13 + frames) +#define _14s(frames) (FPS * 14 + frames) +#define _15s(frames) (FPS * 15 + frames) +#define _16s(frames) (FPS * 16 + frames) +#define _17s(frames) (FPS * 17 + frames) +#define _18s(frames) (FPS * 18 + frames) +#define _19s(frames) (FPS * 19 + frames) +#define _20s(frames) (FPS * 20 + frames) +#define _21s(frames) (FPS * 21 + frames) +#define _22s(frames) (FPS * 22 + frames) +#define _23s(frames) (FPS * 23 + frames) +#define _24s(frames) (FPS * 24 + frames) +#define _25s(frames) (FPS * 25 + frames) +#define _26s(frames) (FPS * 26 + frames) +#define _27s(frames) (FPS * 27 + frames) +#define _28s(frames) (FPS * 28 + frames) +#define _29s(frames) (FPS * 29 + frames) +#define _30s(frames) (FPS * 30 + frames) +#define _31s(frames) (FPS * 31 + frames) +#define _32s(frames) (FPS * 32 + frames) +#define _33s(frames) (FPS * 33 + frames) +#define _34s(frames) (FPS * 34 + frames) +#define _35s(frames) (FPS * 35 + frames) +#define _36s(frames) (FPS * 36 + frames) +#define _37s(frames) (FPS * 37 + frames) +#define _38s(frames) (FPS * 38 + frames) +#define _39s(frames) (FPS * 39 + frames) +#define _40s(frames) (FPS * 40 + frames) + +#define RANK_NONE 0x9F +#define RANK_NONE_2 GLYPH_MULTIPLY + +struct TimerDisplay { + u16 mins; + u16 secs; + u16 fracSecs; +}; + +struct RankDisplay { + char asChar; + u8 asU8; +}; + void print_text_fmt_int(s32 x, s32 y, const char *str, s32 n); void print_text(s32 x, s32 y, const char *str); void print_text_centered(s32 x, s32 y, const char *str); void render_text_labels(void); +struct TimerDisplay frames_to_display_time(u16 timeInFrames); +struct RankDisplay time_to_rank(u16 timeInFrames, s16 courseIdx, s8 starId); #endif // PRINT_H diff --git a/src/game/save_file.c b/src/game/save_file.c index 85e5df18..861bf012 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -15,6 +15,7 @@ #define MENU_DATA_MAGIC 0x4849 #define SAVE_FILE_MAGIC 0x4441 +STATIC_ASSERT(sizeof(struct HighScores) == sizeof(struct SaveFile) * 4, "HighScores size must match"); STATIC_ASSERT(sizeof(struct SaveBuffer) == EEPROM_SIZE, "eeprom buffer size must match"); extern struct SaveBuffer gSaveBuffer; @@ -265,12 +266,18 @@ void save_file_do_save(s32 fileIndex) { gSaveFileModified = FALSE; } + write_eeprom_data(gSaveBuffer.highScores, sizeof(gSaveBuffer.highScores)); + save_main_menu_data(); } void save_file_erase(s32 fileIndex) { touch_high_score_ages(fileIndex); bzero(&gSaveBuffer.files[fileIndex][0], sizeof(gSaveBuffer.files[fileIndex][0])); + /* Don't delete highscores on file erase + * // bzero(&gSaveBuffer.highScores, sizeof(gSaveBuffer.highScores)); + * // bzero(&gSaveBuffer, sizeof(gSaveBuffer)); + */ gSaveFileModified = TRUE; save_file_do_save(fileIndex); @@ -408,6 +415,46 @@ void save_file_collect_star_or_key(s16 coinScore, s16 starIndex) { } } +bool save_file_register_new_time(s32 courseIndex, s16 starIndex, u16 time) { + if (time > 0 && time < save_file_get_best_time(courseIndex, starIndex)) { + gSaveBuffer.highScores[0].times[courseIndex][starIndex] = time; + return TRUE; + } + return FALSE; +} + +u16 save_file_get_best_time(s32 courseIndex, s16 starIndex) { + if (!save_file_best_time_exists(courseIndex, starIndex)) { + return 17999; + } + return gSaveBuffer.highScores[0].times[courseIndex][starIndex]; +} + +bool save_file_best_time_exists(s32 courseIndex, s16 starIndex) { + return gSaveBuffer.highScores[0].times[courseIndex][starIndex] != 0; +} + +u32 save_file_get_course_sob(s32 courseIndex) { + u32 sob; + u32 starFlags; + s16 i; + + sob = 0; + starFlags = save_file_get_star_flags(0, courseIndex); + + for (i = 0; i < 7; i++) { + if (starFlags & (1 << i) || save_file_best_time_exists(courseIndex, i)) { + u16 starPb = save_file_get_best_time(courseIndex, i); + sob += starPb; + if (sob > 17999) { + sob = 17999; + } + } + } + + return sob; +} + s32 save_file_exists(s32 fileIndex) { return (gSaveBuffer.files[fileIndex][0].flags & SAVE_FLAG_FILE_EXISTS) != 0; } @@ -563,7 +610,11 @@ void save_file_set_sound_mode(u16 mode) { } u16 save_file_get_sound_mode(void) { - return gSaveBuffer.menuData[0].soundMode; + u16 soundMode = gSaveBuffer.menuData[0].soundMode; + if (is_sound_mode_valid(soundMode)) { + return soundMode; + } + return SOUND_MENU_MODE_STEREO; } void save_file_move_cap_to_default_location(void) { diff --git a/src/game/save_file.h b/src/game/save_file.h index ad1b62a9..0b5a33af 100644 --- a/src/game/save_file.h +++ b/src/game/save_file.h @@ -9,7 +9,8 @@ #include "course_table.h" #define EEPROM_SIZE 0x200 -#define NUM_SAVE_FILES 4 +#define NUM_SAVE_FILES 1 +#define NUM_SCORES_PER_STAGE 7 struct SaveBlockSignature { u16 magic; @@ -36,13 +37,13 @@ struct SaveFile { struct SaveBlockSignature signature; }; -enum SaveFileIndex { - SAVE_FILE_A, - SAVE_FILE_B, - SAVE_FILE_C, - SAVE_FILE_D +struct HighScores { + u16 times[COURSE_STAGES_COUNT][NUM_SCORES_PER_STAGE]; + u8 filler[sizeof(struct SaveFile) * 4 - sizeof(u16) * COURSE_STAGES_COUNT * NUM_SCORES_PER_STAGE]; }; +enum SaveFileIndex { SAVE_FILE_A }; + struct MainMenuSaveData { // Each save file has a 2 bit "age" for each course. The higher this value, // the older the high score is. This is used for tie-breaking when displaying @@ -58,7 +59,8 @@ struct MainMenuSaveData { #endif // Pad to match the EEPROM size of 0x200 (10 bytes on JP/US, 8 bytes on EU) - u8 filler[EEPROM_SIZE / 2 - SUBTRAHEND - NUM_SAVE_FILES * (4 + sizeof(struct SaveFile))]; + u8 filler[EEPROM_SIZE / 2 - SUBTRAHEND - NUM_SAVE_FILES * (4 + sizeof(struct SaveFile)) + - sizeof(struct HighScores) / 2]; struct SaveBlockSignature signature; }; @@ -66,6 +68,7 @@ struct MainMenuSaveData { struct SaveBuffer { // Each of the four save files has two copies. If one is bad, the other is used as a backup. struct SaveFile files[NUM_SAVE_FILES][2]; + struct HighScores highScores[1]; // The main menu data has two copies. If one is bad, the other is used as a backup. struct MainMenuSaveData menuData[2]; }; @@ -131,6 +134,13 @@ BAD_RETURN(s32) save_file_copy(s32 srcFileIndex, s32 destFileIndex); void save_file_load_all(void); void save_file_reload(void); void save_file_collect_star_or_key(s16 coinScore, s16 starIndex); + +// PB-System +bool save_file_register_new_time(s32 courseIndex, s16 starIndex, u16 time); +u16 save_file_get_best_time(s32 courseIndex, s16 starIndex); +bool save_file_best_time_exists(s32 courseIndex, s16 starIndex); +u32 save_file_get_course_sob(s32 courseIndex); + s32 save_file_exists(s32 fileIndex); u32 save_file_get_max_coin_score(s32 courseIndex); s32 save_file_get_course_star_count(s32 fileIndex, s32 courseIndex); diff --git a/src/game/sound_init.c b/src/game/sound_init.c index c4bad21c..92d20ec3 100644 --- a/src/game/sound_init.c +++ b/src/game/sound_init.c @@ -139,11 +139,15 @@ void enable_background_sound(void) { * Called from threads: thread5_game_loop */ void set_sound_mode(u16 soundMode) { - if (soundMode < 3) { + if (is_sound_mode_valid(soundMode)) { audio_set_sound_mode(sSoundMenuModeToSoundMode[soundMode]); } } +bool is_sound_mode_valid(u16 soundMode) { + return soundMode < 3; +} + /** * Wrapper method by menu used to set the sound via flags. * diff --git a/src/game/sound_init.h b/src/game/sound_init.h index a03c5d84..2fa63373 100644 --- a/src/game/sound_init.h +++ b/src/game/sound_init.h @@ -24,6 +24,7 @@ void lower_background_noise(s32 a); void disable_background_sound(void); void enable_background_sound(void); void set_sound_mode(u16 soundMode); +bool is_sound_mode_valid(u16 soundMode); void play_menu_sounds(s16 soundMenuFlags); void play_painting_eject_sound(void); void play_infinite_stairs_music(void); diff --git a/src/menu/file_select.c b/src/menu/file_select.c index fce9a9e2..6cc550ac 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -154,9 +154,6 @@ static unsigned char textSoundModes[][8] = { { TEXT_STEREO }, { TEXT_MONO }, { T #endif static unsigned char textMarioA[] = { TEXT_FILE_MARIO_A }; -static unsigned char textMarioB[] = { TEXT_FILE_MARIO_B }; -static unsigned char textMarioC[] = { TEXT_FILE_MARIO_C }; -static unsigned char textMarioD[] = { TEXT_FILE_MARIO_D }; #ifndef VERSION_EU static unsigned char textNew[] = { TEXT_NEW }; @@ -578,36 +575,7 @@ void render_score_menu_buttons(struct Object *scoreButton) { 311, -100, 0, -0x8000, 0); } sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A]->oMenuButtonScale = 0.11111111f; - // File B - if (save_file_exists(SAVE_FILE_B) == TRUE) { - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B] = - spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, - -166, 311, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B] = - spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, - -166, 311, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B]->oMenuButtonScale = 0.11111111f; - // File C - if (save_file_exists(SAVE_FILE_C) == TRUE) { - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C] = spawn_object_rel_with_rot( - scoreButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C] = spawn_object_rel_with_rot( - scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C]->oMenuButtonScale = 0.11111111f; - // File D - if (save_file_exists(SAVE_FILE_D) == TRUE) { - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D] = - spawn_object_rel_with_rot(scoreButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, - -166, 0, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D] = spawn_object_rel_with_rot( - scoreButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D]->oMenuButtonScale = 0.11111111f; + // Return to main menu button sMainMenuButtons[MENU_BUTTON_SCORE_RETURN] = spawn_object_rel_with_rot( scoreButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 711, -388, -100, 0, -0x8000, 0); @@ -700,35 +668,7 @@ void render_copy_menu_buttons(struct Object *copyButton) { copyButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 311, -100, 0, -0x8000, 0); } sMainMenuButtons[MENU_BUTTON_COPY_FILE_A]->oMenuButtonScale = 0.11111111f; - // File B - if (save_file_exists(SAVE_FILE_B) == TRUE) { - sMainMenuButtons[MENU_BUTTON_COPY_FILE_B] = - spawn_object_rel_with_rot(copyButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, - -166, 311, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_COPY_FILE_B] = - spawn_object_rel_with_rot(copyButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, - 311, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_COPY_FILE_B]->oMenuButtonScale = 0.11111111f; - // File C - if (save_file_exists(SAVE_FILE_C) == TRUE) { - sMainMenuButtons[MENU_BUTTON_COPY_FILE_C] = spawn_object_rel_with_rot( - copyButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_COPY_FILE_C] = spawn_object_rel_with_rot( - copyButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_COPY_FILE_C]->oMenuButtonScale = 0.11111111f; - // File D - if (save_file_exists(SAVE_FILE_D) == TRUE) { - sMainMenuButtons[MENU_BUTTON_COPY_FILE_D] = spawn_object_rel_with_rot( - copyButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_COPY_FILE_D] = spawn_object_rel_with_rot( - copyButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_COPY_FILE_D]->oMenuButtonScale = 0.11111111f; + // Return to main menu button sMainMenuButtons[MENU_BUTTON_COPY_RETURN] = spawn_object_rel_with_rot( copyButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 711, -388, -100, 0, -0x8000, 0); @@ -890,36 +830,7 @@ void render_erase_menu_buttons(struct Object *eraseButton) { 311, -100, 0, -0x8000, 0); } sMainMenuButtons[MENU_BUTTON_ERASE_FILE_A]->oMenuButtonScale = 0.11111111f; - // File B - if (save_file_exists(SAVE_FILE_B) == TRUE) { - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_B] = - spawn_object_rel_with_rot(eraseButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, - -166, 311, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_B] = - spawn_object_rel_with_rot(eraseButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, - -166, 311, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_B]->oMenuButtonScale = 0.11111111f; - // File C - if (save_file_exists(SAVE_FILE_C) == TRUE) { - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_C] = spawn_object_rel_with_rot( - eraseButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_C] = spawn_object_rel_with_rot( - eraseButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, 711, 0, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_C]->oMenuButtonScale = 0.11111111f; - // File D - if (save_file_exists(SAVE_FILE_D) == TRUE) { - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_D] = - spawn_object_rel_with_rot(eraseButton, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON, bhvMenuButton, - -166, 0, -100, 0, -0x8000, 0); - } else { - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_D] = spawn_object_rel_with_rot( - eraseButton, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, -166, 0, -100, 0, -0x8000, 0); - } - sMainMenuButtons[MENU_BUTTON_ERASE_FILE_D]->oMenuButtonScale = 0.11111111f; + // Return to main menu button sMainMenuButtons[MENU_BUTTON_ERASE_RETURN] = spawn_object_rel_with_rot( eraseButton, MODEL_MAIN_MENU_YELLOW_FILE_BUTTON, bhvMenuButton, 711, -388, -100, 0, -0x8000, 0); @@ -1328,36 +1239,7 @@ void bhv_menu_button_manager_init(void) { bhvMenuButton, -6400, 2800, 0, 0, 0, 0); } sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A]->oMenuButtonScale = 1.0f; - // File B - if (save_file_exists(SAVE_FILE_B) == TRUE) { - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B] = - spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE, - bhvMenuButton, 1500, 2800, 0, 0, 0, 0); - } else { - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B] = - spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, - bhvMenuButton, 1500, 2800, 0, 0, 0, 0); - } - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B]->oMenuButtonScale = 1.0f; - // File C - if (save_file_exists(SAVE_FILE_C) == TRUE) { - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C] = - spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE, - bhvMenuButton, -6400, 0, 0, 0, 0, 0); - } else { - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C] = spawn_object_rel_with_rot( - gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, bhvMenuButton, -6400, 0, 0, 0, 0, 0); - } - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C]->oMenuButtonScale = 1.0f; - // File D - if (save_file_exists(SAVE_FILE_D) == TRUE) { - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D] = spawn_object_rel_with_rot( - gCurrentObject, MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE, bhvMenuButton, 1500, 0, 0, 0, 0, 0); - } else { - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D] = spawn_object_rel_with_rot( - gCurrentObject, MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE, bhvMenuButton, 1500, 0, 0, 0, 0, 0); - } - sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D]->oMenuButtonScale = 1.0f; + // Score menu button sMainMenuButtons[MENU_BUTTON_SCORE] = spawn_object_rel_with_rot( gCurrentObject, MODEL_MAIN_MENU_GREEN_SCORE_BUTTON, bhvMenuButton, -6400, -3500, 0, 0, 0, 0); @@ -1432,27 +1314,7 @@ void check_main_menu_clicked_buttons(void) { func_sh_8024C89C(1); #endif break; - case MENU_BUTTON_PLAY_FILE_B: - play_sound(SAVE_FILE_SOUND, gGlobalSoundSource); -#if ENABLE_RUMBLE - queue_rumble_data(60, 70); - func_sh_8024C89C(1); -#endif - break; - case MENU_BUTTON_PLAY_FILE_C: - play_sound(SAVE_FILE_SOUND, gGlobalSoundSource); -#if ENABLE_RUMBLE - queue_rumble_data(60, 70); - func_sh_8024C89C(1); -#endif - break; - case MENU_BUTTON_PLAY_FILE_D: - play_sound(SAVE_FILE_SOUND, gGlobalSoundSource); -#if ENABLE_RUMBLE - queue_rumble_data(60, 70); - func_sh_8024C89C(1); -#endif - break; + // Play sound of the button clicked and render buttons of that menu. case MENU_BUTTON_SCORE: play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); @@ -1504,15 +1366,6 @@ void bhv_menu_button_manager_loop(void) { case MENU_BUTTON_PLAY_FILE_A: load_main_menu_save_file(sMainMenuButtons[MENU_BUTTON_PLAY_FILE_A], 1); break; - case MENU_BUTTON_PLAY_FILE_B: - load_main_menu_save_file(sMainMenuButtons[MENU_BUTTON_PLAY_FILE_B], 2); - break; - case MENU_BUTTON_PLAY_FILE_C: - load_main_menu_save_file(sMainMenuButtons[MENU_BUTTON_PLAY_FILE_C], 3); - break; - case MENU_BUTTON_PLAY_FILE_D: - load_main_menu_save_file(sMainMenuButtons[MENU_BUTTON_PLAY_FILE_D], 4); - break; case MENU_BUTTON_SCORE: check_score_menu_clicked_buttons(sMainMenuButtons[MENU_BUTTON_SCORE]); break; @@ -1526,15 +1379,6 @@ void bhv_menu_button_manager_loop(void) { case MENU_BUTTON_SCORE_FILE_A: exit_score_file_to_score_menu(sMainMenuButtons[MENU_BUTTON_SCORE_FILE_A], MENU_BUTTON_SCORE); break; - case MENU_BUTTON_SCORE_FILE_B: - exit_score_file_to_score_menu(sMainMenuButtons[MENU_BUTTON_SCORE_FILE_B], MENU_BUTTON_SCORE); - break; - case MENU_BUTTON_SCORE_FILE_C: - exit_score_file_to_score_menu(sMainMenuButtons[MENU_BUTTON_SCORE_FILE_C], MENU_BUTTON_SCORE); - break; - case MENU_BUTTON_SCORE_FILE_D: - exit_score_file_to_score_menu(sMainMenuButtons[MENU_BUTTON_SCORE_FILE_D], MENU_BUTTON_SCORE); - break; case MENU_BUTTON_SCORE_RETURN: return_to_main_menu(MENU_BUTTON_SCORE, sMainMenuButtons[MENU_BUTTON_SCORE_RETURN]); break; @@ -1549,12 +1393,6 @@ void bhv_menu_button_manager_loop(void) { case MENU_BUTTON_COPY_FILE_A: break; - case MENU_BUTTON_COPY_FILE_B: - break; - case MENU_BUTTON_COPY_FILE_C: - break; - case MENU_BUTTON_COPY_FILE_D: - break; case MENU_BUTTON_COPY_RETURN: return_to_main_menu(MENU_BUTTON_COPY, sMainMenuButtons[MENU_BUTTON_COPY_RETURN]); break; @@ -1569,12 +1407,6 @@ void bhv_menu_button_manager_loop(void) { case MENU_BUTTON_ERASE_FILE_A: break; - case MENU_BUTTON_ERASE_FILE_B: - break; - case MENU_BUTTON_ERASE_FILE_C: - break; - case MENU_BUTTON_ERASE_FILE_D: - break; case MENU_BUTTON_ERASE_RETURN: return_to_main_menu(MENU_BUTTON_ERASE, sMainMenuButtons[MENU_BUTTON_ERASE_RETURN]); break; @@ -1620,9 +1452,7 @@ void bhv_menu_button_manager_loop(void) { */ void handle_cursor_button_input(void) { // If scoring a file, pressing A just changes the coin score mode. - if (sSelectedButtonID == MENU_BUTTON_SCORE_FILE_A || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_B - || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_C - || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_D) { + if (sSelectedButtonID == MENU_BUTTON_SCORE_FILE_A) { if (gPlayer3Controller->buttonPressed #ifdef VERSION_EU & (B_BUTTON | START_BUTTON | Z_TRIG) @@ -1832,9 +1662,6 @@ void print_main_menu_strings(void) { #endif // Print file star counts print_save_file_star_count(SAVE_FILE_A, SAVEFILE_X1, 78); - print_save_file_star_count(SAVE_FILE_B, SAVEFILE_X2, 78); - print_save_file_star_count(SAVE_FILE_C, SAVEFILE_X1, 118); - print_save_file_star_count(SAVE_FILE_D, SAVEFILE_X2, 118); gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); #ifndef VERSION_EU // Print menu names @@ -1853,9 +1680,6 @@ void print_main_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); print_menu_generic_string(MARIOTEXT_X1, 65, textMarioA); - print_menu_generic_string(MARIOTEXT_X2, 65, textMarioB); - print_menu_generic_string(MARIOTEXT_X1, 105, textMarioC); - print_menu_generic_string(MARIOTEXT_X2, 105, textMarioD); gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_end); } @@ -1974,9 +1798,6 @@ void print_score_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); print_save_file_star_count(SAVE_FILE_A, 90, 76); - print_save_file_star_count(SAVE_FILE_B, 211, 76); - print_save_file_star_count(SAVE_FILE_C, 90, 119); - print_save_file_star_count(SAVE_FILE_D, 211, 119); gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); #endif @@ -2004,9 +1825,6 @@ void print_score_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); print_menu_generic_string(89, 62, textMarioA); - print_menu_generic_string(211, 62, textMarioB); - print_menu_generic_string(89, 105, textMarioC); - print_menu_generic_string(211, 105, textMarioD); gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_end); #endif } @@ -2161,9 +1979,6 @@ void print_copy_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); print_save_file_star_count(SAVE_FILE_A, 90, 76); - print_save_file_star_count(SAVE_FILE_B, 211, 76); - print_save_file_star_count(SAVE_FILE_C, 90, 119); - print_save_file_star_count(SAVE_FILE_D, 211, 119); gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); #endif // Print menu names @@ -2189,9 +2004,6 @@ void print_copy_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); print_menu_generic_string(89, 62, textMarioA); - print_menu_generic_string(211, 62, textMarioB); - print_menu_generic_string(89, 105, textMarioC); - print_menu_generic_string(211, 105, textMarioD); gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_end); #endif } @@ -2434,9 +2246,6 @@ void print_erase_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); print_save_file_star_count(SAVE_FILE_A, 90, 76); - print_save_file_star_count(SAVE_FILE_B, 211, 76); - print_save_file_star_count(SAVE_FILE_C, 90, 119); - print_save_file_star_count(SAVE_FILE_D, 211, 119); gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); #endif @@ -2465,9 +2274,6 @@ void print_erase_menu_strings(void) { gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, sTextBaseAlpha); print_menu_generic_string(89, 62, textMarioA); - print_menu_generic_string(211, 62, textMarioB); - print_menu_generic_string(89, 105, textMarioC); - print_menu_generic_string(211, 105, textMarioD); gSPDisplayList(gDisplayListHead++, dl_menu_ia8_text_end); #endif } @@ -2605,7 +2411,7 @@ void print_score_file_course_coin_score(s8 fileIndex, s16 courseIndex, s16 x, s1 #endif unsigned char fileNames[][LENGTH] = { { TEXT_4DASHES }, // huh? - { TEXT_SCORE_MARIO_A }, { TEXT_SCORE_MARIO_B }, { TEXT_SCORE_MARIO_C }, { TEXT_SCORE_MARIO_D }, + { TEXT_SCORE_MARIO_A }, }; #undef LENGTH // MYSCORE @@ -2807,22 +2613,12 @@ static void print_file_select_strings(void) { case MENU_BUTTON_SCORE_FILE_A: print_save_file_scores(SAVE_FILE_A); break; - case MENU_BUTTON_SCORE_FILE_B: - print_save_file_scores(SAVE_FILE_B); - break; - case MENU_BUTTON_SCORE_FILE_C: - print_save_file_scores(SAVE_FILE_C); - break; - case MENU_BUTTON_SCORE_FILE_D: - print_save_file_scores(SAVE_FILE_D); - break; case MENU_BUTTON_SOUND_MODE: print_sound_mode_menu_strings(); break; } // If all 4 save file exists, define true to sAllFilesExist to prevent more copies in copy menu - if (save_file_exists(SAVE_FILE_A) == TRUE && save_file_exists(SAVE_FILE_B) == TRUE && - save_file_exists(SAVE_FILE_C) == TRUE && save_file_exists(SAVE_FILE_D) == TRUE) { + if (save_file_exists(SAVE_FILE_A) == TRUE) { sAllFilesExist = TRUE; } else { sAllFilesExist = FALSE; @@ -2859,27 +2655,11 @@ s32 lvl_init_menu_values_and_cursor_pos(UNUSED s32 arg, UNUSED s32 unused) { sSelectedButtonID = MENU_BUTTON_NONE; sCurrentMenuLevel = MENU_LAYER_MAIN; sTextBaseAlpha = 0; - // Place the cursor over the save file that was being played. - // gCurrSaveFileNum is 1 by default when the game boots, as such - // the cursor will point on Mario A save file. - switch (gCurrSaveFileNum) { - case 1: // File A - sCursorPos[0] = -94.0f; - sCursorPos[1] = 46.0f; - break; - case 2: // File B - sCursorPos[0] = 24.0f; - sCursorPos[1] = 46.0f; - break; - case 3: // File C - sCursorPos[0] = -94.0f; - sCursorPos[1] = 5.0f; - break; - case 4: // File D - sCursorPos[0] = 24.0f; - sCursorPos[1] = 5.0f; - break; - } + + // set the cursor pos over file A + sCursorPos[0] = -94.0f; + sCursorPos[1] = 46.0f; + sClickPos[0] = -10000; sClickPos[1] = -10000; sCursorClickingTimer = 0; diff --git a/src/menu/file_select.h b/src/menu/file_select.h index d4d75b65..73f17221 100644 --- a/src/menu/file_select.h +++ b/src/menu/file_select.h @@ -29,9 +29,6 @@ enum MenuButtonTypes { // Main Menu (SELECT FILE) MENU_BUTTON_MAIN_MIN, MENU_BUTTON_PLAY_FILE_A = MENU_BUTTON_MAIN_MIN, - MENU_BUTTON_PLAY_FILE_B, - MENU_BUTTON_PLAY_FILE_C, - MENU_BUTTON_PLAY_FILE_D, MENU_BUTTON_SCORE, MENU_BUTTON_COPY, MENU_BUTTON_ERASE, @@ -40,9 +37,6 @@ enum MenuButtonTypes { // Score Menu (CHECK FILE) MENU_BUTTON_SCORE_MIN = MENU_BUTTON_MAIN_MAX, MENU_BUTTON_SCORE_FILE_A = MENU_BUTTON_SCORE_MIN, - MENU_BUTTON_SCORE_FILE_B, - MENU_BUTTON_SCORE_FILE_C, - MENU_BUTTON_SCORE_FILE_D, MENU_BUTTON_SCORE_RETURN, MENU_BUTTON_SCORE_COPY_FILE, MENU_BUTTON_SCORE_ERASE_FILE, @@ -51,9 +45,6 @@ enum MenuButtonTypes { // Copy Menu (COPY FILE) MENU_BUTTON_COPY_MIN = MENU_BUTTON_SCORE_MAX, MENU_BUTTON_COPY_FILE_A = MENU_BUTTON_COPY_MIN, - MENU_BUTTON_COPY_FILE_B, - MENU_BUTTON_COPY_FILE_C, - MENU_BUTTON_COPY_FILE_D, MENU_BUTTON_COPY_RETURN, MENU_BUTTON_COPY_CHECK_SCORE, MENU_BUTTON_COPY_ERASE_FILE, @@ -62,9 +53,6 @@ enum MenuButtonTypes { // Erase Menu (ERASE FILE) MENU_BUTTON_ERASE_MIN = MENU_BUTTON_COPY_MAX, MENU_BUTTON_ERASE_FILE_A = MENU_BUTTON_ERASE_MIN, - MENU_BUTTON_ERASE_FILE_B, - MENU_BUTTON_ERASE_FILE_C, - MENU_BUTTON_ERASE_FILE_D, MENU_BUTTON_ERASE_RETURN, MENU_BUTTON_ERASE_CHECK_SCORE, MENU_BUTTON_ERASE_COPY_FILE, diff --git a/src/menu/star_select.c b/src/menu/star_select.c index f7d1d740..42294716 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -304,7 +304,7 @@ void print_act_selector_strings(void) { // Print the coin highscore. gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); - print_hud_my_score_coins(1, gCurrSaveFileNum - 1, COURSE_NUM_TO_INDEX(gCurrCourseNum), 155, 106); + print_hud_my_sob(COURSE_NUM_TO_INDEX(gCurrCourseNum), 155, 106); gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);