From 2b20d9e32c2bf99f192706abce96a4f63a94ccdd Mon Sep 17 00:00:00 2001 From: GateGuy <57763469+GateGuy@users.noreply.github.com> Date: Thu, 16 Jul 2020 00:27:54 -0400 Subject: [PATCH 1/6] First commit (it's probably done) --- include/text_strings.h.in | 25 ++ src/game/hud.c | 60 ++++ src/game/ingame_menu.c | 614 +++++++++++++++++++++++++++++++- src/game/interaction.c | 8 + src/game/level_update.c | 16 + src/game/level_update.h | 7 +- src/game/save_file.c | 118 ++++++ src/game/save_file.h | 15 +- src/game/text_save.inc.h | 25 ++ src/pc/ultra_reimplementation.c | 18 +- 10 files changed, 890 insertions(+), 16 deletions(-) diff --git a/include/text_strings.h.in b/include/text_strings.h.in index e5065c570e..d93f288a7d 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -18,6 +18,31 @@ #define TEXT_VARIABLE_X _("×") #define TEXT_UNFILLED_STAR _("☆") +/** + * Time Trial Text + */ +#define TEXT_TIME_TRIAL_STAR _("STAR") +#define TEXT_TIME_TRIAL_KEY _("KEY") +#define TEXT_TIME_TRIAL_FINAL _("FINAL") +#define TEXT_TIME_TRIAL_1 _("1") +#define TEXT_TIME_TRIAL_2 _("2") +#define TEXT_TIME_TRIAL_3 _("3") +#define TEXT_TIME_TRIAL_4 _("4") +#define TEXT_TIME_TRIAL_5 _("5") +#define TEXT_TIME_TRIAL_6 _("6") +#define TEXT_TIME_TRIAL_COURSE _("COURSE") +#define TEXT_TIME_TRIAL_TOTAL _("TOTAL") +#define TEXT_TIME_TRIAL_BOWSER _("BOWSER") +#define TEXT_TIME_TRIAL_PSS1 _("PSS 1") +#define TEXT_TIME_TRIAL_PSS2 _("PSS 2") +#define TEXT_TIME_TRIAL_SA _("SA") +#define TEXT_TIME_TRIAL_TOTWC _("TOTWC") +#define TEXT_TIME_TRIAL_VCUTM _("VCUTM") +#define TEXT_TIME_TRIAL_COTMC _("COTMC") +#define TEXT_TIME_TRIAL_WMOTR _("WMOTR") +#define TEXT_TIME_TRIAL_TIMER_TOGGLE _("C-UP, DOWN - TOGGLE TIMER") +#define TEXT_TIME_TRIAL_RESET _("ZBLZBZLZZB - RESET COURSE TIMES") + /** * Global Text */ diff --git a/src/game/hud.c b/src/game/hud.c index 1540b675ad..2dba3b1fc0 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -335,6 +335,62 @@ void render_hud_timer(void) { hudLUT = segmented_to_virtual(&main_hud_lut); timerValFrames = gHudDisplay.timer; + if (gHudDisplay.flags & HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER) { + timerMins = timerValFrames / (30 * 60); + timerSecs = (timerValFrames - (timerMins * 1800)) / 30; + + timerFracSecs = ((timerValFrames - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) / 3; + + print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(91), 160, "%0d", timerMins); + print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(71), 160, "%02d", timerSecs); + print_text_fmt_int(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(37), 160, "%d", timerFracSecs); + gSPDisplayList(gDisplayListHead++, dl_hud_img_begin); + render_hud_tex_lut(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(81), 57, (*hudLUT)[GLYPH_APOSTROPHE]); + render_hud_tex_lut(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(46), 57, (*hudLUT)[GLYPH_DOUBLE_QUOTE]); + gSPDisplayList(gDisplayListHead++, dl_hud_img_end); + } else { +#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; + } +#endif + timerMins = timerValFrames / (30 * 60); + timerSecs = (timerValFrames - (timerMins * 1800)) / 30; + + timerFracSecs = ((timerValFrames - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) / 3; +#ifndef VERSION_EU + print_text(GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(150), 185, "TIME"); +#endif + 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); + 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]); + gSPDisplayList(gDisplayListHead++, dl_hud_img_end); + } +} + +/** + * Renders the timer for time trials. + */ +void time_trial_render_hud_timer(void) { + u8 *(*hudLUT)[58]; + u16 timerValFrames; + u16 timerMins; + u16 timerSecs; + u16 timerFracSecs; + + hudLUT = segmented_to_virtual(&main_hud_lut); + timerValFrames = gHudDisplay.timeTrialTimer; #ifdef VERSION_EU switch (eu_get_language()) { case LANGUAGE_ENGLISH: @@ -477,5 +533,9 @@ void render_hud(void) { if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER && configHUD) { render_hud_timer(); } + + if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER && configHUD) { + time_trial_render_hud_timer(); + } } } diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 7ae9f1e735..d1c6685f97 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -46,6 +46,9 @@ s8 gRedCoinsCollected; extern u8 gLastCompletedCourseNum; extern u8 gLastCompletedStarNum; +u8 gTimeTrialResetIndex; +s32 timeTrialResetIndexCombo[16] = { Z_TRIG, B_BUTTON, L_TRIG, Z_TRIG, B_BUTTON, Z_TRIG, L_TRIG, Z_TRIG, Z_TRIG, B_BUTTON }; + enum DialogBoxState { DIALOG_STATE_OPENING, DIALOG_STATE_VERTICAL, @@ -900,6 +903,117 @@ void int_to_str(s32 num, u8 *dst) { dst[pos] = DIALOG_CHAR_TERMINATOR; } +void time_trial_int_to_str(u16 num, u8 *dst) { + // Assumes a cap of <10 minutes + u16 timerMins = num / 1800; + u16 timerSecs = (num - (timerMins * 1800)) / 30; + u16 timerFracSecs = ((num - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) * 100/30; + + dst[0] = timerMins; + dst[1] = 0x3E; + + s32 secs1 = timerSecs / 10; + s32 secs2 = (timerSecs - secs1 * 10); + dst[2] = secs1; + dst[3] = secs2; + dst[4] = 0x3E; + + s32 fracSecs1 = timerFracSecs / 10; + s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); + dst[5] = fracSecs1; + dst[6] = fracSecs2; + dst[7] = DIALOG_CHAR_TERMINATOR; +} + +void time_trial_int_to_str_course(u32 num, u8 *dst) { + // Assumes a cap of <100 minutes + u16 timerMins = num / 1800; + u16 timerSecs = (num - (timerMins * 1800)) / 30; + u16 timerFracSecs = ((num - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) * 100/30; + + s8 pos = 0; + + s32 mins1; + s32 mins2; + s32 mins3; + + mins1 = timerMins / 100; + mins2 = (timerMins - mins1 * 100) / 10; + mins3 = (timerMins - mins1 * 100) - (mins2 * 10); + if (mins1 != 0) { + dst[pos++] = mins1; + } else { + dst[pos++] = DIALOG_CHAR_SPACE; + } + if (mins2 != 0 || mins1 != 0) { + dst[pos++] = mins2; + } else { + dst[pos++] = DIALOG_CHAR_SPACE; + } + dst[pos++] = mins3; + dst[pos++] = 0x3E; + + s32 secs1 = timerSecs / 10; + s32 secs2 = (timerSecs - secs1 * 10); + dst[pos++] = secs1; + dst[pos++] = secs2; + dst[pos++] = 0x3E; + + s32 fracSecs1 = timerFracSecs / 10; + s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); + dst[pos++] = fracSecs1; + dst[pos++] = fracSecs2; + dst[pos] = DIALOG_CHAR_TERMINATOR; +} + +void time_trial_int_to_str_total(u32 num, u8 *dst) { + // Assumes a cap of <10000 minutes + u16 timerMins = num / 1800; + u16 timerSecs = (num - (timerMins * 1800)) / 30; + u16 timerFracSecs = ((num - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) * 100/30; + + s8 pos = 0; + + s32 mins1; + s32 mins2; + s32 mins3; + s32 mins4; + + mins1 = timerMins / 1000; + mins2 = (timerMins - mins1 * 1000) / 100; + mins3 = ((timerMins - mins1 * 1000) - (mins2 * 100)) / 10; + mins4 = (timerMins - mins1 * 1000) - (mins2 * 100) - (mins3 * 10); + if (mins1 != 0) { + dst[pos++] = mins1; + } else { + dst[pos++] = DIALOG_CHAR_SPACE; + } + if (mins2 != 0 || mins1 != 0) { + dst[pos++] = mins2; + } else { + dst[pos++] = DIALOG_CHAR_SPACE; + } + if (mins3 != 0 || mins2 != 0 || mins1 != 0) { + dst[pos++] = mins3; + } else { + dst[pos++] = DIALOG_CHAR_SPACE; + } + dst[pos++] = mins4; + dst[pos++] = 0x3E; + + s32 secs1 = timerSecs / 10; + s32 secs2 = (timerSecs - secs1 * 10); + dst[pos++] = secs1; + dst[pos++] = secs2; + dst[pos++] = 0x3E; + + s32 fracSecs1 = timerFracSecs / 10; + s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); + dst[pos++] = fracSecs1; + dst[pos++] = fracSecs2; + dst[pos] = DIALOG_CHAR_TERMINATOR; +} + s16 get_dialog_id(void) { return gDialogID; } @@ -2434,6 +2548,25 @@ void render_pause_castle_menu_box(s16 x, s16 y) { gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); } +void time_trial_render_pause_castle_menu_box(void) { + create_dl_translation_matrix(MENU_MTX_PUSH, 16, 194, 0); // position from bottom-left + create_dl_scale_matrix(MENU_MTX_NOPUSH, 2.215f, 1.925f, 1.0f); // 2.2*130=286px wide, 1.925*80=154px high # 2.21538 + gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 105); + gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box); + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); + + create_dl_translation_matrix(MENU_MTX_PUSH, 166, 198, 0); + create_dl_rotation_matrix(MENU_MTX_NOPUSH, DEFAULT_DIALOG_BOX_ANGLE, 0, 0, 1.0f); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); + gSPDisplayList(gDisplayListHead++, dl_draw_triangle); + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); + + create_dl_translation_matrix(MENU_MTX_PUSH, 151, 36, 0); + create_dl_rotation_matrix(MENU_MTX_NOPUSH, 270.0f, 0, 0, 1.0f); + gSPDisplayList(gDisplayListHead++, dl_draw_triangle); + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); +} + void highlight_last_course_complete_stars(void) { u8 courseDone; @@ -2466,6 +2599,22 @@ void print_hud_pause_colorful_str(void) { gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); } +void time_trial_print_hud_pause_colorful_str(void) { + u8 textPause[] = { TEXT_PAUSE }; + + gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); + +#ifdef VERSION_EU + print_hud_lut_string(HUD_LUT_GLOBAL, get_str_x_pos_from_center_scale( + SCREEN_WIDTH / 2, textPause, 12.0f), 0, textPause); +#else + print_hud_lut_string(HUD_LUT_GLOBAL, 123, 15, textPause); +#endif + + gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); +} + void render_pause_castle_course_stars(s16 x, s16 y, s16 fileNum, s16 courseNum) { s16 hasStar = 0; @@ -2506,6 +2655,114 @@ void render_pause_castle_course_stars(s16 x, s16 y, s16 fileNum, s16 courseNum) print_generic_string(x + 14, y + 13, str); } +void time_trial_render_pause_castle_course_stars(s16 fileNum, s16 courseNum) { + s16 hasStar = 0; + + u8 textStar[] = { TEXT_STAR }; + u8 textUnfilledStar[] = { TEXT_UNFILLED_STAR }; + + u8 starFlags = save_file_get_star_flags(fileNum, courseNum); + + u16 nextStar = 0; + + if (starFlags & 0x40) { + print_generic_string(190, 72, textStar); + } else { + print_generic_string(190, 72, textUnfilledStar); + } + + while (hasStar != 6) { + if (starFlags & (1 << nextStar)) { + print_generic_string(88+(144*(nextStar/3)), 144-24*(nextStar%3), textStar); + hasStar++; + } else { + print_generic_string(88+(144*(nextStar/3)), 144-24*(nextStar%3), textUnfilledStar); + } + nextStar++; + } +} + +void time_trial_render_pause_castle_secret_stars(s16 fileNum) { + u8 textStar[] = { TEXT_STAR }; + u8 textUnfilledStar[] = { TEXT_UNFILLED_STAR }; + + u8 starFlags = save_file_get_star_flags(fileNum, 18); + if (starFlags & 0x01) { + print_generic_string(88, 144, textStar); + } else { + print_generic_string(88, 144, textUnfilledStar); + } + if (starFlags & 0x02) { + print_generic_string(88, 120, textStar); + } else { + print_generic_string(88, 120, textUnfilledStar); + } + starFlags = save_file_get_star_flags(fileNum, 23); + if (starFlags & 0x01) { + print_generic_string(88, 96, textStar); + } else { + print_generic_string(88, 96, textUnfilledStar); + } + starFlags = save_file_get_star_flags(fileNum, 20); + if (starFlags & 0x01) { + print_generic_string(232, 144, textStar); + } else { + print_generic_string(232, 144, textUnfilledStar); + } + starFlags = save_file_get_star_flags(fileNum, 21); + if (starFlags & 0x01) { + print_generic_string(232, 120, textStar); + } else { + print_generic_string(232, 120, textUnfilledStar); + } + starFlags = save_file_get_star_flags(fileNum, 19); + if (starFlags & 0x01) { + print_generic_string(232, 96, textStar); + } else { + print_generic_string(232, 96, textUnfilledStar); + } + starFlags = save_file_get_star_flags(fileNum, 22); + if (starFlags & 0x01) { + print_generic_string(190, 72, textStar); + } else { + print_generic_string(190, 72, textUnfilledStar); + } +} + +void time_trial_render_pause_castle_bowser_stars(s16 fileNum) { + u8 textStar[] = { TEXT_STAR }; + u8 textUnfilledStar[] = { TEXT_UNFILLED_STAR }; + + u8 starFlags = save_file_get_star_flags(fileNum, 15); + if (starFlags & 0x01) { + print_generic_string(88, 144, textStar); + } else { + print_generic_string(88, 144, textUnfilledStar); + } + starFlags = save_file_get_star_flags(fileNum, 16); + if (starFlags & 0x01) { + print_generic_string(88, 120, textStar); + } else { + print_generic_string(88, 120, textUnfilledStar); + } + starFlags = save_file_get_star_flags(fileNum, 17); + if (starFlags & 0x01) { + print_generic_string(88, 96, textStar); + } else { + print_generic_string(88, 96, textUnfilledStar); + } + if (save_file_get_flags() & SAVE_FLAG_HAVE_KEY_1) { + print_generic_string(232, 144, textStar); + } else { + print_generic_string(232, 144, textUnfilledStar); + } + if (save_file_get_flags() & SAVE_FLAG_HAVE_KEY_2) { + print_generic_string(232, 120, textStar); + } else { + print_generic_string(232, 120, textUnfilledStar); + } +} + void render_pause_castle_main_strings(s16 x, s16 y) { #ifdef VERSION_EU void **courseNameTbl; @@ -2597,6 +2854,352 @@ void render_pause_castle_main_strings(s16 x, s16 y) { gSPDisplayList(gDisplayListHead++, dl_ia_text_end); } +void time_trial_render_pause_castle_times(void) { +#ifdef VERSION_EU + u8 textCoin[] = { TEXT_COIN }; + u8 textX[] = { TEXT_VARIABLE_X }; +#else + u8 textCoin[] = { TEXT_COIN_X }; +#endif + + u8 textStarWord[] = { TEXT_TIME_TRIAL_STAR }; + u8 textNum1[] = { TEXT_TIME_TRIAL_1 }; + u8 textNum2[] = { TEXT_TIME_TRIAL_2 }; + u8 textNum3[] = { TEXT_TIME_TRIAL_3 }; + u8 textNum4[] = { TEXT_TIME_TRIAL_4 }; + u8 textNum5[] = { TEXT_TIME_TRIAL_5 }; + u8 textNum6[] = { TEXT_TIME_TRIAL_6 }; + u8 textCourse[] = { TEXT_TIME_TRIAL_COURSE }; + u8 textTotal[] = { TEXT_TIME_TRIAL_TOTAL }; + u8 timeStrVal[8]; + u8 totalTimeStrVal[16]; + + print_generic_string(40, 144, textStarWord); + print_generic_string(70, 144, textNum1); + u16 time1 = time_trial_save_file_get_time(gDialogLineNum, 0); + time_trial_int_to_str(time1, timeStrVal); + print_generic_string(100, 144, timeStrVal); + + print_generic_string(40, 120, textStarWord); + print_generic_string(70, 120, textNum2); + u16 time2 = time_trial_save_file_get_time(gDialogLineNum, 1); + time_trial_int_to_str(time2, timeStrVal); + print_generic_string(100, 120, timeStrVal); + + print_generic_string(40, 96, textStarWord); + print_generic_string(70, 96, textNum3); + u16 time3 = time_trial_save_file_get_time(gDialogLineNum, 2); + time_trial_int_to_str(time3, timeStrVal); + print_generic_string(100, 96, timeStrVal); + + print_generic_string(184, 144, textStarWord); + print_generic_string(214, 144, textNum4); + u16 time4 = time_trial_save_file_get_time(gDialogLineNum, 3); + time_trial_int_to_str(time4, timeStrVal); + print_generic_string(244, 144, timeStrVal); + + print_generic_string(184, 120, textStarWord); + print_generic_string(214, 120, textNum5); + u16 time5 = time_trial_save_file_get_time(gDialogLineNum, 4); + time_trial_int_to_str(time5, timeStrVal); + print_generic_string(244, 120, timeStrVal); + + print_generic_string(184, 96, textStarWord); + print_generic_string(214, 96, textNum6); + u16 time6 = time_trial_save_file_get_time(gDialogLineNum, 5); + time_trial_int_to_str(time6, timeStrVal); + print_generic_string(244, 96, timeStrVal); + + print_generic_string(112, 72, textStarWord); + print_generic_string(142, 72, textCoin); + u16 timeCoin = time_trial_save_file_get_time(gDialogLineNum, 6); + time_trial_int_to_str(timeCoin, timeStrVal); + print_generic_string(202, 72, timeStrVal); + +#ifdef VERSION_EU + print_generic_string(152, 72, textX); +#endif + print_generic_string(40, 48, textCourse); + time_trial_int_to_str_course(time1+time2+time3+time4+time5+time6+timeCoin, totalTimeStrVal); + print_generic_string(82, 48, totalTimeStrVal); + print_generic_string(184, 48, textTotal); + time_trial_int_to_str_total(time_trial_save_file_get_total_time(), totalTimeStrVal); + print_generic_string(226, 48, totalTimeStrVal); + + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + +void time_trial_render_pause_secret_times(void) { + u8 textPSS1[] = { TEXT_TIME_TRIAL_PSS1 }; + u8 textPSS2[] = { TEXT_TIME_TRIAL_PSS2 }; + u8 textSA[] = { TEXT_TIME_TRIAL_SA }; + u8 textTotWC[] = { TEXT_TIME_TRIAL_TOTWC }; + u8 textVCUtM[] = { TEXT_TIME_TRIAL_VCUTM }; + u8 textCotMC[] = { TEXT_TIME_TRIAL_COTMC }; + u8 textWMOtR[] = { TEXT_TIME_TRIAL_WMOTR }; + u8 textCourse[] = { TEXT_TIME_TRIAL_COURSE }; + u8 textTotal[] = { TEXT_TIME_TRIAL_TOTAL }; + u8 timeStrVal[8]; + u8 totalTimeStrVal[16]; + + print_generic_string(40, 144, textPSS1); + u16 time1 = time_trial_save_file_get_time(18, 0); + time_trial_int_to_str(time1, timeStrVal); + print_generic_string(100, 144, timeStrVal); + + print_generic_string(40, 120, textPSS2); + u16 time2 = time_trial_save_file_get_time(18, 1); + time_trial_int_to_str(time2, timeStrVal); + print_generic_string(100, 120, timeStrVal); + + print_generic_string(40, 96, textSA); + u16 time3 = time_trial_save_file_get_time(23, 0); + time_trial_int_to_str(time3, timeStrVal); + print_generic_string(100, 96, timeStrVal); + + print_generic_string(184, 144, textTotWC); + u16 time4 = time_trial_save_file_get_time(20, 0); + time_trial_int_to_str(time4, timeStrVal); + print_generic_string(244, 144, timeStrVal); + + print_generic_string(184, 120, textVCUtM); + u16 time5 = time_trial_save_file_get_time(21, 0); + time_trial_int_to_str(time5, timeStrVal); + print_generic_string(244, 120, timeStrVal); + + print_generic_string(184, 96, textCotMC); + u16 time6 = time_trial_save_file_get_time(19, 0); + time_trial_int_to_str(time6, timeStrVal); + print_generic_string(244, 96, timeStrVal); + + print_generic_string(112, 72, textWMOtR); + u16 time7 = time_trial_save_file_get_time(22, 0); + time_trial_int_to_str(time7, timeStrVal); + print_generic_string(202, 72, timeStrVal); + + print_generic_string(40, 48, textCourse); + time_trial_int_to_str_course(time1+time2+time3+time4+time5+time6+time7, totalTimeStrVal); + print_generic_string(82, 48, totalTimeStrVal); + print_generic_string(184, 48, textTotal); + time_trial_int_to_str_total(time_trial_save_file_get_total_time(), totalTimeStrVal); + print_generic_string(226, 48, totalTimeStrVal); + + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + +void time_trial_render_pause_bowser_times(void) { + u8 textStarWord[] = { TEXT_TIME_TRIAL_STAR }; + u8 textKeyWord[] = { TEXT_TIME_TRIAL_KEY }; + u8 textFinal[] = { TEXT_TIME_TRIAL_FINAL }; + u8 textNum1[] = { TEXT_TIME_TRIAL_1 }; + u8 textNum2[] = { TEXT_TIME_TRIAL_2 }; + u8 textNum3[] = { TEXT_TIME_TRIAL_3 }; + u8 textCourse[] = { TEXT_TIME_TRIAL_COURSE }; + u8 textTotal[] = { TEXT_TIME_TRIAL_TOTAL }; + u8 timeStrVal[8]; + u8 totalTimeStrVal[16]; + + print_generic_string(40, 144, textStarWord); + print_generic_string(70, 144, textNum1); + u16 time1 = time_trial_save_file_get_time(15, 0); + time_trial_int_to_str(time1, timeStrVal); + print_generic_string(100, 144, timeStrVal); + + print_generic_string(40, 120, textStarWord); + print_generic_string(70, 120, textNum2); + u16 time2 = time_trial_save_file_get_time(16, 0); + time_trial_int_to_str(time2, timeStrVal); + print_generic_string(100, 120, timeStrVal); + + print_generic_string(40, 96, textStarWord); + print_generic_string(70, 96, textNum3); + u16 time3 = time_trial_save_file_get_time(17, 0); + time_trial_int_to_str(time3, timeStrVal); + print_generic_string(100, 96, timeStrVal); + + print_generic_string(184, 144, textKeyWord); + print_generic_string(208, 144, textNum1); + u16 time4 = time_trial_save_file_get_time(15, 1); + time_trial_int_to_str(time4, timeStrVal); + print_generic_string(244, 144, timeStrVal); + + print_generic_string(184, 120, textKeyWord); + print_generic_string(208, 120, textNum2); + u16 time5 = time_trial_save_file_get_time(16, 1); + time_trial_int_to_str(time5, timeStrVal); + print_generic_string(244, 120, timeStrVal); + + print_generic_string(184, 96, textFinal); + u16 time6 = time_trial_save_file_get_time(17, 1); + time_trial_int_to_str(time6, timeStrVal); + print_generic_string(244, 96, timeStrVal); + + print_generic_string(40, 48, textCourse); + time_trial_int_to_str_course(time1+time2+time3+time4+time5+time6, totalTimeStrVal); + print_generic_string(82, 48, totalTimeStrVal); + print_generic_string(184, 48, textTotal); + time_trial_int_to_str_total(time_trial_save_file_get_total_time(), totalTimeStrVal); + print_generic_string(226, 48, totalTimeStrVal); + + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + +void time_trial_render_pause_castle_main_strings(void) { +#ifdef VERSION_EU + void **courseNameTbl; +#else + void **courseNameTbl = segmented_to_virtual(seg2_course_name_table); +#endif + + void *courseName; + + u8 strVal[8]; + s16 starNum = gDialogLineNum; + +#ifdef VERSION_EU + switch (gInGameLanguage) { + case LANGUAGE_ENGLISH: + courseNameTbl = segmented_to_virtual(course_name_table_eu_en); + break; + case LANGUAGE_FRENCH: + courseNameTbl = segmented_to_virtual(course_name_table_eu_fr); + break; + case LANGUAGE_GERMAN: + courseNameTbl = segmented_to_virtual(course_name_table_eu_de); + break; + } +#endif + + handle_menu_scrolling(MENU_SCROLL_VERTICAL, &gDialogLineNum, -1, COURSE_STAGES_COUNT + 2); + + if (gDialogLineNum == COURSE_STAGES_COUNT + 2) { + gDialogLineNum = 0; + } + + if (gDialogLineNum == -1) { + gDialogLineNum = COURSE_STAGES_COUNT + 1; + } + + if (gDialogLineNum < COURSE_STAGES_COUNT) { + while (save_file_get_course_star_count(gCurrSaveFileNum - 1, gDialogLineNum) == 0) { + if (gDialogLineNum >= starNum) { + gDialogLineNum++; + } else { + gDialogLineNum--; + } + + if (gDialogLineNum == COURSE_STAGES_COUNT || gDialogLineNum == -1) { + gDialogLineNum = COURSE_STAGES_COUNT; + break; + } + } + } + + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); + + u8 bowserStr[8] = { TEXT_TIME_TRIAL_BOWSER }; + + switch (gDialogLineNum) { + case COURSE_STAGES_COUNT: + courseName = segmented_to_virtual(courseNameTbl[COURSE_MAX]); + time_trial_render_pause_castle_secret_stars(gCurrSaveFileNum - 1); +#ifdef VERSION_EU + print_generic_string(get_str_x_pos_from_center(155, courseName, 10.0f), 168, courseName); +#else + print_generic_string(95, 168, courseName); +#endif + time_trial_render_pause_secret_times(); + break; + case COURSE_STAGES_COUNT + 1: + courseName = bowserStr; + time_trial_render_pause_castle_bowser_stars(gCurrSaveFileNum - 1); +#ifdef VERSION_EU + print_generic_string(get_str_x_pos_from_center(155, courseName, 10.0f), 168, courseName); +#else + print_generic_string(143, 168, courseName); +#endif + time_trial_render_pause_bowser_times(); + break; + default: + courseName = segmented_to_virtual(courseNameTbl[gDialogLineNum]); + time_trial_render_pause_castle_course_stars(gCurrSaveFileNum - 1, gDialogLineNum); + int_to_str(save_file_get_course_coin_score(gCurrSaveFileNum - 1, gDialogLineNum), strVal); + print_generic_string(162, 72, strVal); +#ifdef VERSION_EU + print_generic_string(87, 168, courseName); +#else + print_generic_string(95, 168, courseName); +#endif + time_trial_render_pause_castle_times(); + break; + } +} + +void time_trial_render_pause_timer_toggle(void) { + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); + + u8 timerToggleText[32] = { TEXT_TIME_TRIAL_TIMER_TOGGLE }; + print_generic_string(88, 20, timerToggleText); + + if (gPlayer3Controller->buttonPressed & (U_CBUTTONS | D_CBUTTONS)) { + gHudDisplay.flags ^= HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; + play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs); + } + + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + +void time_trial_check_input_for_course_times_reset(void) { + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); + + u8 resetCodeStr[] = { TEXT_TIME_TRIAL_RESET }; + print_generic_string(64, 8, resetCodeStr); + + if (gPlayer3Controller->buttonPressed & timeTrialResetIndexCombo[gTimeTrialResetIndex]) { + gTimeTrialResetIndex++; + if (gTimeTrialResetIndex >= 10) { + // TODO: actually reset times here + switch (gDialogLineNum) { + case COURSE_STAGES_COUNT: + time_trial_save_file_set_time(18, 0, 17999, 1); + time_trial_save_file_set_time(18, 1, 17999, 1); + time_trial_save_file_set_time(23, 0, 17999, 1); + time_trial_save_file_set_time(20, 0, 17999, 1); + time_trial_save_file_set_time(21, 0, 17999, 1); + time_trial_save_file_set_time(19, 0, 17999, 1); + time_trial_save_file_set_time(22, 0, 17999, 1); + break; + case COURSE_STAGES_COUNT + 1: + time_trial_save_file_set_time(15, 0, 17999, 1); + time_trial_save_file_set_time(15, 1, 17999, 1); + time_trial_save_file_set_time(16, 0, 17999, 1); + time_trial_save_file_set_time(16, 1, 17999, 1); + time_trial_save_file_set_time(17, 0, 17999, 1); + time_trial_save_file_set_time(17, 1, 17999, 1); + break; + default: + time_trial_save_file_set_time(gDialogLineNum, 0, 17999, 1); + time_trial_save_file_set_time(gDialogLineNum, 1, 17999, 1); + time_trial_save_file_set_time(gDialogLineNum, 2, 17999, 1); + time_trial_save_file_set_time(gDialogLineNum, 3, 17999, 1); + time_trial_save_file_set_time(gDialogLineNum, 4, 17999, 1); + time_trial_save_file_set_time(gDialogLineNum, 5, 17999, 1); + time_trial_save_file_set_time(gDialogLineNum, 6, 17999, 1); + break; + } + play_sound(SOUND_MENU_LET_GO_MARIO_FACE, gDefaultSoundArgs); + gTimeTrialResetIndex = 0; + } + } else if (gPlayer3Controller->buttonPressed > 0) { + gTimeTrialResetIndex = 0; + } + + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + s8 gCourseCompleteCoinsEqual = 0; s32 gCourseDoneMenuTimer = 0; s32 gCourseCompleteCoins = 0; @@ -2634,6 +3237,7 @@ s16 render_pause_courses_and_castle(void) { shade_screen(); render_pause_my_score_coins(); render_pause_red_coins(); + time_trial_render_pause_timer_toggle(); /* Added support for the "Exit course at any time" cheat */ if ((gMarioStates[0].action & ACT_FLAG_PAUSE_EXIT) || (Cheats.EnableCheats && Cheats.ExitAnywhere)) { @@ -2663,9 +3267,13 @@ s16 render_pause_courses_and_castle(void) { break; case DIALOG_STATE_HORIZONTAL: shade_screen(); - print_hud_pause_colorful_str(); - render_pause_castle_menu_box(160, 143); - render_pause_castle_main_strings(104, 60); + // print_hud_pause_colorful_str(); + // render_pause_castle_menu_box(160, 143); + // render_pause_castle_main_strings(104, 60); + time_trial_print_hud_pause_colorful_str(); + time_trial_render_pause_castle_menu_box(); + time_trial_render_pause_castle_main_strings(); + time_trial_check_input_for_course_times_reset(); #ifdef VERSION_EU if (gPlayer3Controller->buttonPressed & (A_BUTTON | Z_TRIG | START_BUTTON)) diff --git a/src/game/interaction.c b/src/game/interaction.c index 7a9c5203b0..73a7b3af8e 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -24,6 +24,8 @@ #include "sound_init.h" #include "thread6.h" +#include "hud.h" + #define INT_GROUND_POUND_OR_TWIRL (1 << 0) // 0x01 #define INT_PUNCH (1 << 1) // 0x02 #define INT_KICK (1 << 2) // 0x04 @@ -802,6 +804,11 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O starIndex = (o->oBehParams >> 24) & 0x1F; save_file_collect_star_or_key(m->numCoins, starIndex); + if ((!noExit) && (gCurrLevelNum == LEVEL_BOWSER_1 || gCurrLevelNum == LEVEL_BOWSER_2 || gCurrLevelNum == LEVEL_BOWSER_3)) { + time_trial_save_file_set_time(gCurrCourseNum - 1, 1, gHudDisplay.timeTrialTimer, 0); + } else { + time_trial_save_file_set_time(gCurrCourseNum - 1, starIndex, gHudDisplay.timeTrialTimer, 0); + } m->numStars = save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1); @@ -809,6 +816,7 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O if (!noExit) { drop_queued_background_music(); fadeout_level_music(126); + sTimeTrialTimerRunning = 0; } play_sound(SOUND_MENU_STAR_SOUND, m->marioObj->header.gfx.cameraToObject); diff --git a/src/game/level_update.c b/src/game/level_update.c index 72a6a6073c..ef0fe50bb7 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -171,7 +171,9 @@ s32 sDelayedWarpArg; s16 unusedEULevelUpdateBss1; #endif s8 sTimerRunning; +s8 sTimeTrialTimerRunning; s8 gShouldNotPlayCastleMusic; +s16 sLastLevelNum; struct MarioState *gMarioState = &gMarioStates[0]; u8 unused1[4] = { 0 }; @@ -211,6 +213,8 @@ u32 pressed_pause(void) { if (!intangible && !val4 && !gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE && (gPlayer1Controller->buttonPressed & START_BUTTON)) { + gTimeTrialResetIndex = 0; + time_trial_verify_times(); return TRUE; } @@ -890,8 +894,10 @@ void update_hud_values(void) { if (gCurrCourseNum > 0) { gHudDisplay.flags |= HUD_DISPLAY_FLAG_COIN_COUNT; + gHudDisplay.flags |= HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; } else { gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_COIN_COUNT; + gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; } if (gHudDisplay.coins < gMarioState->numCoins) { @@ -980,6 +986,10 @@ s32 play_mode_normal(void) { gHudDisplay.timer += 1; } + if (sTimeTrialTimerRunning && gHudDisplay.timeTrialTimer < 17999) { + gHudDisplay.timeTrialTimer += 1; + } + area_update_objects(); update_hud_values(); @@ -1225,6 +1235,12 @@ s32 init_level(void) { sound_banks_disable(2, 0x0330); } + // gCurrAreaIndex is > 1 for certain areas you can spawn directly into, like LLL's volcano or SSL's pyramid + if ((sLastLevelNum == LEVEL_CASTLE || sLastLevelNum == LEVEL_CASTLE_GROUNDS || sLastLevelNum == LEVEL_CASTLE_COURTYARD) && (gCurrAreaIndex == 1 || gCurrLevelNum == LEVEL_THI)) + gHudDisplay.timeTrialTimer = 0; + sTimeTrialTimerRunning = !(gCurrLevelNum == LEVEL_CASTLE || gCurrLevelNum == LEVEL_CASTLE_GROUNDS || gCurrLevelNum == LEVEL_CASTLE_COURTYARD); + sLastLevelNum = gCurrLevelNum; + return 1; } diff --git a/src/game/level_update.h b/src/game/level_update.h index ecf9c3a35e..3ee6fa79dc 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -89,6 +89,9 @@ extern s32 sDelayedWarpArg; extern u8 unused4[2]; extern s8 sTimerRunning; +extern s8 sTimeTrialTimerRunning; +extern u8 gTimeTrialResetIndex; + struct HudDisplay { /*0x00*/ s16 lives; /*0x02*/ s16 coins; @@ -97,6 +100,7 @@ struct HudDisplay { /*0x08*/ s16 keys; /*0x0A*/ s16 flags; /*0x0C*/ u16 timer; + /*0x0E*/ u16 timeTrialTimer; }; extern struct HudDisplay gHudDisplay; @@ -110,10 +114,11 @@ enum HUDDisplayFlag { HUD_DISPLAY_FLAG_KEYS = 0x0010, HUD_DISPLAY_FLAG_UNKNOWN_0020 = 0x0020, HUD_DISPLAY_FLAG_TIMER = 0x0040, + HUD_DISPLAY_FLAG_TIME_TRIAL_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 | HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER }; diff --git a/src/game/save_file.c b/src/game/save_file.c index 45ac71f4a8..2344d7d0b5 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -72,6 +72,9 @@ static inline void bswap_menudata(struct MainMenuSaveData *data) { for (int i = 0; i < NUM_SAVE_FILES; ++i) data->coinScoreAges[i] = BSWAP32(data->coinScoreAges[i]); data->soundMode = BSWAP16(data->soundMode); + for (int i = 0; i < 118; ++i) + data->timeTrialTimes[i] = BSWAP16(data->timeTrialTimes[i]); + data->timeTrialTotalTime = BSWAP32(data->timeTrialTotalTime); #ifdef VERSION_EU data->language = BSWAP16(data->language); #endif @@ -248,6 +251,11 @@ static void wipe_main_menu_data(void) { gSaveBuffer.menuData[0].coinScoreAges[1] = 0x2AAAAAAA; gSaveBuffer.menuData[0].coinScoreAges[2] = 0x15555555; + // Set all time trial times to the max amount + for (u8 i = 0; i < 118; i++) + gSaveBuffer.menuData[0].timeTrialTimes[i] = 17999; + gSaveBuffer.menuData[0].timeTrialTotalTime = 17999 * 118; + gMainMenuDataModified = TRUE; save_main_menu_data(); } @@ -758,4 +766,114 @@ s32 check_warp_checkpoint(struct WarpNode *warpNode) { } return isWarpCheckpointActive; +} + +void time_trial_save_file_set_time(s32 courseIndex, s16 starIndex, u16 time, u8 forceSet) { + u8 timeIndex; + u8 forceSave = 0; + switch (courseIndex) { + case 15: + timeIndex = 112 + (3*starIndex); + break; + case 16: + timeIndex = 113 + (3*starIndex); + break; + case 17: + timeIndex = 114 + (3*starIndex); + // Save times after final Bowser fight + if (starIndex == 1) { + forceSave = 1; + } + break; + case 18: + timeIndex = 105 + starIndex; + break; + case 23: + timeIndex = 107; + break; + case 20: + timeIndex = 108; + break; + case 21: + timeIndex = 109; + break; + case 19: + timeIndex = 110; + break; + case 22: + timeIndex = 111; + break; + default: + timeIndex = courseIndex*7 + starIndex; + break; + } + if (forceSet || (gSaveBuffer.menuData[0].timeTrialTimes[timeIndex] > time)) { + gSaveBuffer.menuData[0].timeTrialTimes[timeIndex] = time; + } + time_trial_update_total_time(forceSave); +} + +void time_trial_update_total_time(u8 forceSave) { + gSaveBuffer.menuData[0].timeTrialTotalTime = 0; + for (u8 i = 0; i < 118; i++) { + gSaveBuffer.menuData[0].timeTrialTotalTime += gSaveBuffer.menuData[0].timeTrialTimes[i]; + } + gMainMenuDataModified = TRUE; + if (forceSave) { + save_main_menu_data(); + } +} + +u16 time_trial_save_file_get_time(s32 courseIndex, s16 starIndex) { + u8 timeIndex; + switch (courseIndex) { + case 15: + timeIndex = 112 + (3*starIndex); + break; + case 16: + timeIndex = 113 + (3*starIndex); + break; + case 17: + timeIndex = 114 + (3*starIndex); + break; + case 18: + timeIndex = 105 + starIndex; + break; + case 23: + timeIndex = 107; + break; + case 20: + timeIndex = 108; + break; + case 21: + timeIndex = 109; + break; + case 19: + timeIndex = 110; + break; + case 22: + timeIndex = 111; + break; + default: + timeIndex = courseIndex*7 + starIndex; + break; + } + return gSaveBuffer.menuData[0].timeTrialTimes[timeIndex]; +} + +u32 time_trial_save_file_get_total_time(void) { + return gSaveBuffer.menuData[0].timeTrialTotalTime; +} + +// If any times are equal to 0 (which is how they're initialized) or above the max allowed value, reset all times +void time_trial_verify_times(void) { + for (u8 i = 0; i < 118; i++) { + if (gSaveBuffer.menuData[0].timeTrialTimes[i] == 0 || gSaveBuffer.menuData[0].timeTrialTimes[i] > 17999) { + for (u8 j = 0; j < 118; j++) { + gSaveBuffer.menuData[0].timeTrialTimes[j] = 17999; + time_trial_update_total_time(0); + } + break; + } + } } \ No newline at end of file diff --git a/src/game/save_file.h b/src/game/save_file.h index c292a15624..273ee3f05e 100644 --- a/src/game/save_file.h +++ b/src/game/save_file.h @@ -8,7 +8,7 @@ #include "course_table.h" -#define EEPROM_SIZE 0x200 +#define EEPROM_SIZE 0x800 // increased from 0x200 for time trial times #define NUM_SAVE_FILES 4 struct SaveBlockSignature @@ -53,11 +53,14 @@ struct MainMenuSaveData u32 coinScoreAges[NUM_SAVE_FILES]; u16 soundMode; + u16 timeTrialTimes[118]; + u32 timeTrialTotalTime; + #ifdef VERSION_EU u16 language; -#define SUBTRAHEND 8 +#define SUBTRAHEND 252 // was 8 #else -#define SUBTRAHEND 6 +#define SUBTRAHEND 250 // was 6 #endif // Pad to match the EEPROM size of 0x200 (10 bytes on JP/US, 8 bytes on EU) @@ -149,6 +152,12 @@ void disable_warp_checkpoint(void); void check_if_should_set_warp_checkpoint(struct WarpNode *warpNode); s32 check_warp_checkpoint(struct WarpNode *warpNode); +void time_trial_save_file_set_time(s32 courseIndex, s16 starIndex, u16 time, u8 forceSet); +void time_trial_update_total_time(u8 forceSave); +u16 time_trial_save_file_get_time(s32 courseIndex, s16 starIndex); +u32 time_trial_save_file_get_total_time(void); +void time_trial_verify_times(void); + #ifdef VERSION_EU enum EuLanguages { LANGUAGE_ENGLISH, diff --git a/src/game/text_save.inc.h b/src/game/text_save.inc.h index a9ce6c2aa6..e3924b65c6 100644 --- a/src/game/text_save.inc.h +++ b/src/game/text_save.inc.h @@ -117,6 +117,12 @@ static s32 write_text_save(s32 fileIndex) { printf("Undefined sound mode!"); return -1; } + fprintf(file, "time_trial_times = "); + for (i = 0; i < 118; i++) { + fprintf(file, "%05d", menudata->timeTrialTimes[i]); + } + fprintf(file, "\n"); + fprintf(file, "time_trial_total_time = %d\n", menudata->timeTrialTotalTime); fprintf(file, "\n[flags]\n"); for (i = 1; i < NUM_FLAGS; i++) { @@ -240,6 +246,25 @@ static s32 read_text_save(s32 fileIndex) { printf("Invalid 'menu:sound_mode' flag!\n"); return -1; } + value = ini_get(savedata, "menu", "time_trial_times"); + if (value) { + u16 currTTValue; + char subString[6]; + for (i = 0; i < 118; i++) { + for (u8 j = 0; j < 5; j++) { + subString[j] = value[i*5+j]; + } + subString[5] = '\0'; + sscanf(subString, "%d", &currTTValue); + gSaveBuffer.menuData[0].timeTrialTimes[i] = currTTValue; + } + } + value = ini_get(savedata, "menu", "time_trial_total_time"); + if (value) { + u32 tTTTValue; + sscanf(value, "%d", &tTTTValue); + gSaveBuffer.menuData[0].timeTrialTotalTime = tTTTValue; + } for (i = 1; i < NUM_FLAGS; i++) { value = ini_get(savedata, "flags", sav_flags[i]); diff --git a/src/pc/ultra_reimplementation.c b/src/pc/ultra_reimplementation.c index 0389776b9b..94a8f6ebbc 100644 --- a/src/pc/ultra_reimplementation.c +++ b/src/pc/ultra_reimplementation.c @@ -124,7 +124,7 @@ s32 osEepromProbe(UNUSED OSMesgQueue *mq) { } s32 osEepromLongRead(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) { - u8 content[512]; + u8 content[2048]; s32 ret = -1; #ifdef TARGET_WEB @@ -133,8 +133,8 @@ s32 osEepromLongRead(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) if (s && s.length === 684) { try { var binary = atob(s); - if (binary.length === 512) { - for (var i = 0; i < 512; i++) { + if (binary.length === 2048) { + for (var i = 0; i < 2048; i++) { HEAPU8[$0 + i] = binary.charCodeAt(i); } return 1; @@ -152,7 +152,7 @@ s32 osEepromLongRead(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) if (fp == NULL) { return -1; } - if (fs_read(fp, content, 512) == 512) { + if (fs_read(fp, content, 2048) == 2048) { memcpy(buffer, content + address * 8, nbytes); ret = 0; } @@ -162,16 +162,16 @@ s32 osEepromLongRead(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) } s32 osEepromLongWrite(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) { - u8 content[512] = {0}; - if (address != 0 || nbytes != 512) { - osEepromLongRead(mq, 0, content, 512); + u8 content[2048] = {0}; + if (address != 0 || nbytes != 2048) { + osEepromLongRead(mq, 0, content, 2048); } memcpy(content + address * 8, buffer, nbytes); #ifdef TARGET_WEB EM_ASM({ var str = ""; - for (var i = 0; i < 512; i++) { + for (var i = 0; i < 2048; i++) { str += String.fromCharCode(HEAPU8[$0 + i]); } localStorage.sm64_save_file = btoa(str); @@ -182,7 +182,7 @@ s32 osEepromLongWrite(UNUSED OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes if (fp == NULL) { return -1; } - s32 ret = fwrite(content, 1, 512, fp) == 512 ? 0 : -1; + s32 ret = fwrite(content, 1, 2048, fp) == 2048 ? 0 : -1; fclose(fp); #endif return ret; From ad19b3fd289197c1e94148fc2937b666dcbab9f0 Mon Sep 17 00:00:00 2001 From: GateGuy <57763469+GateGuy@users.noreply.github.com> Date: Thu, 16 Jul 2020 00:54:37 -0400 Subject: [PATCH 2/6] Slight refactor --- src/game/level_update.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/level_update.c b/src/game/level_update.c index ef0fe50bb7..000f846b49 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -213,8 +213,6 @@ u32 pressed_pause(void) { if (!intangible && !val4 && !gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE && (gPlayer1Controller->buttonPressed & START_BUTTON)) { - gTimeTrialResetIndex = 0; - time_trial_verify_times(); return TRUE; } @@ -1008,6 +1006,8 @@ s32 play_mode_normal(void) { } else if (sTransitionTimer != 0) { set_play_mode(PLAY_MODE_CHANGE_AREA); } else if (pressed_pause()) { + gTimeTrialResetIndex = 0; + time_trial_verify_times(); lower_background_noise(1); cancel_rumble(); gCameraMovementFlags |= CAM_MOVE_PAUSE_SCREEN; From dd1ff56a6d2fcf9feda152b115dc2cc4d2d3f1db Mon Sep 17 00:00:00 2001 From: GateGuy <57763469+GateGuy@users.noreply.github.com> Date: Thu, 16 Jul 2020 13:55:24 -0400 Subject: [PATCH 3/6] Refactored for consistency with N64 patch --- src/game/ingame_menu.c | 100 ++++++++++++++++++----------------------- src/game/save_file.c | 13 ++++-- 2 files changed, 53 insertions(+), 60 deletions(-) diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index d1c6685f97..5fd0b51005 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -908,18 +908,18 @@ void time_trial_int_to_str(u16 num, u8 *dst) { u16 timerMins = num / 1800; u16 timerSecs = (num - (timerMins * 1800)) / 30; u16 timerFracSecs = ((num - (timerMins * 1800) - (timerSecs * 30)) & 0xFFFF) * 100/30; + s32 secs1 = timerSecs / 10; + s32 secs2 = (timerSecs - secs1 * 10); + s32 fracSecs1 = timerFracSecs / 10; + s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); dst[0] = timerMins; dst[1] = 0x3E; - s32 secs1 = timerSecs / 10; - s32 secs2 = (timerSecs - secs1 * 10); dst[2] = secs1; dst[3] = secs2; dst[4] = 0x3E; - s32 fracSecs1 = timerFracSecs / 10; - s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); dst[5] = fracSecs1; dst[6] = fracSecs2; dst[7] = DIALOG_CHAR_TERMINATOR; @@ -933,13 +933,13 @@ void time_trial_int_to_str_course(u32 num, u8 *dst) { s8 pos = 0; - s32 mins1; - s32 mins2; - s32 mins3; - - mins1 = timerMins / 100; - mins2 = (timerMins - mins1 * 100) / 10; - mins3 = (timerMins - mins1 * 100) - (mins2 * 10); + s32 mins1 = timerMins / 100; + s32 mins2 = (timerMins - mins1 * 100) / 10; + s32 mins3 = (timerMins - mins1 * 100) - (mins2 * 10); + s32 secs1 = timerSecs / 10; + s32 secs2 = (timerSecs - secs1 * 10); + s32 fracSecs1 = timerFracSecs / 10; + s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); if (mins1 != 0) { dst[pos++] = mins1; } else { @@ -952,15 +952,9 @@ void time_trial_int_to_str_course(u32 num, u8 *dst) { } dst[pos++] = mins3; dst[pos++] = 0x3E; - - s32 secs1 = timerSecs / 10; - s32 secs2 = (timerSecs - secs1 * 10); dst[pos++] = secs1; dst[pos++] = secs2; dst[pos++] = 0x3E; - - s32 fracSecs1 = timerFracSecs / 10; - s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); dst[pos++] = fracSecs1; dst[pos++] = fracSecs2; dst[pos] = DIALOG_CHAR_TERMINATOR; @@ -974,15 +968,14 @@ void time_trial_int_to_str_total(u32 num, u8 *dst) { s8 pos = 0; - s32 mins1; - s32 mins2; - s32 mins3; - s32 mins4; - - mins1 = timerMins / 1000; - mins2 = (timerMins - mins1 * 1000) / 100; - mins3 = ((timerMins - mins1 * 1000) - (mins2 * 100)) / 10; - mins4 = (timerMins - mins1 * 1000) - (mins2 * 100) - (mins3 * 10); + s32 mins1 = timerMins / 1000; + s32 mins2 = (timerMins - mins1 * 1000) / 100; + s32 mins3 = ((timerMins - mins1 * 1000) - (mins2 * 100)) / 10; + s32 mins4 = (timerMins - mins1 * 1000) - (mins2 * 100) - (mins3 * 10); + s32 secs1 = timerSecs / 10; + s32 secs2 = (timerSecs - secs1 * 10); + s32 fracSecs1 = timerFracSecs / 10; + s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); if (mins1 != 0) { dst[pos++] = mins1; } else { @@ -1000,15 +993,9 @@ void time_trial_int_to_str_total(u32 num, u8 *dst) { } dst[pos++] = mins4; dst[pos++] = 0x3E; - - s32 secs1 = timerSecs / 10; - s32 secs2 = (timerSecs - secs1 * 10); dst[pos++] = secs1; dst[pos++] = secs2; dst[pos++] = 0x3E; - - s32 fracSecs1 = timerFracSecs / 10; - s32 fracSecs2 = (timerFracSecs - fracSecs1 * 10); dst[pos++] = fracSecs1; dst[pos++] = fracSecs2; dst[pos] = DIALOG_CHAR_TERMINATOR; @@ -2873,46 +2860,46 @@ void time_trial_render_pause_castle_times(void) { u8 textTotal[] = { TEXT_TIME_TRIAL_TOTAL }; u8 timeStrVal[8]; u8 totalTimeStrVal[16]; + u16 time1 = time_trial_save_file_get_time(gDialogLineNum, 0); + u16 time2 = time_trial_save_file_get_time(gDialogLineNum, 1); + u16 time3 = time_trial_save_file_get_time(gDialogLineNum, 2); + u16 time4 = time_trial_save_file_get_time(gDialogLineNum, 3); + u16 time5 = time_trial_save_file_get_time(gDialogLineNum, 4); + u16 time6 = time_trial_save_file_get_time(gDialogLineNum, 5); + u16 timeCoin = time_trial_save_file_get_time(gDialogLineNum, 6); print_generic_string(40, 144, textStarWord); print_generic_string(70, 144, textNum1); - u16 time1 = time_trial_save_file_get_time(gDialogLineNum, 0); time_trial_int_to_str(time1, timeStrVal); print_generic_string(100, 144, timeStrVal); print_generic_string(40, 120, textStarWord); print_generic_string(70, 120, textNum2); - u16 time2 = time_trial_save_file_get_time(gDialogLineNum, 1); time_trial_int_to_str(time2, timeStrVal); print_generic_string(100, 120, timeStrVal); print_generic_string(40, 96, textStarWord); print_generic_string(70, 96, textNum3); - u16 time3 = time_trial_save_file_get_time(gDialogLineNum, 2); time_trial_int_to_str(time3, timeStrVal); print_generic_string(100, 96, timeStrVal); print_generic_string(184, 144, textStarWord); print_generic_string(214, 144, textNum4); - u16 time4 = time_trial_save_file_get_time(gDialogLineNum, 3); time_trial_int_to_str(time4, timeStrVal); print_generic_string(244, 144, timeStrVal); print_generic_string(184, 120, textStarWord); print_generic_string(214, 120, textNum5); - u16 time5 = time_trial_save_file_get_time(gDialogLineNum, 4); time_trial_int_to_str(time5, timeStrVal); print_generic_string(244, 120, timeStrVal); print_generic_string(184, 96, textStarWord); print_generic_string(214, 96, textNum6); - u16 time6 = time_trial_save_file_get_time(gDialogLineNum, 5); time_trial_int_to_str(time6, timeStrVal); print_generic_string(244, 96, timeStrVal); print_generic_string(112, 72, textStarWord); print_generic_string(142, 72, textCoin); - u16 timeCoin = time_trial_save_file_get_time(gDialogLineNum, 6); time_trial_int_to_str(timeCoin, timeStrVal); print_generic_string(202, 72, timeStrVal); @@ -2941,39 +2928,39 @@ void time_trial_render_pause_secret_times(void) { u8 textTotal[] = { TEXT_TIME_TRIAL_TOTAL }; u8 timeStrVal[8]; u8 totalTimeStrVal[16]; + u16 time1 = time_trial_save_file_get_time(18, 0); + u16 time2 = time_trial_save_file_get_time(18, 1); + u16 time3 = time_trial_save_file_get_time(23, 0); + u16 time4 = time_trial_save_file_get_time(20, 0); + u16 time5 = time_trial_save_file_get_time(21, 0); + u16 time6 = time_trial_save_file_get_time(19, 0); + u16 time7 = time_trial_save_file_get_time(22, 0); print_generic_string(40, 144, textPSS1); - u16 time1 = time_trial_save_file_get_time(18, 0); time_trial_int_to_str(time1, timeStrVal); print_generic_string(100, 144, timeStrVal); print_generic_string(40, 120, textPSS2); - u16 time2 = time_trial_save_file_get_time(18, 1); time_trial_int_to_str(time2, timeStrVal); print_generic_string(100, 120, timeStrVal); print_generic_string(40, 96, textSA); - u16 time3 = time_trial_save_file_get_time(23, 0); time_trial_int_to_str(time3, timeStrVal); print_generic_string(100, 96, timeStrVal); print_generic_string(184, 144, textTotWC); - u16 time4 = time_trial_save_file_get_time(20, 0); time_trial_int_to_str(time4, timeStrVal); print_generic_string(244, 144, timeStrVal); print_generic_string(184, 120, textVCUtM); - u16 time5 = time_trial_save_file_get_time(21, 0); time_trial_int_to_str(time5, timeStrVal); print_generic_string(244, 120, timeStrVal); print_generic_string(184, 96, textCotMC); - u16 time6 = time_trial_save_file_get_time(19, 0); time_trial_int_to_str(time6, timeStrVal); print_generic_string(244, 96, timeStrVal); print_generic_string(112, 72, textWMOtR); - u16 time7 = time_trial_save_file_get_time(22, 0); time_trial_int_to_str(time7, timeStrVal); print_generic_string(202, 72, timeStrVal); @@ -2998,39 +2985,39 @@ void time_trial_render_pause_bowser_times(void) { u8 textTotal[] = { TEXT_TIME_TRIAL_TOTAL }; u8 timeStrVal[8]; u8 totalTimeStrVal[16]; + u16 time1 = time_trial_save_file_get_time(15, 0); + u16 time2 = time_trial_save_file_get_time(16, 0); + u16 time3 = time_trial_save_file_get_time(17, 0); + u16 time4 = time_trial_save_file_get_time(15, 1); + u16 time5 = time_trial_save_file_get_time(16, 1); + u16 time6 = time_trial_save_file_get_time(17, 1); print_generic_string(40, 144, textStarWord); print_generic_string(70, 144, textNum1); - u16 time1 = time_trial_save_file_get_time(15, 0); time_trial_int_to_str(time1, timeStrVal); print_generic_string(100, 144, timeStrVal); print_generic_string(40, 120, textStarWord); print_generic_string(70, 120, textNum2); - u16 time2 = time_trial_save_file_get_time(16, 0); time_trial_int_to_str(time2, timeStrVal); print_generic_string(100, 120, timeStrVal); print_generic_string(40, 96, textStarWord); print_generic_string(70, 96, textNum3); - u16 time3 = time_trial_save_file_get_time(17, 0); time_trial_int_to_str(time3, timeStrVal); print_generic_string(100, 96, timeStrVal); print_generic_string(184, 144, textKeyWord); print_generic_string(208, 144, textNum1); - u16 time4 = time_trial_save_file_get_time(15, 1); time_trial_int_to_str(time4, timeStrVal); print_generic_string(244, 144, timeStrVal); print_generic_string(184, 120, textKeyWord); print_generic_string(208, 120, textNum2); - u16 time5 = time_trial_save_file_get_time(16, 1); time_trial_int_to_str(time5, timeStrVal); print_generic_string(244, 120, timeStrVal); print_generic_string(184, 96, textFinal); - u16 time6 = time_trial_save_file_get_time(17, 1); time_trial_int_to_str(time6, timeStrVal); print_generic_string(244, 96, timeStrVal); @@ -3055,6 +3042,7 @@ void time_trial_render_pause_castle_main_strings(void) { u8 strVal[8]; s16 starNum = gDialogLineNum; + u8 bowserStr[8] = { TEXT_TIME_TRIAL_BOWSER }; #ifdef VERSION_EU switch (gInGameLanguage) { @@ -3098,8 +3086,6 @@ void time_trial_render_pause_castle_main_strings(void) { gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); - u8 bowserStr[8] = { TEXT_TIME_TRIAL_BOWSER }; - switch (gDialogLineNum) { case COURSE_STAGES_COUNT: courseName = segmented_to_virtual(courseNameTbl[COURSE_MAX]); @@ -3137,10 +3123,11 @@ void time_trial_render_pause_castle_main_strings(void) { } void time_trial_render_pause_timer_toggle(void) { + u8 timerToggleText[32] = { TEXT_TIME_TRIAL_TIMER_TOGGLE }; + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); - u8 timerToggleText[32] = { TEXT_TIME_TRIAL_TIMER_TOGGLE }; print_generic_string(88, 20, timerToggleText); if (gPlayer3Controller->buttonPressed & (U_CBUTTONS | D_CBUTTONS)) { @@ -3152,10 +3139,11 @@ void time_trial_render_pause_timer_toggle(void) { } void time_trial_check_input_for_course_times_reset(void) { + u8 resetCodeStr[] = { TEXT_TIME_TRIAL_RESET }; + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); - u8 resetCodeStr[] = { TEXT_TIME_TRIAL_RESET }; print_generic_string(64, 8, resetCodeStr); if (gPlayer3Controller->buttonPressed & timeTrialResetIndexCombo[gTimeTrialResetIndex]) { diff --git a/src/game/save_file.c b/src/game/save_file.c index 2344d7d0b5..7694593acc 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -244,6 +244,8 @@ static void save_main_menu_data(void) { } static void wipe_main_menu_data(void) { + u8 i; + bzero(&gSaveBuffer.menuData[0], sizeof(gSaveBuffer.menuData[0])); // Set score ages for all courses to 3, 2, 1, and 0, respectively. @@ -252,7 +254,7 @@ static void wipe_main_menu_data(void) { gSaveBuffer.menuData[0].coinScoreAges[2] = 0x15555555; // Set all time trial times to the max amount - for (u8 i = 0; i < 118; i++) + for (i = 0; i < 118; i++) gSaveBuffer.menuData[0].timeTrialTimes[i] = 17999; gSaveBuffer.menuData[0].timeTrialTotalTime = 17999 * 118; @@ -814,8 +816,9 @@ void time_trial_save_file_set_time(s32 courseIndex, s16 starIndex, u16 time, u8 } void time_trial_update_total_time(u8 forceSave) { + u8 i; gSaveBuffer.menuData[0].timeTrialTotalTime = 0; - for (u8 i = 0; i < 118; i++) { + for (i = 0; i < 118; i++) { gSaveBuffer.menuData[0].timeTrialTotalTime += gSaveBuffer.menuData[0].timeTrialTimes[i]; } gMainMenuDataModified = TRUE; @@ -867,9 +870,11 @@ u32 time_trial_save_file_get_total_time(void) { // If any times are equal to 0 (which is how they're initialized) or above the max allowed value, reset all times void time_trial_verify_times(void) { - for (u8 i = 0; i < 118; i++) { + u8 i; + for (i = 0; i < 118; i++) { if (gSaveBuffer.menuData[0].timeTrialTimes[i] == 0 || gSaveBuffer.menuData[0].timeTrialTimes[i] > 17999) { - for (u8 j = 0; j < 118; j++) { + u8 j; + for (j = 0; j < 118; j++) { gSaveBuffer.menuData[0].timeTrialTimes[j] = 17999; time_trial_update_total_time(0); } From 4d747166902dc8858260036748de096ff44cfe5e Mon Sep 17 00:00:00 2001 From: GateGuy <57763469+GateGuy@users.noreply.github.com> Date: Sun, 19 Jul 2020 16:51:18 -0400 Subject: [PATCH 4/6] HUD polish + a bug fix --- src/game/ingame_menu.c | 1 + src/game/level_update.c | 11 +++++++++-- src/game/level_update.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 5fd0b51005..b9b32c97ae 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -3131,6 +3131,7 @@ void time_trial_render_pause_timer_toggle(void) { print_generic_string(88, 20, timerToggleText); if (gPlayer3Controller->buttonPressed & (U_CBUTTONS | D_CBUTTONS)) { + sTimeTrialTimerDisabled = !sTimeTrialTimerDisabled; gHudDisplay.flags ^= HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs); } diff --git a/src/game/level_update.c b/src/game/level_update.c index 000f846b49..ba4a06efd9 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -172,6 +172,7 @@ s16 unusedEULevelUpdateBss1; #endif s8 sTimerRunning; s8 sTimeTrialTimerRunning; +u8 sTimeTrialTimerDisabled; s8 gShouldNotPlayCastleMusic; s16 sLastLevelNum; @@ -892,10 +893,13 @@ void update_hud_values(void) { if (gCurrCourseNum > 0) { gHudDisplay.flags |= HUD_DISPLAY_FLAG_COIN_COUNT; - gHudDisplay.flags |= HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; + if (sTimeTrialTimerDisabled) { + gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; + } else { + gHudDisplay.flags |= HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; + } } else { gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_COIN_COUNT; - gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; } if (gHudDisplay.coins < gMarioState->numCoins) { @@ -1239,6 +1243,9 @@ s32 init_level(void) { if ((sLastLevelNum == LEVEL_CASTLE || sLastLevelNum == LEVEL_CASTLE_GROUNDS || sLastLevelNum == LEVEL_CASTLE_COURTYARD) && (gCurrAreaIndex == 1 || gCurrLevelNum == LEVEL_THI)) gHudDisplay.timeTrialTimer = 0; sTimeTrialTimerRunning = !(gCurrLevelNum == LEVEL_CASTLE || gCurrLevelNum == LEVEL_CASTLE_GROUNDS || gCurrLevelNum == LEVEL_CASTLE_COURTYARD); + if (!sTimeTrialTimerRunning) { + gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_TIME_TRIAL_TIMER; + } sLastLevelNum = gCurrLevelNum; return 1; diff --git a/src/game/level_update.h b/src/game/level_update.h index 3ee6fa79dc..c99775b34a 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -90,6 +90,7 @@ extern u8 unused4[2]; extern s8 sTimerRunning; extern s8 sTimeTrialTimerRunning; +extern u8 sTimeTrialTimerDisabled; extern u8 gTimeTrialResetIndex; struct HudDisplay { From 4d40149419f883aa91acd6d3ba4baa3f106cc7d4 Mon Sep 17 00:00:00 2001 From: GateGuy <57763469+GateGuy@users.noreply.github.com> Date: Mon, 20 Jul 2020 18:24:42 -0400 Subject: [PATCH 5/6] Added verification upon setting a time --- src/game/save_file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game/save_file.c b/src/game/save_file.c index 7694593acc..f74471cfe8 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -773,6 +773,7 @@ s32 check_warp_checkpoint(struct WarpNode *warpNode) { void time_trial_save_file_set_time(s32 courseIndex, s16 starIndex, u16 time, u8 forceSet) { u8 timeIndex; u8 forceSave = 0; + time_trial_verify_times(); switch (courseIndex) { case 15: timeIndex = 112 + (3*starIndex); From 3111199c261d98deb282cdc025179c4692f957d7 Mon Sep 17 00:00:00 2001 From: GateGuy <57763469+GateGuy@users.noreply.github.com> Date: Mon, 20 Jul 2020 18:26:38 -0400 Subject: [PATCH 6/6] Moved verification function --- src/game/save_file.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/game/save_file.c b/src/game/save_file.c index f74471cfe8..178370d44d 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -770,6 +770,21 @@ s32 check_warp_checkpoint(struct WarpNode *warpNode) { return isWarpCheckpointActive; } +// If any times are equal to 0 (which is how they're initialized) or above the max allowed value, reset all times +void time_trial_verify_times(void) { + u8 i; + for (i = 0; i < 118; i++) { + if (gSaveBuffer.menuData[0].timeTrialTimes[i] == 0 || gSaveBuffer.menuData[0].timeTrialTimes[i] > 17999) { + u8 j; + for (j = 0; j < 118; j++) { + gSaveBuffer.menuData[0].timeTrialTimes[j] = 17999; + time_trial_update_total_time(0); + } + break; + } + } +} + void time_trial_save_file_set_time(s32 courseIndex, s16 starIndex, u16 time, u8 forceSet) { u8 timeIndex; u8 forceSave = 0; @@ -868,18 +883,3 @@ u16 time_trial_save_file_get_time(s32 courseIndex, s16 starIndex) { u32 time_trial_save_file_get_total_time(void) { return gSaveBuffer.menuData[0].timeTrialTotalTime; } - -// If any times are equal to 0 (which is how they're initialized) or above the max allowed value, reset all times -void time_trial_verify_times(void) { - u8 i; - for (i = 0; i < 118; i++) { - if (gSaveBuffer.menuData[0].timeTrialTimes[i] == 0 || gSaveBuffer.menuData[0].timeTrialTimes[i] > 17999) { - u8 j; - for (j = 0; j < 118; j++) { - gSaveBuffer.menuData[0].timeTrialTimes[j] = 17999; - time_trial_update_total_time(0); - } - break; - } - } -} \ No newline at end of file