From b944f0b2a36d8b4e60f04f51662749f5df0f34e5 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Thu, 19 Oct 2023 02:59:09 -0500 Subject: [PATCH 01/45] loadless timer + segment timer stuff --- scripts/gen_compile_commands.py | 0 scripts/genfunc.py | 0 scripts/go.sh | 0 scripts/str2hex.py | 0 scripts/subtrees.sh | 0 src/mods/storytimer.cpp | 455 ++++++++++++++++++++++++++++++++ src/mods/storytimer.h | 8 + src/systems/main.cpp | 3 + src/systems/menu_defn.cpp | 41 +++ src/systems/menu_impl.cpp | 2 +- src/systems/pref.cpp | 8 +- src/systems/pref.h | 2 + src/utils/timerdisp.cpp | 142 ++++++++++ src/utils/timerdisp.h | 1 + 14 files changed, 660 insertions(+), 2 deletions(-) mode change 100755 => 100644 scripts/gen_compile_commands.py mode change 100755 => 100644 scripts/genfunc.py mode change 100755 => 100644 scripts/go.sh mode change 100755 => 100644 scripts/str2hex.py mode change 100755 => 100644 scripts/subtrees.sh create mode 100644 src/mods/storytimer.cpp create mode 100644 src/mods/storytimer.h diff --git a/scripts/gen_compile_commands.py b/scripts/gen_compile_commands.py old mode 100755 new mode 100644 diff --git a/scripts/genfunc.py b/scripts/genfunc.py old mode 100755 new mode 100644 diff --git a/scripts/go.sh b/scripts/go.sh old mode 100755 new mode 100644 diff --git a/scripts/str2hex.py b/scripts/str2hex.py old mode 100755 new mode 100644 diff --git a/scripts/subtrees.sh b/scripts/subtrees.sh old mode 100755 new mode 100644 diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp new file mode 100644 index 00000000..f78104c7 --- /dev/null +++ b/src/mods/storytimer.cpp @@ -0,0 +1,455 @@ +#include "iw.h" + +#include "mkb/mkb.h" + +#include "mods/freecam.h" +#include "systems/assembly.h" +#include "systems/pad.h" +#include "systems/pref.h" +#include "utils/draw.h" +#include "utils/patch.h" +#include "utils/timerdisp.h" + +namespace storytimer { + + enum class FullgameTimerOptions { + F_DontShow = 0, + F_AlwaysShow = 1, + F_BetweenWorlds = 2, + F_EndOfRun = 3, + }; + + enum class SegmentTimerOptions { + S_DontShow = 0, + S_AlwaysShow = 1, + S_BetweenWorlds = 2, + S_EndOfRun = 3, + }; + +static u32 s_loadless_iw_time; +static u32 s_spin_in_timer; +static u32 s_gameplay_timer; +static u32 s_postgoal_timer; +static u32 s_postgoal_replay_timer; +static u32 s_exit_game_timer; +static u32 s_fallout_timer; +static u32 s_stage_select_timer; +static u32 s_loadless_story_timer; +static bool s_run_timer; +static bool s_is_on_spin_in; +static bool s_is_on_stage_select_screen; +static bool s_is_on_exit_game_screen; +static bool s_is_on_fallout_screen; +static bool s_is_postgoal; +static bool s_can_increment_stage_counter; +static bool s_lower_stage_counter; +static bool s_in_story; +static u32 s_prev_completed_stage_count; +static s32 s_completed_stages; +static u32 s_dummy; +static u32 s_dummy_2; +static u32 s_dummy_3; +static u32 s_split[10]; // s_split[k] is the loadless time on tape break of the 10th stage of world k +static u32 s_segment_time[10]; // s_segment_time[k] is the loadless time spent on world k, starting from stage select spin in to tape break on the 10th stage +static u32 s_segment_start_time[10]; // the loadless time at the start of world k, used to calculate s_segment_time[k] +static bool s_display_story_timer; +static bool s_display_segment_timer; +static bool s_display_split; +static bool s_display_world_time; +static bool s_display_segment; +static bool s_is_between_worlds; +static bool s_passed_cutscene; +static bool s_is_run_complete; +static u32 s_segment_timer[10]; +static bool s_is_on_world[10]; +static bool s_can_change_segment_start_time[10]; + +void tick() { + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ + s_run_timer = true; + } + + /* + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN){ + // can increment counter after going through the goal + s_can_increment_stage_counter = true; + } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED || mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT){ + // but if you go back to the stage select screen without entering the goal or from an exit game, don't increment the counter + s_can_increment_stage_counter = false; + } + + if (s_can_increment_stage_counter == true && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN){ + s_completed_stages += 1; + } + */ + + // there is likely a simpler way to increment the stage counter in a way that works when you retry after breaking the tape and also does not break if you pause during + // game goal init or game goal main + + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { + s_prev_completed_stage_count = s_completed_stages; + } + + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { + // not allowed to increment the stage counter on goal init because of first framing + s_can_increment_stage_counter = true; + } + + if ( (s_completed_stages - s_prev_completed_stage_count) > 0 ) { + // if we've incremented the stage counter already, we're not allowed to increment again until the next game goal main + s_can_increment_stage_counter = false; + // however, if you retry after breaking the tape, lower the counter + if (mkb::sub_mode==mkb::SMD_GAME_READY_INIT) { + s_lower_stage_counter = true; + } else if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + s_lower_stage_counter = false; + s_prev_completed_stage_count = s_completed_stages; + } + } + + if (s_can_increment_stage_counter == true) { + s_completed_stages += 1; + } + + if (s_lower_stage_counter == true && ((s_completed_stages - s_prev_completed_stage_count) > 0 )) { + s_completed_stages += -1; + s_lower_stage_counter = false; + } + + /* + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { + s_completed_stages +=1; + } + */ + + // submodes during spin in + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_MAIN) { + s_is_on_spin_in = true; + } else { + s_is_on_spin_in = false; + } + + // states entered during the story select screen + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE || mkb::g_storymode_stageselect_state == 5 || mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { + // 3, 5 unlabelled inits + s_is_on_stage_select_screen = true; + } else { + s_is_on_stage_select_screen = false; + } + + // submodes entered when exiting game + if (mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT || mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_MAIN + || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_INIT || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_MAIN) { + s_is_on_exit_game_screen = true; + } else{ + s_is_on_exit_game_screen = false; + } + + // submodes entered when breaking the goal tape + if (mkb::sub_mode==mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode==mkb::SMD_GAME_GOAL_MAIN || + mkb::sub_mode==mkb::SMD_GAME_GOAL_REPLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_GOAL_REPLAY_MAIN || mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + s_is_postgoal = true; + } else { + s_is_postgoal = false; + } + + // submodes for the fallout and y/n screen + if (mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_MAIN + || mkb::sub_mode == mkb::SMD_GAME_RETRY_INIT || mkb::sub_mode == mkb::SMD_GAME_RETRY_MAIN) { + s_is_on_fallout_screen = true; + } else { + s_is_on_fallout_screen = false; + } + + if (mkb::g_storymode_mode == 5){ + // zero the timer on the file select screen and set the number of completed stages to 0 + s_spin_in_timer = 0 ; + s_gameplay_timer = 0; + s_postgoal_timer = 0; + // s_postgoal_replay_timer = 0; + s_stage_select_timer = 0; + s_exit_game_timer = 0; + s_fallout_timer = 0; + s_run_timer = false; + s_lower_stage_counter = false; + s_loadless_story_timer = 0; + s_completed_stages = 0; + } else{ + s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer; + } + + if (s_run_timer == true){ + if (s_is_on_spin_in == true) { + // increment the timer every frame during spin in + s_spin_in_timer +=1; + } + if (mkb::sub_mode==mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_PLAY_MAIN) { + //increment the timer every frame during gameplay + s_gameplay_timer +=1; + } + if (s_is_postgoal == true) { + //increment the timer every frame after breaking the tape before returning to story select + s_postgoal_timer +=1; + } + // if (mkb::sub_mode==mkb::SMD_GAME_GOAL_REPLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_GOAL_REPLAY_MAIN) { + //increment the timer every frame during the postgoal replay + // s_postgoal_replay_timer= s_postgoal_replay_timer+1; + //} + if (s_is_on_stage_select_screen == true) { + //increment the timer every frame on the story mode select screen + s_stage_select_timer +=1; + } + if (s_is_on_exit_game_screen == true) { + // increment the timer every frame on the exit game screen + s_exit_game_timer +=1; + } + if (s_is_on_fallout_screen == true) { + // increment the timer every frame during the fallout sequence and y/n screen + s_fallout_timer += 1; + } + mkb::OSReport("submode: %d ", mkb::sub_mode); + // mkb::OSReport("mainmode: %d ", mkb::main_mode); + } + + + if (s_completed_stages == 99 && mkb::sub_mode ==mkb::SMD_GAME_GOAL_INIT){ + // stop the timer after breaking the tape on stage 100 + // to do: make this work for story mode packs with less than 100 stages like kaizo + s_run_timer = false; + } + + if (s_completed_stages == 100 && s_is_postgoal == true) { + s_is_run_complete = true; + } else { + s_is_run_complete = false; + } + + if ( (mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { + s_in_story = true; + } else{ + s_in_story = false; + } + + // code for handling loadless split and segment times + for (s32 k=1; k<11; k++){ + if (s_completed_stages == 10*k-1 && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { // delete later probably + // on tape break on the last stage in world k + // need to correct by 3f since goal_init doesn't happen immediately after the tape is broken + s_split[k] = s_loadless_story_timer-3; + s_display_segment = true; // testing + } + + // if you enter the first stage of the next world but then stage select, do not restart the segment timer + if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { + s_can_change_segment_start_time[k] = true; + } else if (s_completed_stages == 10*(k-1) && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + s_can_change_segment_start_time[k] = false; + } + + if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_can_change_segment_start_time[k] == true) { + s_segment_start_time[k] = s_loadless_story_timer+1; + } + + // display split and iw time after breaking the tape on the last stage of a world, but stop displaying when the stage select screen for the next world starts spinning in + if (s_completed_stages == 10*k && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { // delete later + s_display_segment = false; // testing + } + + // maybe can simplify but I want to avoid things breaking if you first frame (menuing on goal init or the frame before) + if (s_completed_stages == 10*k-1 && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { + s_passed_cutscene = false; + } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + s_passed_cutscene = true; + } + + if ( (s_completed_stages % 10 == 0) && s_completed_stages != 0 && s_passed_cutscene == false){ + s_is_between_worlds = true; + } else if ((s_completed_stages % 10 == 0) && s_completed_stages != 0 && s_passed_cutscene == true){ + s_is_between_worlds = false; + } + + // loadless time taken to complete world k + s_segment_time[k] = s_split[k]-s_segment_start_time[k]; + + if ( ( (10*(k-1) <= s_completed_stages) && (s_completed_stages <= (10*k-2) ) ) || (s_completed_stages == (10*k-1) && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT) ){ + s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k]; + } else if (s_completed_stages == (10*k-1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { + // I don't know a better way of doing this to make the timer show the time at tape break + // if we show the segment timer at all times, since the timer will run for 2 frames after breaking the tape + s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k] -3; + } + + + if ( ( (10*(k-1) +1)<= s_completed_stages) && (s_completed_stages <= (10*k-1)) ) { + s_is_on_world[k] = true; + } else if (s_completed_stages == 10*(k-1) && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ + s_is_on_world[k-1] = false; + s_is_on_world[k] = true; + } else if (s_completed_stages == 10*k && s_is_postgoal == true && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT) { + s_is_on_world[k] = true; + } + + + /* can't use switch case in for loop :( + + switch (s_completed_stages) { + case ( (10*(k-1) +1<= s_completed_stages) && (s_completed_stages <= (10*k-1)) ): + s_is_on_world[k] = true; + break; + case (s_completed_stages == 10*(k-1) && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE): + s_is_on_world[k-1] = false; + s_is_on_world[k] = true; + break; + case (s_completed_stages == 10*k && s_is_postgoal == true): + s_is_on_world[k] = true; + break; + } + + */ + if (s_is_on_world[1] == true) { + s_dummy_2 = 1; + } else { + s_dummy_2 = 0; + } + } + + + + /* + if ( ( (10*(k-1)-1 < s_completed_stages) && (s_completed_stages < 10*k-1) ) || (s_completed_stages == 10*k-1 && s_is_postgoal == false) ){ + s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k]; + } + + // display split and iw time after breaking the tape on the last stage of a world, but stop displaying when the stage select screen for the next world starts spinning in + if ((s_completed_stages == 10*k-1 || s_completed_stages == 10*k ) && mkb::g_storymode_stageselect_state != mkb::STAGE_SELECT_INTRO_SEQUENCE) { + s_display_segment = true; + } else if (s_completed_stages == 10*k && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + s_display_segment = false; + } + + */ + + if (s_is_between_worlds == true){ + s_dummy = 1; + } else { + s_dummy = 0; + /* things tested that didn't work for exit game so far + SMD_GAME_FORCE_EXIT_MAIN=93 + SMD_GAME_FORCE_OVER_MAIN=96 + SMD_GAME_OVER_POINT_MAIN=86 + + things that do work + SMD_GAME_SUGG_SAVE_MAIN, doesn't include playpoint text, only the save data question after + SMD_GAME_INTR_SEL_MAIN is the playpoint text + + fallout submode testing + test: 50, 51, 58, 59, 90, 91, 48, 49, + + SMD_GAME_READY_INIT=48, + SMD_GAME_READY_MAIN=49, + SMD_GAME_RINGOUT_INIT=58, + SMD_GAME_RINGOUT_MAIN=59 + SMD_GAME_RETRY_INIT=90, + SMD_GAME_RETRY_MAIN=91 + + conclusion: ringout = fallout submode, game retry init/main = y/n menu + + FOR LATER, TRY THESE: + SMD_GAME_SCENSCNPLAY_RETURN=94 (missing frame on world entry?) + SMD_AUTHOR_PLAY_INIT=247, + SMD_AUTHOR_PLAY_MAIN=248, + SMD_AUTHOR_PLAY_STORY_INIT=249, + + */ + } + +} + +void disp() { + // timerdisp::draw_timer(static_cast(s_display_segment), "Splt:", 1, draw::WHITE, true); + // timerdisp::draw_timer(static_cast(60*mkb::sub_mode), "dbg:", 4, draw::WHITE, true); + // timerdisp::draw_timer(static_cast(s_segment_timer[2]), "IW:", 3, draw::WHITE, true); +/* + if (FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_AlwaysShow){ + timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false); + } +*/ + /* + if (mkb::main_mode != mkb::MD_GAME || mkb::main_game_mode != mkb::STORY_MODE || + freecam::should_hide_hud()) { + return; + } +*/ +if (s_in_story == false || freecam::should_hide_hud() ){ + return; +} + + switch(FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions))) { + case FullgameTimerOptions::F_AlwaysShow: + s_display_story_timer = true; + break; + case FullgameTimerOptions::F_BetweenWorlds: + if (s_is_between_worlds == true) { + s_display_story_timer = true; + } else { + s_display_story_timer = false; + } + break; + case FullgameTimerOptions::F_EndOfRun: + if (s_is_run_complete == true){ + s_display_story_timer = true; + } else { + s_display_story_timer = false; + } + break; + case FullgameTimerOptions::F_DontShow: + s_display_story_timer = false; + break; + } + + switch(SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { + case SegmentTimerOptions::S_AlwaysShow: + s_display_segment_timer = true; + break; + case SegmentTimerOptions::S_BetweenWorlds: + if (s_is_between_worlds == true) { + s_display_segment_timer = true; + } else { + s_display_segment_timer = false; + } + break; + case SegmentTimerOptions::S_EndOfRun: + if (s_is_run_complete == true){ + s_display_segment_timer = true; + } else { + s_display_segment_timer = false; + } + break; + case SegmentTimerOptions::S_DontShow: + s_display_segment_timer = false; + break; + } + + for (s32 k=1; k<11; k++){ + if (s_display_story_timer == true && s_is_between_worlds == false){ + timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false, false, 0); + } else if (s_display_story_timer == true && s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { + timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false, true, s_split[k]); + } + if (s_display_segment_timer == true && s_is_on_world[k] == true && s_is_run_complete == false) { + timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, false, 0); + } else if (s_display_segment_timer == true && s_is_run_complete == true) { + timerdisp::draw_storytimer(static_cast(s_split[k]), "Splt:", k, draw::WHITE, false, true, s_segment_timer[k]); + // to do: modify draw_storytimer so that you can display in the format "World k: split k time (segment k time)" + } + } + + // debugging + timerdisp::draw_timer(static_cast(s_dummy), "Splt:", 0, draw::WHITE, true); + timerdisp::draw_timer(static_cast(s_dummy_2), "Splt:", 1, draw::WHITE, true); +// draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) (reference) +// if (IlBattleLength(pref::get(pref::U8Pref::IlBattleLength)) == IlBattleLength::Endless); (reference) +} + +} // namespace storytimer diff --git a/src/mods/storytimer.h b/src/mods/storytimer.h new file mode 100644 index 00000000..16df1c93 --- /dev/null +++ b/src/mods/storytimer.h @@ -0,0 +1,8 @@ +#pragma once + +namespace storytimer { + +void tick(); +void disp(); + +} // namespace storytimer \ No newline at end of file diff --git a/src/systems/main.cpp b/src/systems/main.cpp index 8f45c36d..1c870286 100644 --- a/src/systems/main.cpp +++ b/src/systems/main.cpp @@ -31,6 +31,7 @@ #include "mods/savest_ui.h" #include "mods/scratch.h" #include "mods/sfx.h" +#include "mods/storytimer.h" #include "mods/tetris.h" #include "mods/timer.h" #include "mods/unlock.h" @@ -116,6 +117,7 @@ void init() { fallout::tick(); physics::tick(); iw::tick(); + storytimer::tick(); savest_ui::tick(); menu_impl::tick(); jump::tick(); @@ -150,6 +152,7 @@ void init() { draw::predraw(); timer::disp(); iw::disp(); + storytimer::disp(); Tetris::get_instance().disp(); ilbattle::disp(); cmseg::disp(); diff --git a/src/systems/menu_defn.cpp b/src/systems/menu_defn.cpp index 41005ed7..96cc57f5 100644 --- a/src/systems/menu_defn.cpp +++ b/src/systems/menu_defn.cpp @@ -658,6 +658,43 @@ static Widget s_cm_seg_widgets[] = { }, }; +static const char* FULLGAME_TIMER_OPTIONS[] = { + "Don't show", + "Always show", + "Between worlds", + "End of run", +}; + +static const char* SEGMENT_TIMER_OPTIONS[] = { + "Don't show", + "Always show", + "Between worlds", + "End of run", +}; + +static Widget s_loadless_timers_widgets[] = { + { + .type = WidgetType::Choose, + .choose = + { + .label = "Fullgame Timer", + .choices = FULLGAME_TIMER_OPTIONS, + .num_choices = LEN(FULLGAME_TIMER_OPTIONS), + .pref = pref::U8Pref::FullgameTimerOptions, + }, + }, + { + .type = WidgetType::Choose, + .choose = + { + .label = "Segment Timer", + .choices = SEGMENT_TIMER_OPTIONS, + .num_choices = LEN(SEGMENT_TIMER_OPTIONS), + .pref = pref::U8Pref::SegmentTimerOptions, + }, + }, +}; + static Widget s_timers_widgets[] = { { .type = WidgetType::Checkbox, @@ -683,6 +720,10 @@ static Widget s_timers_widgets[] = { .pref = pref::BoolPref::CmTimer, }, }, + { + .type = WidgetType::Menu, + .menu = {"Loadless Timers", s_loadless_timers_widgets, LEN(s_loadless_timers_widgets)}, + }, }; static Widget s_savestates_help_widgets[] = { diff --git a/src/systems/menu_impl.cpp b/src/systems/menu_impl.cpp index f6f97702..94a74cc2 100644 --- a/src/systems/menu_impl.cpp +++ b/src/systems/menu_impl.cpp @@ -414,7 +414,7 @@ static void draw_help(const Widget& widget) { "Reset"); break; } - case WidgetType::InputSelect: { + case WidgetType::InputSelect: { draw::debug_text(START, Y_HEIGHT, draw::LIGHT_GREEN, "A"); draw::debug_text(BUTTON_START + 1 * BLOCK_WIDTH, Y_HEIGHT, draw::WHITE, ":"); draw::debug_text(BUTTON_START + 1 * BLOCK_WIDTH + HALF_SPACE, Y_HEIGHT, draw::WHITE, diff --git a/src/systems/pref.cpp b/src/systems/pref.cpp index 97611efa..988e271f 100644 --- a/src/systems/pref.cpp +++ b/src/systems/pref.cpp @@ -87,6 +87,8 @@ enum class PrefId : u16 { IlBattleReadyBind = 67, FreecamToggleBind = 68, SavestateClearBind = 69, + FullgameTimerOptions = 70, + SegmentTimerOptions = 71, }; // Verbatim list of preference IDs we iterate over when writing savefile back out @@ -302,6 +304,10 @@ static std::optional pref_id_to_u8_pref(PrefId id) { return U8Pref::SavestateClearBind; case PrefId::FalloutPlaneType: return U8Pref::FalloutPlaneType; + case PrefId::FullgameTimerOptions: + return U8Pref::FullgameTimerOptions; + case PrefId::SegmentTimerOptions: + return U8Pref::SegmentTimerOptions; default: return {}; } @@ -343,7 +349,7 @@ static DefaultU8Pref s_default_u8_prefs[] = { struct PrefState { u8 bool_prefs[8]; // up to 64 bool prefs - u8 u8_prefs[25]; // 25 u8 prefs + u8 u8_prefs[27]; // 27 u8 prefs }; static PrefState s_pref_state, s_default_pref_state; diff --git a/src/systems/pref.h b/src/systems/pref.h index 1d17f76a..9bd2b117 100644 --- a/src/systems/pref.h +++ b/src/systems/pref.h @@ -77,6 +77,8 @@ enum class U8Pref : u8 { FreecamToggleBind, SavestateClearBind, FalloutPlaneType, + FullgameTimerOptions, + SegmentTimerOptions, }; void init(); diff --git a/src/utils/timerdisp.cpp b/src/utils/timerdisp.cpp index 6261f7c3..8880b8ae 100644 --- a/src/utils/timerdisp.cpp +++ b/src/utils/timerdisp.cpp @@ -9,6 +9,7 @@ static constexpr u32 MINUTE_FRAMES = SECOND_FRAMES * 60; static constexpr u32 HOUR_FRAMES = MINUTE_FRAMES * 60; static constexpr s32 X = 380; +static constexpr s32 X_2 = 18; static constexpr s32 Y = 24; void draw_timer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds) { @@ -39,4 +40,145 @@ void draw_timer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, boo } } +/* +void draw_storytimer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds) { + bool positive = frames >= 0; + if (!positive) frames = -frames; + const char* sign = positive ? "" : "-"; + + u32 hours = frames / HOUR_FRAMES; + u32 minutes = frames % HOUR_FRAMES / MINUTE_FRAMES; + u32 seconds = frames % MINUTE_FRAMES / SECOND_FRAMES; + u32 centiseconds = (frames % SECOND_FRAMES) * 100 / 60; + + s32 y = Y + (row+2) * 16; + + if (hours > 0 && !show_seconds) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d", sign, hours, minutes, seconds, + centiseconds); + } else if (minutes > 0 && !show_seconds) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d", sign, minutes, seconds, + centiseconds); + } else { + u32 total_seconds = + seconds + (minutes * MINUTE_FRAMES + hours * HOUR_FRAMES) / SECOND_FRAMES; + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d.%02d", sign, total_seconds, centiseconds); + } +} */ + +void draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) { + bool positive = frames_1 >= 0; + if (!positive) frames_1 = -frames_1; + const char* sign = positive ? "" : "-"; + + u32 hours_1 = frames_1 / HOUR_FRAMES; + u32 minutes_1 = frames_1 % HOUR_FRAMES / MINUTE_FRAMES; + u32 seconds_1 = frames_1 % MINUTE_FRAMES / SECOND_FRAMES; + u32 centiseconds_1 = (frames_1 % SECOND_FRAMES) * 100 / 60; + + u32 hours_2 = frames_2 / HOUR_FRAMES; + u32 minutes_2 = frames_2 % HOUR_FRAMES / MINUTE_FRAMES; + u32 seconds_2 = frames_2 % MINUTE_FRAMES / SECOND_FRAMES; + u32 centiseconds_2 = (frames_2 % SECOND_FRAMES) * 100 / 60; + + s32 y = Y + (row+2) * 16; +/* + if (second_argument == false) { + if (hours_1 > 0 && !show_seconds) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d", sign, hours_1, minutes_1, seconds_1, + centiseconds_1); + } else if (minutes_1 > 0 && !show_seconds) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d", sign, minutes_1, seconds_1, + centiseconds_1); + } else { + u32 total_seconds_1 = + seconds_1 + (minutes_1 * MINUTE_FRAMES + hours_1 * HOUR_FRAMES) / SECOND_FRAMES; + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d.%02d", sign, total_seconds_1, centiseconds_1); + } + } else { + if (hours_1 > 0 && hours_2 > 0 && !show_seconds) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, + centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); + } else if (minutes_1 > 0 && minutes_2 > 0 && !show_seconds) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, minutes_1, seconds_1, + centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); + } else { + u32 total_seconds_2 = + seconds_2 + (minutes_2 * MINUTE_FRAMES + hours_2 * HOUR_FRAMES) / SECOND_FRAMES; + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d.%02d", sign, total_seconds_2, centiseconds_2); + } + } +*/ + if (second_argument == true){ + if (hours_1 > 0) { + if (hours_2 > 0 ) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, + centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); + } else if (minutes_2 > 0) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, + centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); + } else { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%02d.%02d)", sign, hours_1, minutes_1, seconds_1, + centiseconds_1, sign, seconds_2, centiseconds_2); + } + } else if (minutes_1 > 0) { + if (hours_2 > 0) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, minutes_1, seconds_1, + centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); + } else if (minutes_2 > 0) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d (%s%02d:%02d.%02d)", sign, minutes_1, seconds_1, + centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); + } else { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d (%s%02d.%02d)", sign, minutes_1, seconds_1, + centiseconds_1, sign, seconds_2, centiseconds_2); + } + + } else { + if (hours_2 > 0) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d.%02d (%s%d:%02d:%02d.%02d)", sign, seconds_1, + centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); + } else if (minutes_2 > 0) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d.%02d (%s%d:%02d.%02d)", sign, seconds_1, + centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); + } else { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d.%02d (%s%d.%02d)", sign, seconds_1, + centiseconds_1, sign, seconds_2, centiseconds_2); + } + } + } else { + if (hours_1 > 0 && !show_seconds) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d", sign, hours_1, minutes_1, seconds_1, + centiseconds_1); + } else if (minutes_1 > 0 && !show_seconds) { + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d", sign, minutes_1, seconds_1, + centiseconds_1); + } else { + u32 total_seconds_1 = + seconds_1 + (minutes_1 * MINUTE_FRAMES + hours_1 * HOUR_FRAMES) / SECOND_FRAMES; + draw::debug_text(X_2, y, color, prefix); + draw::debug_text(X_2 + 54, y, color, "%s%02d.%02d", sign, total_seconds_1, centiseconds_1); + } + } +} + } // namespace timerdisp diff --git a/src/utils/timerdisp.h b/src/utils/timerdisp.h index a2844e75..db0b3dfc 100644 --- a/src/utils/timerdisp.h +++ b/src/utils/timerdisp.h @@ -5,5 +5,6 @@ namespace timerdisp { void draw_timer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, bool show_minutes); +void draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_minutes, bool second_argument, s32 frames_2); } From 03b8941150715f20d549ed832059550009f32509 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Mon, 30 Oct 2023 23:27:18 -0500 Subject: [PATCH 02/45] fixing segment timer after resetting --- src/mods/storytimer.cpp | 59 +++++++++---- ...storytimer.cpp\357\200\272Zone.Identifier" | 3 + src/utils/timerdisp.cpp | 82 +++++++++++++++++++ src/utils/timerdisp.h | 3 +- 4 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 "src/mods/storytimer.cpp\357\200\272Zone.Identifier" diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index f78104c7..cde02991 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -63,6 +63,7 @@ static bool s_is_run_complete; static u32 s_segment_timer[10]; static bool s_is_on_world[10]; static bool s_can_change_segment_start_time[10]; +static u32 s_segment_timer_location; void tick() { if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ @@ -175,6 +176,7 @@ void tick() { s_lower_stage_counter = false; s_loadless_story_timer = 0; s_completed_stages = 0; + s_prev_completed_stage_count = 0; } else{ s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer; } @@ -382,8 +384,8 @@ void disp() { } */ if (s_in_story == false || freecam::should_hide_hud() ){ - return; -} + return; + } switch(FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions))) { case FullgameTimerOptions::F_AlwaysShow: @@ -408,22 +410,38 @@ if (s_in_story == false || freecam::should_hide_hud() ){ break; } + if (s_display_story_timer == true){ + timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false, false, 0); + } + + // if the fullgame timer is off but the segment timer is on, move the segment timer up by 1 line + if(FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_DontShow){ + s_segment_timer_location = 1; + } else { + s_segment_timer_location = 0; + } + switch(SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { case SegmentTimerOptions::S_AlwaysShow: s_display_segment_timer = true; - break; - case SegmentTimerOptions::S_BetweenWorlds: - if (s_is_between_worlds == true) { - s_display_segment_timer = true; - } else { - s_display_segment_timer = false; + // if the segment timer is always showing, + // use the format iw time (split time) after breaking the tape on the last stage of a world + for (s32 k=1; k<11; k++){ + if (s_display_segment_timer == true && s_is_on_world[k] == true && s_is_between_worlds == false && s_is_run_complete == false) { + timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, false, 0); + } + else if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { + timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Time:", 1, draw::WHITE, false, true, s_split[k]); + } } break; - case SegmentTimerOptions::S_EndOfRun: - if (s_is_run_complete == true){ - s_display_segment_timer = true; - } else { - s_display_segment_timer = false; + case SegmentTimerOptions::S_BetweenWorlds: + s_display_segment_timer = true; + // otherwise use the format split time (iw time) + for (s32 k=1; k<11; k++){ + if (s_display_segment_timer == true && s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { + timerdisp::draw_storytimer(static_cast(s_split[k]), "Time:", 1, draw::WHITE, false, true, s_segment_timer[k]); + } } break; case SegmentTimerOptions::S_DontShow: @@ -431,6 +449,16 @@ if (s_in_story == false || freecam::should_hide_hud() ){ break; } + // if the segment timer is enabled in any capacity, show all 10 split times + iw times after the tape is broken on the last stage + if (SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != SegmentTimerOptions::S_DontShow) { + for (s32 k=1; k<11; k++){ + if (s_is_run_complete == true){ + timerdisp::draw_storytimer(static_cast(s_split[k]), "Splt:", k+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[k]); + } + } + } + +/* for (s32 k=1; k<11; k++){ if (s_display_story_timer == true && s_is_between_worlds == false){ timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false, false, 0); @@ -444,10 +472,11 @@ if (s_in_story == false || freecam::should_hide_hud() ){ // to do: modify draw_storytimer so that you can display in the format "World k: split k time (segment k time)" } } +*/ // debugging - timerdisp::draw_timer(static_cast(s_dummy), "Splt:", 0, draw::WHITE, true); - timerdisp::draw_timer(static_cast(s_dummy_2), "Splt:", 1, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*s_completed_stages), "Splt:", 0, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*s_prev_completed_stage_count), "Splt:", 1, draw::WHITE, true); // draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) (reference) // if (IlBattleLength(pref::get(pref::U8Pref::IlBattleLength)) == IlBattleLength::Endless); (reference) } diff --git "a/src/mods/storytimer.cpp\357\200\272Zone.Identifier" "b/src/mods/storytimer.cpp\357\200\272Zone.Identifier" new file mode 100644 index 00000000..43a1a01e --- /dev/null +++ "b/src/mods/storytimer.cpp\357\200\272Zone.Identifier" @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +HostUrl=https://github.com/ diff --git a/src/utils/timerdisp.cpp b/src/utils/timerdisp.cpp index 8880b8ae..5e875675 100644 --- a/src/utils/timerdisp.cpp +++ b/src/utils/timerdisp.cpp @@ -181,4 +181,86 @@ void draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor col } } +void draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color){ + bool positive = frames_1 >= 0; + if (!positive) frames_1 = -frames_1; + const char* sign = positive ? "" : "-"; + + u32 hours_1 = frames_1 / HOUR_FRAMES; + u32 minutes_1 = frames_1 % HOUR_FRAMES / MINUTE_FRAMES; + u32 seconds_1 = frames_1 % MINUTE_FRAMES / SECOND_FRAMES; + u32 centiseconds_1 = (frames_1 % SECOND_FRAMES) * 100 / 60; + + u32 hours_2 = frames_2 / HOUR_FRAMES; + u32 minutes_2 = frames_2 % HOUR_FRAMES / MINUTE_FRAMES; + u32 seconds_2 = frames_2 % MINUTE_FRAMES / SECOND_FRAMES; + u32 centiseconds_2 = (frames_2 % SECOND_FRAMES) * 100 / 60; + + s32 A = pos_x; + s32 a = A + text_offset; + s32 b = Y + (pos_y+2)*16; + + if (show_second_argument == true){ + if (hours_1 > 0) { + if (hours_2 > 0 ) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, + centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); + } else if (minutes_2 > 0) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d (%s%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, + centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); + } else { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d (%s%02d.%02d)", sign, hours_1, minutes_1, seconds_1, + centiseconds_1, sign, seconds_2, centiseconds_2); + } + } else if (minutes_1 > 0) { + if (hours_2 > 0) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, minutes_1, seconds_1, + centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); + } else if (minutes_2 > 0) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%02d:%02d.%02d (%s%02d:%02d.%02d)", sign, minutes_1, seconds_1, + centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); + } else { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%02d:%02d.%02d (%s%02d.%02d)", sign, minutes_1, seconds_1, + centiseconds_1, sign, seconds_2, centiseconds_2); + } + + } else { + if (hours_2 > 0) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%d.%02d (%s%d:%02d:%02d.%02d)", sign, seconds_1, + centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); + } else if (minutes_2 > 0) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%d.%02d (%s%d:%02d.%02d)", sign, seconds_1, + centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); + } else { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%d.%02d (%s%d.%02d)", sign, seconds_1, + centiseconds_1, sign, seconds_2, centiseconds_2); + } + } + } else { + if (hours_1 > 0 && !show_seconds_only) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d", sign, hours_1, minutes_1, seconds_1, + centiseconds_1); + } else if (minutes_1 > 0 && !show_seconds_only) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(A, b, color, "%s%02d:%02d.%02d", sign, minutes_1, seconds_1, + centiseconds_1); + } else { + u32 total_seconds_1 = + seconds_1 + (minutes_1 * MINUTE_FRAMES + hours_1 * HOUR_FRAMES) / SECOND_FRAMES; + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%02d.%02d", sign, total_seconds_1, centiseconds_1); + } + } +} + } // namespace timerdisp diff --git a/src/utils/timerdisp.h b/src/utils/timerdisp.h index db0b3dfc..b072c95b 100644 --- a/src/utils/timerdisp.h +++ b/src/utils/timerdisp.h @@ -5,6 +5,7 @@ namespace timerdisp { void draw_timer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, bool show_minutes); -void draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_minutes, bool second_argument, s32 frames_2); +void draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color); +void draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds_only, bool second_argument, s32 frames_2); } From 60848bdd8cae2bf436c54f4e0f1ed8a6a7f3322a Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 31 Oct 2023 01:00:05 -0500 Subject: [PATCH 03/45] somewhat fixed some issues with the timer missing frames --- src/mods/storytimer.cpp | 71 +++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index cde02991..40b61d9b 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -64,6 +64,13 @@ static u32 s_segment_timer[10]; static bool s_is_on_world[10]; static bool s_can_change_segment_start_time[10]; static u32 s_segment_timer_location; +static u32 s_spin_in_init_timer; +static bool s_stage_selected_state; +static bool s_can_increment_spin_in_init_timer; +static bool s_has_incremented_spin_in_init_timer; +static u32 s_previous_spin_in_init_timer; +static u32 s_game_scenario_return_timer; +static u32 s_correction_timer; void tick() { if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ @@ -123,6 +130,44 @@ void tick() { } */ + /* + // trying to detect the missing frame during spin + if (mkb::g_storymode_mode == 5) { + s_can_increment_spin_in_init_timer = false; + } + + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { + s_stage_selected_state = true; + s_previous_spin_in_init_timer = s_spin_in_init_timer; + } else { + false; + } + + if (s_stage_selected_state == false ) { + s_can_increment_spin_in_init_timer = true; + } + + if (s_can_increment_spin_in_init_timer == true) { + s_spin_in_init_timer +=1; + } + + if ( (s_spin_in_init_timer - s_previous_spin_in_init_timer) >0 ) { + s_can_increment_spin_in_init_timer = false; + } + */ + + // no idea why the spin_in_init_timer only properly incremenents when it's not in the if (s_run_timer == true){ statement below (I checked and s_run_timer always remains true during spin in) + // this is very jank I hate it so much + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { + s_spin_in_init_timer += 1; + } + + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + s_game_scenario_return_timer += 1; + } + + s_correction_timer = s_spin_in_init_timer + s_game_scenario_return_timer; + // submodes during spin in if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_MAIN) { s_is_on_spin_in = true; @@ -165,11 +210,13 @@ void tick() { if (mkb::g_storymode_mode == 5){ // zero the timer on the file select screen and set the number of completed stages to 0 + s_spin_in_init_timer = 0; s_spin_in_timer = 0 ; s_gameplay_timer = 0; s_postgoal_timer = 0; // s_postgoal_replay_timer = 0; s_stage_select_timer = 0; + s_game_scenario_return_timer = 0; s_exit_game_timer = 0; s_fallout_timer = 0; s_run_timer = false; @@ -178,7 +225,9 @@ void tick() { s_completed_stages = 0; s_prev_completed_stage_count = 0; } else{ - s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer; + // trying to figure out missing frames + // for some reason, separately including s_spin_in_init_timer doesn't cause the visual frame skip in the timer + s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer+s_spin_in_init_timer+s_game_scenario_return_timer; } if (s_run_timer == true){ @@ -186,6 +235,12 @@ void tick() { // increment the timer every frame during spin in s_spin_in_timer +=1; } + /* + no idea why putting this here makes this timer not work correctly, but it works correctly above + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { + s_spin_in_init_timer += 1; + } + */ if (mkb::sub_mode==mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_PLAY_MAIN) { //increment the timer every frame during gameplay s_gameplay_timer +=1; @@ -309,11 +364,9 @@ void tick() { } */ - if (s_is_on_world[1] == true) { - s_dummy_2 = 1; - } else { - s_dummy_2 = 0; - } + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { + s_dummy_2 += 1; + } } @@ -332,7 +385,7 @@ void tick() { */ - if (s_is_between_worlds == true){ + if (s_run_timer == true){ s_dummy = 1; } else { s_dummy = 0; @@ -475,8 +528,8 @@ if (s_in_story == false || freecam::should_hide_hud() ){ */ // debugging - timerdisp::draw_timer(static_cast(60*s_completed_stages), "Splt:", 0, draw::WHITE, true); - timerdisp::draw_timer(static_cast(60*s_prev_completed_stage_count), "Splt:", 1, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*mkb::sub_mode), "Splt:", 0, draw::WHITE, true); + timerdisp::draw_timer(static_cast(s_dummy), "Splt:", 1, draw::WHITE, true); // draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) (reference) // if (IlBattleLength(pref::get(pref::U8Pref::IlBattleLength)) == IlBattleLength::Endless); (reference) } From 835c8d838555cb14ef94d82bdaf28e22fe3c3927 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sun, 5 Nov 2023 01:52:37 -0500 Subject: [PATCH 04/45] fixed the missing frames issue (kinda jank fix) for the loadless timer --- src/mods/storytimer.cpp | 148 +++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 72 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 40b61d9b..be240db5 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -71,6 +71,14 @@ static bool s_has_incremented_spin_in_init_timer; static u32 s_previous_spin_in_init_timer; static u32 s_game_scenario_return_timer; static u32 s_correction_timer; +static u32 s_corrected_stage_select_timer; +static bool s_is_on_world_first_intro_sequence[10]; +static bool s_has_entered_world[10]; +static bool s_has_corrected_stage_select_timer[10]; +static bool s_is_on_first_frame_of_world[10]; +static bool s_has_passed_first_frame_of_world[10]; +static bool s_can_detect_first_frame_of_world[10]; +static bool s_has_done_start_world_correction[10]; void tick() { if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ @@ -124,6 +132,17 @@ void tick() { s_lower_stage_counter = false; } + for (s32 k=1; k<11; k++) { + /* + if ( s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_has_done_start_world_correction[k] == false && k != 1) { + s_corrected_stage_select_timer += 1; + s_has_done_start_world_correction[k] == true; + } + */ + if (s_is_on_world[k] == true) { + s_corrected_stage_select_timer = 2*k; + } + } /* if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { s_completed_stages +=1; @@ -166,7 +185,7 @@ void tick() { s_game_scenario_return_timer += 1; } - s_correction_timer = s_spin_in_init_timer + s_game_scenario_return_timer; + s_correction_timer = s_spin_in_init_timer + s_game_scenario_return_timer+s_corrected_stage_select_timer; // submodes during spin in if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_MAIN) { @@ -224,10 +243,20 @@ void tick() { s_loadless_story_timer = 0; s_completed_stages = 0; s_prev_completed_stage_count = 0; + s_corrected_stage_select_timer = 0; + for (s32 k=1; k<11; k++) { + s_has_done_start_world_correction[k] = false; + } } else{ // trying to figure out missing frames // for some reason, separately including s_spin_in_init_timer doesn't cause the visual frame skip in the timer - s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer+s_spin_in_init_timer+s_game_scenario_return_timer; + // last 3 terms are correction terms to account for missing frames + s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer + +s_spin_in_init_timer+s_game_scenario_return_timer+s_corrected_stage_select_timer; + } + // on the file select screen, set these to false just in case you reset while on world k but did not complete 10k stages + for (s32 k=1; k<11; k++){ + s_is_on_world[k] = false; } if (s_run_timer == true){ @@ -344,51 +373,55 @@ void tick() { s_is_on_world[k-1] = false; s_is_on_world[k] = true; } else if (s_completed_stages == 10*k && s_is_postgoal == true && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT) { + // testing what happens when adding the scenario return part, since if you are on world k+1, have not completed a stage, and stage select back to the 10 ball screen, + // the code thinks you are on world k for 1 frame + // && mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN s_is_on_world[k] = true; } - - /* can't use switch case in for loop :( - - switch (s_completed_stages) { - case ( (10*(k-1) +1<= s_completed_stages) && (s_completed_stages <= (10*k-1)) ): - s_is_on_world[k] = true; - break; - case (s_completed_stages == 10*(k-1) && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE): - s_is_on_world[k-1] = false; - s_is_on_world[k] = true; - break; - case (s_completed_stages == 10*k && s_is_postgoal == true): - s_is_on_world[k] = true; - break; + // missing frames at the start of each world + + /* + if (s_completed_stages == 10*(k-1) && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + s_has_entered_world[k] = true; + } else { + s_has_entered_world[k] = false; } - */ - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { - s_dummy_2 += 1; - } - } + if (s_has_entered_world[k] == true && s_has_corrected_stage_select_timer[k] == false) { + s_corrected_stage_select_timer = s_stage_select_timer+2*k; + } + if ((s_corrected_stage_select_timer - s_stage_select_timer) == 2*k) { + s_has_corrected_stage_select_timer[k] = true; + } else { + s_has_corrected_stage_select_timer[k] = false; + } - /* - if ( ( (10*(k-1)-1 < s_completed_stages) && (s_completed_stages < 10*k-1) ) || (s_completed_stages == 10*k-1 && s_is_postgoal == false) ){ - s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k]; + if (mkb::g_storymode_mode == 5) { + s_has_passed_first_frame_of_world[k] = false; } - - // display split and iw time after breaking the tape on the last stage of a world, but stop displaying when the stage select screen for the next world starts spinning in - if ((s_completed_stages == 10*k-1 || s_completed_stages == 10*k ) && mkb::g_storymode_stageselect_state != mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_display_segment = true; - } else if (s_completed_stages == 10*k && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_display_segment = false; + if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_RETURN) { + s_can_detect_first_frame_of_world[k] = true; } + if (s_can_detect_first_frame_of_world[k] == true && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE && s_has_passed_first_frame_of_world[k] == false) { + s_is_on_first_frame_of_world[k] = true; + s_has_passed_first_frame_of_world[k] = true; + } + */ + + if (mkb::g_storymode_stageselect_state == 1) { + s_dummy_2 = 1; + } else{ + s_dummy_2 = 0; + } + } - */ - - if (s_run_timer == true){ - s_dummy = 1; - } else { - s_dummy = 0; + if (mkb::g_storymode_mode == 5){ + s_dummy = 1; + } else { + s_dummy = 0; /* things tested that didn't work for exit game so far SMD_GAME_FORCE_EXIT_MAIN=93 SMD_GAME_FORCE_OVER_MAIN=96 @@ -422,23 +455,9 @@ void tick() { } void disp() { - // timerdisp::draw_timer(static_cast(s_display_segment), "Splt:", 1, draw::WHITE, true); - // timerdisp::draw_timer(static_cast(60*mkb::sub_mode), "dbg:", 4, draw::WHITE, true); - // timerdisp::draw_timer(static_cast(s_segment_timer[2]), "IW:", 3, draw::WHITE, true); -/* - if (FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_AlwaysShow){ - timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false); + if (s_in_story == false || freecam::should_hide_hud() ){ + return; } -*/ - /* - if (mkb::main_mode != mkb::MD_GAME || mkb::main_game_mode != mkb::STORY_MODE || - freecam::should_hide_hud()) { - return; - } -*/ -if (s_in_story == false || freecam::should_hide_hud() ){ - return; - } switch(FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions))) { case FullgameTimerOptions::F_AlwaysShow: @@ -484,7 +503,7 @@ if (s_in_story == false || freecam::should_hide_hud() ){ timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, false, 0); } else if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Time:", 1, draw::WHITE, false, true, s_split[k]); + timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, true, s_split[k]); } } break; @@ -493,7 +512,7 @@ if (s_in_story == false || freecam::should_hide_hud() ){ // otherwise use the format split time (iw time) for (s32 k=1; k<11; k++){ if (s_display_segment_timer == true && s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_storytimer(static_cast(s_split[k]), "Time:", 1, draw::WHITE, false, true, s_segment_timer[k]); + timerdisp::draw_storytimer(static_cast(s_split[k]), "Seg:", 1, draw::WHITE, false, true, s_segment_timer[k]); } } break; @@ -511,25 +530,10 @@ if (s_in_story == false || freecam::should_hide_hud() ){ } } -/* - for (s32 k=1; k<11; k++){ - if (s_display_story_timer == true && s_is_between_worlds == false){ - timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false, false, 0); - } else if (s_display_story_timer == true && s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false, true, s_split[k]); - } - if (s_display_segment_timer == true && s_is_on_world[k] == true && s_is_run_complete == false) { - timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, false, 0); - } else if (s_display_segment_timer == true && s_is_run_complete == true) { - timerdisp::draw_storytimer(static_cast(s_split[k]), "Splt:", k, draw::WHITE, false, true, s_segment_timer[k]); - // to do: modify draw_storytimer so that you can display in the format "World k: split k time (segment k time)" - } - } -*/ - // debugging - timerdisp::draw_timer(static_cast(60*mkb::sub_mode), "Splt:", 0, draw::WHITE, true); - timerdisp::draw_timer(static_cast(s_dummy), "Splt:", 1, draw::WHITE, true); + timerdisp::draw_timer(static_cast(s_is_on_world[1]), "dbg1:", 0, draw::WHITE, true); + timerdisp::draw_timer(static_cast(s_is_on_world[2]), "dbg2:", 1, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*s_dummy), "dbg3:", 2, draw::WHITE, true); // draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) (reference) // if (IlBattleLength(pref::get(pref::U8Pref::IlBattleLength)) == IlBattleLength::Endless); (reference) } From bd51ae14f92d7a681e4d674711ccc79cfb69ca96 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sun, 5 Nov 2023 11:08:29 -0600 Subject: [PATCH 05/45] fixed segments not showing up when run ends --- src/mods/storytimer.cpp | 158 +++++++++++++++++++++++--------------- src/systems/menu_defn.cpp | 8 ++ src/systems/pref.cpp | 6 ++ src/systems/pref.h | 1 + 4 files changed, 112 insertions(+), 61 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index be240db5..42f3762d 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -38,6 +38,7 @@ static u32 s_loadless_story_timer; static bool s_run_timer; static bool s_is_on_spin_in; static bool s_is_on_stage_select_screen; +static bool s_is_on_gameplay; static bool s_is_on_exit_game_screen; static bool s_is_on_fallout_screen; static bool s_is_postgoal; @@ -49,9 +50,9 @@ static s32 s_completed_stages; static u32 s_dummy; static u32 s_dummy_2; static u32 s_dummy_3; -static u32 s_split[10]; // s_split[k] is the loadless time on tape break of the 10th stage of world k -static u32 s_segment_time[10]; // s_segment_time[k] is the loadless time spent on world k, starting from stage select spin in to tape break on the 10th stage -static u32 s_segment_start_time[10]; // the loadless time at the start of world k, used to calculate s_segment_time[k] +static u32 s_split[11]; // s_split[k] is the loadless time on tape break of the 10th stage of world k +static u32 s_segment_time[11]; // s_segment_time[k] is the loadless time spent on world k, starting from stage select spin in to tape break on the 10th stage +static u32 s_segment_start_time[11]; // the loadless time at the start of world k, used to calculate s_segment_time[k] static bool s_display_story_timer; static bool s_display_segment_timer; static bool s_display_split; @@ -60,9 +61,9 @@ static bool s_display_segment; static bool s_is_between_worlds; static bool s_passed_cutscene; static bool s_is_run_complete; -static u32 s_segment_timer[10]; -static bool s_is_on_world[10]; -static bool s_can_change_segment_start_time[10]; +static u32 s_segment_timer[11]; +static bool s_is_on_world[11]; +static bool s_can_change_segment_start_time[11]; static u32 s_segment_timer_location; static u32 s_spin_in_init_timer; static bool s_stage_selected_state; @@ -72,13 +73,20 @@ static u32 s_previous_spin_in_init_timer; static u32 s_game_scenario_return_timer; static u32 s_correction_timer; static u32 s_corrected_stage_select_timer; -static bool s_is_on_world_first_intro_sequence[10]; -static bool s_has_entered_world[10]; -static bool s_has_corrected_stage_select_timer[10]; -static bool s_is_on_first_frame_of_world[10]; -static bool s_has_passed_first_frame_of_world[10]; -static bool s_can_detect_first_frame_of_world[10]; -static bool s_has_done_start_world_correction[10]; +static bool s_is_on_world_first_intro_sequence[11]; +static bool s_has_entered_world[11]; +static bool s_has_corrected_stage_select_timer[11]; +static bool s_is_on_first_frame_of_world[11]; +static bool s_has_passed_first_frame_of_world[11]; +static bool s_can_detect_first_frame_of_world[11]; +static bool s_has_done_start_world_correction[11]; +static constexpr s32 fullgame_timer_location_x = 18; +static constexpr s32 fullgame_timer_text_offset = 54; +static constexpr s32 segment_timer_location_x = 29; +static constexpr s32 segment_timer_text_offset = 43; +static constexpr s32 IW_time_location_x = 40; +static constexpr s32 IW_time_text_offset = 32; +static constexpr s32 Y=24; void tick() { if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ @@ -178,12 +186,12 @@ void tick() { // no idea why the spin_in_init_timer only properly incremenents when it's not in the if (s_run_timer == true){ statement below (I checked and s_run_timer always remains true during spin in) // this is very jank I hate it so much if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - s_spin_in_init_timer += 1; - } + s_spin_in_init_timer += 1; + } if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - s_game_scenario_return_timer += 1; - } + s_game_scenario_return_timer += 1; + } s_correction_timer = s_spin_in_init_timer + s_game_scenario_return_timer+s_corrected_stage_select_timer; @@ -203,6 +211,13 @@ void tick() { s_is_on_stage_select_screen = false; } + // submodes during gameplay + if (mkb::sub_mode==mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_PLAY_MAIN) { + s_is_on_gameplay = true; + } else { + s_is_on_gameplay = false; + } + // submodes entered when exiting game if (mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT || mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_MAIN || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_INIT || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_MAIN) { @@ -255,10 +270,13 @@ void tick() { +s_spin_in_init_timer+s_game_scenario_return_timer+s_corrected_stage_select_timer; } // on the file select screen, set these to false just in case you reset while on world k but did not complete 10k stages + // need to stipulate s_run_timer is false otherwise there's weird behavior on the first stage of e/ world for (s32 k=1; k<11; k++){ - s_is_on_world[k] = false; + if (s_run_timer == false){ + s_is_on_world[k] = false; + } } - + if (s_run_timer == true){ if (s_is_on_spin_in == true) { // increment the timer every frame during spin in @@ -302,14 +320,30 @@ void tick() { if (s_completed_stages == 99 && mkb::sub_mode ==mkb::SMD_GAME_GOAL_INIT){ // stop the timer after breaking the tape on stage 100 // to do: make this work for story mode packs with less than 100 stages like kaizo - s_run_timer = false; + + // when completing a run, first correct by 2 frames since the timer will run for 2f after breaking the tape, + // then set s_run_timer to false so that if we pause on goal init, we don't subtract 2 from the timer every frame while paused + /* + if (s_run_timer == true) { + // s_loadless_story_timer = s_loadless_story_timer - 2; + s_loadless_story_timer = s_segment_start_time[10]+s_segment_timer[10]; + s_run_timer = false; } - + */ + } + if (s_completed_stages == 100) { + s_is_run_complete = true; + s_loadless_story_timer = s_segment_start_time[10]+s_segment_timer[10]; + } else { + s_is_run_complete = false; + } + /* if (s_completed_stages == 100 && s_is_postgoal == true) { s_is_run_complete = true; } else { s_is_run_complete = false; } + */ if ( (mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { s_in_story = true; @@ -369,47 +403,15 @@ void tick() { if ( ( (10*(k-1) +1)<= s_completed_stages) && (s_completed_stages <= (10*k-1)) ) { s_is_on_world[k] = true; - } else if (s_completed_stages == 10*(k-1) && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ + } else if (s_completed_stages == 10*(k-1) && (s_is_on_stage_select_screen == true || s_is_on_spin_in == true || s_is_on_gameplay == true) ){ s_is_on_world[k-1] = false; s_is_on_world[k] = true; - } else if (s_completed_stages == 10*k && s_is_postgoal == true && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT) { + } else if (s_completed_stages == 10*k && s_is_postgoal == true && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT && mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN) { // testing what happens when adding the scenario return part, since if you are on world k+1, have not completed a stage, and stage select back to the 10 ball screen, // the code thinks you are on world k for 1 frame - // && mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN s_is_on_world[k] = true; } - // missing frames at the start of each world - - /* - if (s_completed_stages == 10*(k-1) && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_has_entered_world[k] = true; - } else { - s_has_entered_world[k] = false; - } - - if (s_has_entered_world[k] == true && s_has_corrected_stage_select_timer[k] == false) { - s_corrected_stage_select_timer = s_stage_select_timer+2*k; - } - - if ((s_corrected_stage_select_timer - s_stage_select_timer) == 2*k) { - s_has_corrected_stage_select_timer[k] = true; - } else { - s_has_corrected_stage_select_timer[k] = false; - } - - - if (mkb::g_storymode_mode == 5) { - s_has_passed_first_frame_of_world[k] = false; - } - if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_RETURN) { - s_can_detect_first_frame_of_world[k] = true; - } - if (s_can_detect_first_frame_of_world[k] == true && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE && s_has_passed_first_frame_of_world[k] == false) { - s_is_on_first_frame_of_world[k] = true; - s_has_passed_first_frame_of_world[k] = true; - } - */ if (mkb::g_storymode_stageselect_state == 1) { s_dummy_2 = 1; @@ -451,10 +453,16 @@ void tick() { */ } - + // debugging + /* + if (pad::button_pressed(mkb::PAD_BUTTON_DOWN)) { + s_completed_stages = 91; + } + */ } void disp() { + if (s_in_story == false || freecam::should_hide_hud() ){ return; } @@ -503,7 +511,7 @@ void disp() { timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, false, 0); } else if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, true, s_split[k]); + timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, false, s_split[k]); } } break; @@ -512,7 +520,7 @@ void disp() { // otherwise use the format split time (iw time) for (s32 k=1; k<11; k++){ if (s_display_segment_timer == true && s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_storytimer(static_cast(s_split[k]), "Seg:", 1, draw::WHITE, false, true, s_segment_timer[k]); + timerdisp::draw_storytimer(static_cast(s_split[k]), "Seg:", 1, draw::WHITE, false, false, s_segment_timer[k]); } } break; @@ -523,18 +531,46 @@ void disp() { // if the segment timer is enabled in any capacity, show all 10 split times + iw times after the tape is broken on the last stage if (SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != SegmentTimerOptions::S_DontShow) { + /* for (s32 k=1; k<11; k++){ if (s_is_run_complete == true){ timerdisp::draw_storytimer(static_cast(s_split[k]), "Splt:", k+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[k]); } } + */ + if (s_is_run_complete == true){ + // I'm so sorry :( + // I don't know how to get the text to show "Wk" where k ranges in a for loop + timerdisp::draw_storytimer(static_cast(s_split[1]), "W1:", 1+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[1]); + timerdisp::draw_storytimer(static_cast(s_split[2]), "W2:", 2+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[2]); + timerdisp::draw_storytimer(static_cast(s_split[3]), "W3:", 3+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[3]); + timerdisp::draw_storytimer(static_cast(s_split[4]), "W4:", 4+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[4]); + timerdisp::draw_storytimer(static_cast(s_split[5]), "W5:", 5+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[5]); + timerdisp::draw_storytimer(static_cast(s_split[6]), "W6:", 6+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[6]); + timerdisp::draw_storytimer(static_cast(s_split[7]), "W7:", 7+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[7]); + timerdisp::draw_storytimer(static_cast(s_split[8]), "W8:", 8+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[8]); + timerdisp::draw_storytimer(static_cast(s_split[9]), "W9:", 9+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[9]); + timerdisp::draw_storytimer(static_cast(s_split[10]), "W10:", 10+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[10]); + } } + // (to do) toggle-able warning if no timers are going to display during the run + // debugging - timerdisp::draw_timer(static_cast(s_is_on_world[1]), "dbg1:", 0, draw::WHITE, true); - timerdisp::draw_timer(static_cast(s_is_on_world[2]), "dbg2:", 1, draw::WHITE, true); - timerdisp::draw_timer(static_cast(60*s_dummy), "dbg3:", 2, draw::WHITE, true); + /* + timerdisp::draw_timer(static_cast(s_run_timer), "dbg1:", 0, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*s_is_run_complete), "dbg2:", 1, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*s_completed_stages), "dbg3:", 2, draw::WHITE, true); + timerdisp::draw_timer(static_cast(s_segment_start_time[10]), "dbg4:", 3, draw::WHITE, true); + timerdisp::draw_timer(static_cast(s_segment_timer[10]), "dbg5:", 4, draw::WHITE, true); + + timerdisp::draw_timer_general(fullgame_timer_location_x, 8, fullgame_timer_text_offset, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); + timerdisp::draw_timer_general(segment_timer_location_x, 40, segment_timer_text_offset, "Seg:", s_loadless_story_timer, 0, false, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, 56, IW_time_text_offset, "IW:", s_loadless_story_timer, 0, false, false, draw::WHITE); + */ // draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) (reference) +// draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color) (reference) +// timerdisp text offset for 5 characters (includes :) is 54; for 4 characters, try an additional 54 for the x pos, // if (IlBattleLength(pref::get(pref::U8Pref::IlBattleLength)) == IlBattleLength::Endless); (reference) } diff --git a/src/systems/menu_defn.cpp b/src/systems/menu_defn.cpp index 96cc57f5..ef599ed6 100644 --- a/src/systems/menu_defn.cpp +++ b/src/systems/menu_defn.cpp @@ -693,6 +693,14 @@ static Widget s_loadless_timers_widgets[] = { .pref = pref::U8Pref::SegmentTimerOptions, }, }, + { + .type = WidgetType::Checkbox, + .checkbox = + { + .label = "Timer Not On Warning", + .pref = pref::BoolPref::StoryTimerWarning, + }, + }, }; static Widget s_timers_widgets[] = { diff --git a/src/systems/pref.cpp b/src/systems/pref.cpp index 988e271f..aacb37fb 100644 --- a/src/systems/pref.cpp +++ b/src/systems/pref.cpp @@ -89,6 +89,7 @@ enum class PrefId : u16 { SavestateClearBind = 69, FullgameTimerOptions = 70, SegmentTimerOptions = 71, + StoryTimerWarning = 72, }; // Verbatim list of preference IDs we iterate over when writing savefile back out @@ -159,6 +160,9 @@ static const PrefId s_pref_ids[] = { PrefId::FreecamToggleBind, PrefId::SavestateClearBind, PrefId::FalloutPlaneType, + PrefId::FullgameTimerOptions, + PrefId::SegmentTimerOptions, + PrefId::StoryTimerWarning, }; static std::optional pref_id_to_bool_pref(PrefId id) { @@ -247,6 +251,8 @@ static std::optional pref_id_to_bool_pref(PrefId id) { return BoolPref::UseCustomPhysics; case PrefId::SavestateDisableOverwrite: return BoolPref::SavestateDisableOverwrite; + case PrefId::StoryTimerWarning: + return BoolPref::StoryTimerWarning; default: return {}; } diff --git a/src/systems/pref.h b/src/systems/pref.h index 9bd2b117..b75865c3 100644 --- a/src/systems/pref.h +++ b/src/systems/pref.h @@ -49,6 +49,7 @@ enum class BoolPref : u8 { IlBattleBuzzerOld, UseCustomPhysics, SavestateDisableOverwrite, + StoryTimerWarning, }; enum class U8Pref : u8 { From f9cfe63bc6e398efcbb15a1cb068831d6ab51d6f Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sun, 5 Nov 2023 15:19:31 -0600 Subject: [PATCH 06/45] added a story death counter --- src/mods/deathcounter.cpp | 55 +++++++++++++++++++++++++++++++++++++++ src/mods/deathcounter.h | 8 ++++++ src/systems/main.cpp | 3 +++ src/systems/menu_defn.cpp | 8 ++++++ src/systems/pref.cpp | 4 +++ src/systems/pref.h | 1 + 6 files changed, 79 insertions(+) create mode 100644 src/mods/deathcounter.cpp create mode 100644 src/mods/deathcounter.h diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp new file mode 100644 index 00000000..04c8ac60 --- /dev/null +++ b/src/mods/deathcounter.cpp @@ -0,0 +1,55 @@ +#include "mkb/mkb.h" + +#include "mods/freecam.h" +#include "systems/assembly.h" +#include "systems/pad.h" +#include "systems/pref.h" +#include "utils/draw.h" +#include "utils/patch.h" +#include "utils/timerdisp.h" + +namespace deathcounter { + +static bool s_can_die; +static u32 s_death_count; +static bool s_in_story; + +void tick() { + + if ( (mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { + s_in_story = true; + } else{ + s_in_story = false; + } + + // set the death count to 0 on the file select screen + if (mkb::g_storymode_mode == 5) { + s_death_count = 0; + } + + if (mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { + s_can_die = true; + } + + if ( (mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT) && s_can_die == true){ + s_death_count += 1; + s_can_die = false; + } + + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { + s_can_die = false; + } + +} + +void disp() { + + if (s_in_story == false || freecam::should_hide_hud() || pref::get(pref::BoolPref::ShowDeathCounter) == false ){ + return; + } + draw::debug_text(18, 56, draw::WHITE, "Deaths: "); + draw::debug_text(100, 56, draw::WHITE, "%d", s_death_count); + +} + +} // namespace deathcounter diff --git a/src/mods/deathcounter.h b/src/mods/deathcounter.h new file mode 100644 index 00000000..68d11abb --- /dev/null +++ b/src/mods/deathcounter.h @@ -0,0 +1,8 @@ +#pragma once + +namespace deathcounter { + +void tick(); +void disp(); + +} // namespace deathcounter \ No newline at end of file diff --git a/src/systems/main.cpp b/src/systems/main.cpp index 1c870286..5822ce55 100644 --- a/src/systems/main.cpp +++ b/src/systems/main.cpp @@ -16,6 +16,7 @@ #include "mods/banans.h" #include "mods/camera.h" #include "mods/cmseg.h" +#include "mods/deathcounter.h" #include "mods/dpad.h" #include "mods/fallout.h" #include "mods/freecam.h" @@ -118,6 +119,7 @@ void init() { physics::tick(); iw::tick(); storytimer::tick(); + deathcounter::tick(); savest_ui::tick(); menu_impl::tick(); jump::tick(); @@ -153,6 +155,7 @@ void init() { timer::disp(); iw::disp(); storytimer::disp(); + deathcounter::disp(); Tetris::get_instance().disp(); ilbattle::disp(); cmseg::disp(); diff --git a/src/systems/menu_defn.cpp b/src/systems/menu_defn.cpp index ef599ed6..b5e031b0 100644 --- a/src/systems/menu_defn.cpp +++ b/src/systems/menu_defn.cpp @@ -1249,6 +1249,14 @@ static Widget s_displays_widgets[] = { .pref = pref::BoolPref::BananaCounter9999, }, }, + { + .type = WidgetType::Checkbox, + .checkbox = + { + .label = "Show Death Counter", + .pref = pref::BoolPref::ShowDeathCounter, + }, + }, }; static Widget s_enabled_physics_widgets[] = { diff --git a/src/systems/pref.cpp b/src/systems/pref.cpp index aacb37fb..146e8c33 100644 --- a/src/systems/pref.cpp +++ b/src/systems/pref.cpp @@ -90,6 +90,7 @@ enum class PrefId : u16 { FullgameTimerOptions = 70, SegmentTimerOptions = 71, StoryTimerWarning = 72, + ShowDeathCounter = 73, }; // Verbatim list of preference IDs we iterate over when writing savefile back out @@ -163,6 +164,7 @@ static const PrefId s_pref_ids[] = { PrefId::FullgameTimerOptions, PrefId::SegmentTimerOptions, PrefId::StoryTimerWarning, + PrefId::ShowDeathCounter, }; static std::optional pref_id_to_bool_pref(PrefId id) { @@ -253,6 +255,8 @@ static std::optional pref_id_to_bool_pref(PrefId id) { return BoolPref::SavestateDisableOverwrite; case PrefId::StoryTimerWarning: return BoolPref::StoryTimerWarning; + case PrefId::ShowDeathCounter: + return BoolPref::ShowDeathCounter; default: return {}; } diff --git a/src/systems/pref.h b/src/systems/pref.h index b75865c3..c1103b87 100644 --- a/src/systems/pref.h +++ b/src/systems/pref.h @@ -50,6 +50,7 @@ enum class BoolPref : u8 { UseCustomPhysics, SavestateDisableOverwrite, StoryTimerWarning, + ShowDeathCounter, }; enum class U8Pref : u8 { From c78143f2af529a4c1eed82365a09565fa5fa5db1 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Mon, 6 Nov 2023 06:34:20 -0600 Subject: [PATCH 07/45] fixed timer/death counter spacing + timer not on warning --- src/mods/deathcounter.cpp | 6 ++- src/mods/storytimer.cpp | 99 ++++++++++++++++++++++++--------------- src/utils/timerdisp.cpp | 2 +- 3 files changed, 67 insertions(+), 40 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 04c8ac60..028cbd0d 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -36,7 +36,9 @@ void tick() { s_can_die = false; } - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { + // first framing should not increase the death counter, and retrying after breaking the tape should not increase it either + // to do: however, if you retry after breaking the tape on the very first frame (so the frame before goal init), it does count as a death when it should not + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { s_can_die = false; } @@ -50,6 +52,8 @@ void disp() { draw::debug_text(18, 56, draw::WHITE, "Deaths: "); draw::debug_text(100, 56, draw::WHITE, "%d", s_death_count); + // to do so I don't forget: get pref for the storytimers so that the the text doesn't overlap + } } // namespace deathcounter diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 42f3762d..0f310b4e 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -64,7 +64,8 @@ static bool s_is_run_complete; static u32 s_segment_timer[11]; static bool s_is_on_world[11]; static bool s_can_change_segment_start_time[11]; -static u32 s_segment_timer_location; +static u32 s_fullgame_timer_location_y; +static u32 s_segment_timer_location_y; static u32 s_spin_in_init_timer; static bool s_stage_selected_state; static bool s_can_increment_spin_in_init_timer; @@ -80,11 +81,11 @@ static bool s_is_on_first_frame_of_world[11]; static bool s_has_passed_first_frame_of_world[11]; static bool s_can_detect_first_frame_of_world[11]; static bool s_has_done_start_world_correction[11]; -static constexpr s32 fullgame_timer_location_x = 18; -static constexpr s32 fullgame_timer_text_offset = 54; -static constexpr s32 segment_timer_location_x = 29; -static constexpr s32 segment_timer_text_offset = 43; -static constexpr s32 IW_time_location_x = 40; +static constexpr s32 fullgame_timer_location_x = 18+24; +static constexpr s32 fullgame_timer_text_offset = 56; +static constexpr s32 segment_timer_location_x = 30+24; +static constexpr s32 segment_timer_text_offset = 44; +static constexpr s32 IW_time_location_x = 42+24; static constexpr s32 IW_time_text_offset = 32; static constexpr s32 Y=24; @@ -420,7 +421,7 @@ void tick() { } } - if (mkb::g_storymode_mode == 5){ + if (mkb::g_storymode_mode == 21){ s_dummy = 1; } else { s_dummy = 0; @@ -467,6 +468,22 @@ void disp() { return; } + if (pref::get(pref::BoolPref::ShowDeathCounter) == true) { + s_fullgame_timer_location_y = 1; + } else { + s_fullgame_timer_location_y = 0; + } + + // if the fullgame timer and death counter is off but the segment timer is on, move the segment timer to the top line; if either the fullgame timer or death counter are on but not both are on, + // move it to the 2nd line, if all 3 are enabled, put it on the 3rd line + if(s_display_story_timer == false && pref::get(pref::BoolPref::ShowDeathCounter) == false ){ + s_segment_timer_location_y = 0; + } else if (s_display_story_timer == false || pref::get(pref::BoolPref::ShowDeathCounter) == false ){ + s_segment_timer_location_y = 1; + } else { + s_segment_timer_location_y = 2; + } + switch(FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions))) { case FullgameTimerOptions::F_AlwaysShow: s_display_story_timer = true; @@ -491,36 +508,31 @@ void disp() { } if (s_display_story_timer == true){ - timerdisp::draw_storytimer(static_cast(s_loadless_story_timer), "Time:", 0, draw::WHITE, false, false, 0); + timerdisp::draw_timer_general(fullgame_timer_location_x, s_fullgame_timer_location_y, fullgame_timer_text_offset, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); } - - // if the fullgame timer is off but the segment timer is on, move the segment timer up by 1 line - if(FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_DontShow){ - s_segment_timer_location = 1; - } else { - s_segment_timer_location = 0; - } switch(SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { case SegmentTimerOptions::S_AlwaysShow: s_display_segment_timer = true; // if the segment timer is always showing, // use the format iw time (split time) after breaking the tape on the last stage of a world + // to do: get the spacing right for showing the on tape break split time; currently I have show second argument set to false between worlds for (s32 k=1; k<11; k++){ if (s_display_segment_timer == true && s_is_on_world[k] == true && s_is_between_worlds == false && s_is_run_complete == false) { - timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, false, 0); + timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); } else if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_storytimer(static_cast(s_segment_timer[k]), "Seg:", 1, draw::WHITE, false, false, s_split[k]); + timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], s_split[k], false, false, draw::WHITE); } } break; case SegmentTimerOptions::S_BetweenWorlds: s_display_segment_timer = true; - // otherwise use the format split time (iw time) + // otherwise use the format split time (iw time) + // to do: switch around arguments if I fix the spacing for (s32 k=1; k<11; k++){ if (s_display_segment_timer == true && s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_storytimer(static_cast(s_split[k]), "Seg:", 1, draw::WHITE, false, false, s_segment_timer[k]); + timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], s_split[k], false, false, draw::WHITE); } } break; @@ -534,39 +546,50 @@ void disp() { /* for (s32 k=1; k<11; k++){ if (s_is_run_complete == true){ - timerdisp::draw_storytimer(static_cast(s_split[k]), "Splt:", k+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[k]); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+k, IW_time_text_offset, "Wk:", s_split[k], s_segment_timer[k], true, false, draw::WHITE); } } */ - if (s_is_run_complete == true){ + if (s_is_run_complete == true) { // I'm so sorry :( // I don't know how to get the text to show "Wk" where k ranges in a for loop - timerdisp::draw_storytimer(static_cast(s_split[1]), "W1:", 1+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[1]); - timerdisp::draw_storytimer(static_cast(s_split[2]), "W2:", 2+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[2]); - timerdisp::draw_storytimer(static_cast(s_split[3]), "W3:", 3+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[3]); - timerdisp::draw_storytimer(static_cast(s_split[4]), "W4:", 4+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[4]); - timerdisp::draw_storytimer(static_cast(s_split[5]), "W5:", 5+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[5]); - timerdisp::draw_storytimer(static_cast(s_split[6]), "W6:", 6+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[6]); - timerdisp::draw_storytimer(static_cast(s_split[7]), "W7:", 7+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[7]); - timerdisp::draw_storytimer(static_cast(s_split[8]), "W8:", 8+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[8]); - timerdisp::draw_storytimer(static_cast(s_split[9]), "W9:", 9+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[9]); - timerdisp::draw_storytimer(static_cast(s_split[10]), "W10:", 10+s_segment_timer_location, draw::WHITE, false, true, s_segment_timer[10]); - } + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+1, IW_time_text_offset, "W1:", s_split[1], s_segment_timer[1], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+2, IW_time_text_offset, "W2:", s_split[2], s_segment_timer[2], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+3, IW_time_text_offset, "W3:", s_split[3], s_segment_timer[3], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+4, IW_time_text_offset, "W4:", s_split[4], s_segment_timer[4], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+5, IW_time_text_offset, "W5:", s_split[5], s_segment_timer[5], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+6, IW_time_text_offset, "W6:", s_split[6], s_segment_timer[6], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+7, IW_time_text_offset, "W7:", s_split[7], s_segment_timer[7], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+8, IW_time_text_offset, "W8:", s_split[8], s_segment_timer[8], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+9, IW_time_text_offset, "W9:", s_split[9], s_segment_timer[9], true, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+10, IW_time_text_offset, "W10:", s_split[10], s_segment_timer[10], true, false, draw::WHITE); + } } - // (to do) toggle-able warning if no timers are going to display during the run + if (pref::get(pref::BoolPref::StoryTimerWarning) == true && FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_DontShow + && SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) == SegmentTimerOptions::S_DontShow && mkb::g_storymode_mode == 21){ + // mkb::g_storymode_mode 21 is the name entry screen, not sure if it has a name in ghidra + draw::debug_text(460, 425, draw::RED, "Timer Not On!"); + } // debugging /* - timerdisp::draw_timer(static_cast(s_run_timer), "dbg1:", 0, draw::WHITE, true); - timerdisp::draw_timer(static_cast(60*s_is_run_complete), "dbg2:", 1, draw::WHITE, true); + timerdisp::draw_timer(static_cast(s_dummy), "dbg1:", 0, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*mkb::g_storymode_mode), "dbg2:", 1, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*s_completed_stages), "dbg3:", 2, draw::WHITE, true); timerdisp::draw_timer(static_cast(s_segment_start_time[10]), "dbg4:", 3, draw::WHITE, true); timerdisp::draw_timer(static_cast(s_segment_timer[10]), "dbg5:", 4, draw::WHITE, true); + */ + + + /* + timerdisp::draw_timer_general(fullgame_timer_location_x, 3, fullgame_timer_text_offset, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); + timerdisp::draw_timer_general(segment_timer_location_x, 1, segment_timer_text_offset, "Seg:", s_loadless_story_timer, 0, false, false, draw::WHITE); + timerdisp::draw_timer_general(IW_time_location_x, 2, IW_time_text_offset, "W1:", s_loadless_story_timer, 0, false, false, draw::WHITE); + + timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); - timerdisp::draw_timer_general(fullgame_timer_location_x, 8, fullgame_timer_text_offset, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); - timerdisp::draw_timer_general(segment_timer_location_x, 40, segment_timer_text_offset, "Seg:", s_loadless_story_timer, 0, false, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, 56, IW_time_text_offset, "IW:", s_loadless_story_timer, 0, false, false, draw::WHITE); */ // draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) (reference) // draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color) (reference) diff --git a/src/utils/timerdisp.cpp b/src/utils/timerdisp.cpp index 5e875675..2242dbe4 100644 --- a/src/utils/timerdisp.cpp +++ b/src/utils/timerdisp.cpp @@ -252,7 +252,7 @@ void draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefi centiseconds_1); } else if (minutes_1 > 0 && !show_seconds_only) { draw::debug_text(A, b, color, prefix); - draw::debug_text(A, b, color, "%s%02d:%02d.%02d", sign, minutes_1, seconds_1, + draw::debug_text(a, b, color, "%s%02d:%02d.%02d", sign, minutes_1, seconds_1, centiseconds_1); } else { u32 total_seconds_1 = From d7ceef524d137cf70cfdc31110382fe774954a38 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 7 Nov 2023 06:01:50 -0600 Subject: [PATCH 08/45] some code cleanup --- src/mods/deathcounter.cpp | 2 +- src/mods/storytimer.cpp | 401 ++++++++++++-------------------------- 2 files changed, 123 insertions(+), 280 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 028cbd0d..0d77c770 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -50,7 +50,7 @@ void disp() { return; } draw::debug_text(18, 56, draw::WHITE, "Deaths: "); - draw::debug_text(100, 56, draw::WHITE, "%d", s_death_count); + draw::debug_text(98, 56, draw::WHITE, "%d", s_death_count); // to do so I don't forget: get pref for the storytimers so that the the text doesn't overlap diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 0f310b4e..d99f3a07 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -26,16 +26,13 @@ namespace storytimer { S_EndOfRun = 3, }; -static u32 s_loadless_iw_time; static u32 s_spin_in_timer; static u32 s_gameplay_timer; static u32 s_postgoal_timer; -static u32 s_postgoal_replay_timer; static u32 s_exit_game_timer; static u32 s_fallout_timer; static u32 s_stage_select_timer; static u32 s_loadless_story_timer; -static bool s_run_timer; static bool s_is_on_spin_in; static bool s_is_on_stage_select_screen; static bool s_is_on_gameplay; @@ -49,38 +46,21 @@ static u32 s_prev_completed_stage_count; static s32 s_completed_stages; static u32 s_dummy; static u32 s_dummy_2; -static u32 s_dummy_3; static u32 s_split[11]; // s_split[k] is the loadless time on tape break of the 10th stage of world k -static u32 s_segment_time[11]; // s_segment_time[k] is the loadless time spent on world k, starting from stage select spin in to tape break on the 10th stage -static u32 s_segment_start_time[11]; // the loadless time at the start of world k, used to calculate s_segment_time[k] +static u32 s_segment_start_time[11]; // the loadless time at the start of world k, used to calculate s_segment_timer[k] static bool s_display_story_timer; static bool s_display_segment_timer; -static bool s_display_split; -static bool s_display_world_time; -static bool s_display_segment; static bool s_is_between_worlds; -static bool s_passed_cutscene; static bool s_is_run_complete; static u32 s_segment_timer[11]; static bool s_is_on_world[11]; static bool s_can_change_segment_start_time[11]; static u32 s_fullgame_timer_location_y; static u32 s_segment_timer_location_y; -static u32 s_spin_in_init_timer; -static bool s_stage_selected_state; -static bool s_can_increment_spin_in_init_timer; -static bool s_has_incremented_spin_in_init_timer; -static u32 s_previous_spin_in_init_timer; -static u32 s_game_scenario_return_timer; +static u32 s_spin_in_timer_correction; +static u32 s_game_scenario_return_timer_correction; static u32 s_correction_timer; -static u32 s_corrected_stage_select_timer; -static bool s_is_on_world_first_intro_sequence[11]; -static bool s_has_entered_world[11]; -static bool s_has_corrected_stage_select_timer[11]; -static bool s_is_on_first_frame_of_world[11]; -static bool s_has_passed_first_frame_of_world[11]; -static bool s_can_detect_first_frame_of_world[11]; -static bool s_has_done_start_world_correction[11]; +static u32 s_world_start_timer_correction; static constexpr s32 fullgame_timer_location_x = 18+24; static constexpr s32 fullgame_timer_text_offset = 56; static constexpr s32 segment_timer_location_x = 30+24; @@ -90,30 +70,10 @@ static constexpr s32 IW_time_text_offset = 32; static constexpr s32 Y=24; void tick() { - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ - s_run_timer = true; - } - /* - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN){ - // can increment counter after going through the goal - s_can_increment_stage_counter = true; - } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED || mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT){ - // but if you go back to the stage select screen without entering the goal or from an exit game, don't increment the counter - s_can_increment_stage_counter = false; - } - - if (s_can_increment_stage_counter == true && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN){ - s_completed_stages += 1; - } - */ - - // there is likely a simpler way to increment the stage counter in a way that works when you retry after breaking the tape and also does not break if you pause during - // game goal init or game goal main - - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { - s_prev_completed_stage_count = s_completed_stages; - } + // for later use, it's useful to record how many stages we've completed + // there is likely a simpler way to increment the stage counter in a way that works when you retry after breaking the tape and also does not break if you pause during + // game goal init or game goal main if (mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { // not allowed to increment the stage counter on goal init because of first framing @@ -141,60 +101,8 @@ void tick() { s_lower_stage_counter = false; } - for (s32 k=1; k<11; k++) { - /* - if ( s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_has_done_start_world_correction[k] == false && k != 1) { - s_corrected_stage_select_timer += 1; - s_has_done_start_world_correction[k] == true; - } - */ - if (s_is_on_world[k] == true) { - s_corrected_stage_select_timer = 2*k; - } - } - /* - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { - s_completed_stages +=1; - } - */ - - /* - // trying to detect the missing frame during spin - if (mkb::g_storymode_mode == 5) { - s_can_increment_spin_in_init_timer = false; - } - - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { - s_stage_selected_state = true; - s_previous_spin_in_init_timer = s_spin_in_init_timer; - } else { - false; - } - - if (s_stage_selected_state == false ) { - s_can_increment_spin_in_init_timer = true; - } - - if (s_can_increment_spin_in_init_timer == true) { - s_spin_in_init_timer +=1; - } - - if ( (s_spin_in_init_timer - s_previous_spin_in_init_timer) >0 ) { - s_can_increment_spin_in_init_timer = false; - } - */ - - // no idea why the spin_in_init_timer only properly incremenents when it's not in the if (s_run_timer == true){ statement below (I checked and s_run_timer always remains true during spin in) - // this is very jank I hate it so much - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - s_spin_in_init_timer += 1; - } - - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - s_game_scenario_return_timer += 1; - } - - s_correction_timer = s_spin_in_init_timer + s_game_scenario_return_timer+s_corrected_stage_select_timer; + // for later, it's useful to record what submodes correspond to spin in, gameplay, etc. + // splitting up the timer this way also makes it easier in the future if I decide to implement features such as menuing timeloss // submodes during spin in if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_MAIN) { @@ -203,7 +111,7 @@ void tick() { s_is_on_spin_in = false; } - // states entered during the story select screen + // story mode states entered during the story select screen if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || mkb::g_storymode_stageselect_state == 3 || mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE || mkb::g_storymode_stageselect_state == 5 || mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { // 3, 5 unlabelled inits @@ -243,53 +151,56 @@ void tick() { s_is_on_fallout_screen = false; } + if ( (mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { + s_in_story = true; + } else{ + s_in_story = false; + } + + // before starting the run, there are several values we zero on the file select screen (this serves to reset the timer) + // to do: in the future, have the timer not reset unless the file's data is reset (either manually or by using the IW move up/down feature) + if (mkb::g_storymode_mode == 5){ // zero the timer on the file select screen and set the number of completed stages to 0 - s_spin_in_init_timer = 0; + s_spin_in_timer_correction = 0; s_spin_in_timer = 0 ; s_gameplay_timer = 0; s_postgoal_timer = 0; - // s_postgoal_replay_timer = 0; s_stage_select_timer = 0; - s_game_scenario_return_timer = 0; + s_world_start_timer_correction = 0; + s_game_scenario_return_timer_correction = 0; s_exit_game_timer = 0; s_fallout_timer = 0; - s_run_timer = false; s_lower_stage_counter = false; s_loadless_story_timer = 0; s_completed_stages = 0; s_prev_completed_stage_count = 0; - s_corrected_stage_select_timer = 0; for (s32 k=1; k<11; k++) { - s_has_done_start_world_correction[k] = false; + // on the file select screen, set these to false just in case you reset while on world k but did not complete 10k stages + s_is_on_world[k] = false; } - } else{ - // trying to figure out missing frames - // for some reason, separately including s_spin_in_init_timer doesn't cause the visual frame skip in the timer - // last 3 terms are correction terms to account for missing frames - s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer - +s_spin_in_init_timer+s_game_scenario_return_timer+s_corrected_stage_select_timer; + } - // on the file select screen, set these to false just in case you reset while on world k but did not complete 10k stages - // need to stipulate s_run_timer is false otherwise there's weird behavior on the first stage of e/ world - for (s32 k=1; k<11; k++){ - if (s_run_timer == false){ - s_is_on_world[k] = false; - } + + if (s_in_story == true) { + + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { + // need to add 1 additional frame to the timer during spin in + // putting this code before the code below for s_loadless_story_timer makes the timer tick up more naturally when transitioning from the 10 ball screen to spin in, + // more specifically, this prevents the timer from skipping ahead for a few frames, then pausing for a few frames to even itself out (I don't understand why that happens) + s_spin_in_timer_correction += 1; } - - if (s_run_timer == true){ + + // last 3 terms are correction terms to account for missing frames + s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer + +s_spin_in_timer_correction+s_game_scenario_return_timer_correction+ s_world_start_timer_correction; + + if (s_is_on_spin_in == true) { // increment the timer every frame during spin in s_spin_in_timer +=1; } - /* - no idea why putting this here makes this timer not work correctly, but it works correctly above - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - s_spin_in_init_timer += 1; - } - */ - if (mkb::sub_mode==mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_PLAY_MAIN) { + if (s_is_on_gameplay == true) { //increment the timer every frame during gameplay s_gameplay_timer +=1; } @@ -297,10 +208,6 @@ void tick() { //increment the timer every frame after breaking the tape before returning to story select s_postgoal_timer +=1; } - // if (mkb::sub_mode==mkb::SMD_GAME_GOAL_REPLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_GOAL_REPLAY_MAIN) { - //increment the timer every frame during the postgoal replay - // s_postgoal_replay_timer= s_postgoal_replay_timer+1; - //} if (s_is_on_stage_select_screen == true) { //increment the timer every frame on the story mode select screen s_stage_select_timer +=1; @@ -313,54 +220,40 @@ void tick() { // increment the timer every frame during the fallout sequence and y/n screen s_fallout_timer += 1; } - mkb::OSReport("submode: %d ", mkb::sub_mode); - // mkb::OSReport("mainmode: %d ", mkb::main_mode); - } - - if (s_completed_stages == 99 && mkb::sub_mode ==mkb::SMD_GAME_GOAL_INIT){ - // stop the timer after breaking the tape on stage 100 - // to do: make this work for story mode packs with less than 100 stages like kaizo - - // when completing a run, first correct by 2 frames since the timer will run for 2f after breaking the tape, - // then set s_run_timer to false so that if we pause on goal init, we don't subtract 2 from the timer every frame while paused - /* - if (s_run_timer == true) { - // s_loadless_story_timer = s_loadless_story_timer - 2; - s_loadless_story_timer = s_segment_start_time[10]+s_segment_timer[10]; - s_run_timer = false; - } - */ + for (s32 k=1; k<11; k++) { + if (s_is_on_world[k] == true) { + // need to add 2 frames to the timer at the start of each world + s_world_start_timer_correction = 2*k; + } } + + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + // need to add 1 frame to the timer when stage selecting to the 10 ball screen + s_game_scenario_return_timer_correction += 1; + } + } + if (s_completed_stages == 100) { s_is_run_complete = true; + // s_segment_timer[k] is already corrected for tape break (see code below), so no further corrections needed to get an accurate time s_loadless_story_timer = s_segment_start_time[10]+s_segment_timer[10]; } else { s_is_run_complete = false; } - /* - if (s_completed_stages == 100 && s_is_postgoal == true) { - s_is_run_complete = true; - } else { - s_is_run_complete = false; - } - */ - if ( (mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { - s_in_story = true; - } else{ - s_in_story = false; - } + // it is useful to know when we are between worlds (for the "between worlds" option in the menu) + if ( (s_completed_stages % 10 == 0) && s_completed_stages != 0 && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN){ + s_is_between_worlds = true; + } else if ( (s_completed_stages % 10 == 0 && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) || s_completed_stages % 10 !=0 ){ + // no longer "between worlds" if you enter the next worlds 10 ball screen, or if you break the tape on the last stage + // of the current world, but retry + s_is_between_worlds = false; + } // code for handling loadless split and segment times for (s32 k=1; k<11; k++){ - if (s_completed_stages == 10*k-1 && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { // delete later probably - // on tape break on the last stage in world k - // need to correct by 3f since goal_init doesn't happen immediately after the tape is broken - s_split[k] = s_loadless_story_timer-3; - s_display_segment = true; // testing - } - + // if you enter the first stage of the next world but then stage select, do not restart the segment timer if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { s_can_change_segment_start_time[k] = true; @@ -369,30 +262,9 @@ void tick() { } if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_can_change_segment_start_time[k] == true) { - s_segment_start_time[k] = s_loadless_story_timer+1; - } - - // display split and iw time after breaking the tape on the last stage of a world, but stop displaying when the stage select screen for the next world starts spinning in - if (s_completed_stages == 10*k && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { // delete later - s_display_segment = false; // testing - } - - // maybe can simplify but I want to avoid things breaking if you first frame (menuing on goal init or the frame before) - if (s_completed_stages == 10*k-1 && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { - s_passed_cutscene = false; - } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_passed_cutscene = true; + s_segment_start_time[k] = s_loadless_story_timer+2; } - - if ( (s_completed_stages % 10 == 0) && s_completed_stages != 0 && s_passed_cutscene == false){ - s_is_between_worlds = true; - } else if ((s_completed_stages % 10 == 0) && s_completed_stages != 0 && s_passed_cutscene == true){ - s_is_between_worlds = false; - } - - // loadless time taken to complete world k - s_segment_time[k] = s_split[k]-s_segment_start_time[k]; - + if ( ( (10*(k-1) <= s_completed_stages) && (s_completed_stages <= (10*k-2) ) ) || (s_completed_stages == (10*k-1) && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT) ){ s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k]; } else if (s_completed_stages == (10*k-1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { @@ -401,65 +273,20 @@ void tick() { s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k] -3; } - + // fullgame loadless time upon breaking the tape on the last stage of world k + s_split[k] = s_segment_start_time[k]+s_segment_timer[k]; + if ( ( (10*(k-1) +1)<= s_completed_stages) && (s_completed_stages <= (10*k-1)) ) { s_is_on_world[k] = true; } else if (s_completed_stages == 10*(k-1) && (s_is_on_stage_select_screen == true || s_is_on_spin_in == true || s_is_on_gameplay == true) ){ + // if you've completed 10*(k-1) stages, are in world k, but haven't completed the first stage yet, then you are not in world k-1 s_is_on_world[k-1] = false; s_is_on_world[k] = true; } else if (s_completed_stages == 10*k && s_is_postgoal == true && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT && mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN) { - // testing what happens when adding the scenario return part, since if you are on world k+1, have not completed a stage, and stage select back to the 10 ball screen, - // the code thinks you are on world k for 1 frame s_is_on_world[k] = true; } - - - if (mkb::g_storymode_stageselect_state == 1) { - s_dummy_2 = 1; - } else{ - s_dummy_2 = 0; - } } - if (mkb::g_storymode_mode == 21){ - s_dummy = 1; - } else { - s_dummy = 0; - /* things tested that didn't work for exit game so far - SMD_GAME_FORCE_EXIT_MAIN=93 - SMD_GAME_FORCE_OVER_MAIN=96 - SMD_GAME_OVER_POINT_MAIN=86 - - things that do work - SMD_GAME_SUGG_SAVE_MAIN, doesn't include playpoint text, only the save data question after - SMD_GAME_INTR_SEL_MAIN is the playpoint text - - fallout submode testing - test: 50, 51, 58, 59, 90, 91, 48, 49, - - SMD_GAME_READY_INIT=48, - SMD_GAME_READY_MAIN=49, - SMD_GAME_RINGOUT_INIT=58, - SMD_GAME_RINGOUT_MAIN=59 - SMD_GAME_RETRY_INIT=90, - SMD_GAME_RETRY_MAIN=91 - - conclusion: ringout = fallout submode, game retry init/main = y/n menu - - FOR LATER, TRY THESE: - SMD_GAME_SCENSCNPLAY_RETURN=94 (missing frame on world entry?) - SMD_AUTHOR_PLAY_INIT=247, - SMD_AUTHOR_PLAY_MAIN=248, - SMD_AUTHOR_PLAY_STORY_INIT=249, - - */ - } - // debugging - /* - if (pad::button_pressed(mkb::PAD_BUTTON_DOWN)) { - s_completed_stages = 91; - } - */ } void disp() { @@ -468,6 +295,7 @@ void disp() { return; } + // move the positions of the fullgame and segment timers if the death counter is on if (pref::get(pref::BoolPref::ShowDeathCounter) == true) { s_fullgame_timer_location_y = 1; } else { @@ -513,26 +341,17 @@ void disp() { switch(SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { case SegmentTimerOptions::S_AlwaysShow: - s_display_segment_timer = true; - // if the segment timer is always showing, - // use the format iw time (split time) after breaking the tape on the last stage of a world - // to do: get the spacing right for showing the on tape break split time; currently I have show second argument set to false between worlds for (s32 k=1; k<11; k++){ - if (s_display_segment_timer == true && s_is_on_world[k] == true && s_is_between_worlds == false && s_is_run_complete == false) { + if (s_is_on_world[k] == true && s_is_run_complete == false) { timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); } - else if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], s_split[k], false, false, draw::WHITE); - } + } break; case SegmentTimerOptions::S_BetweenWorlds: - s_display_segment_timer = true; - // otherwise use the format split time (iw time) - // to do: switch around arguments if I fix the spacing for (s32 k=1; k<11; k++){ - if (s_display_segment_timer == true && s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], s_split[k], false, false, draw::WHITE); + if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { + timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); } } break; @@ -543,13 +362,6 @@ void disp() { // if the segment timer is enabled in any capacity, show all 10 split times + iw times after the tape is broken on the last stage if (SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != SegmentTimerOptions::S_DontShow) { - /* - for (s32 k=1; k<11; k++){ - if (s_is_run_complete == true){ - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+k, IW_time_text_offset, "Wk:", s_split[k], s_segment_timer[k], true, false, draw::WHITE); - } - } - */ if (s_is_run_complete == true) { // I'm so sorry :( // I don't know how to get the text to show "Wk" where k ranges in a for loop @@ -566,35 +378,66 @@ void disp() { } } + // show warning on the name entry screen if no timers are on (if the toggle for the warning is turned on) if (pref::get(pref::BoolPref::StoryTimerWarning) == true && FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_DontShow && SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) == SegmentTimerOptions::S_DontShow && mkb::g_storymode_mode == 21){ // mkb::g_storymode_mode 21 is the name entry screen, not sure if it has a name in ghidra draw::debug_text(460, 425, draw::RED, "Timer Not On!"); } - + // debugging + + if (s_is_between_worlds == true){ + s_dummy = 1; + } else { + s_dummy = 0; + /* things tested that didn't work for exit game so far + SMD_GAME_FORCE_EXIT_MAIN=93 + SMD_GAME_FORCE_OVER_MAIN=96 + SMD_GAME_OVER_POINT_MAIN=86 + + things that do work + SMD_GAME_SUGG_SAVE_MAIN, doesn't include playpoint text, only the save data question after + SMD_GAME_INTR_SEL_MAIN is the playpoint text + + fallout submode testing + test: 50, 51, 58, 59, 90, 91, 48, 49, + + SMD_GAME_READY_INIT=48, + SMD_GAME_READY_MAIN=49, + SMD_GAME_RINGOUT_INIT=58, + SMD_GAME_RINGOUT_MAIN=59 + SMD_GAME_RETRY_INIT=90, + SMD_GAME_RETRY_MAIN=91 + + conclusion: ringout = fallout submode, game retry init/main = y/n menu + + FOR LATER, TRY THESE: + SMD_GAME_SCENSCNPLAY_RETURN=94 (missing frame on world entry?) + SMD_AUTHOR_PLAY_INIT=247, + SMD_AUTHOR_PLAY_MAIN=248, + SMD_AUTHOR_PLAY_STORY_INIT=249, + + */ + } + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + s_dummy_2 = 1; + } else{ + s_dummy_2 = 0; + } + /* - timerdisp::draw_timer(static_cast(s_dummy), "dbg1:", 0, draw::WHITE, true); - timerdisp::draw_timer(static_cast(60*mkb::g_storymode_mode), "dbg2:", 1, draw::WHITE, true); - - timerdisp::draw_timer(static_cast(60*s_completed_stages), "dbg3:", 2, draw::WHITE, true); - timerdisp::draw_timer(static_cast(s_segment_start_time[10]), "dbg4:", 3, draw::WHITE, true); - timerdisp::draw_timer(static_cast(s_segment_timer[10]), "dbg5:", 4, draw::WHITE, true); + if (pad::button_pressed(mkb::PAD_BUTTON_DOWN)) { + s_completed_stages = 91; + } */ - /* - timerdisp::draw_timer_general(fullgame_timer_location_x, 3, fullgame_timer_text_offset, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); - timerdisp::draw_timer_general(segment_timer_location_x, 1, segment_timer_text_offset, "Seg:", s_loadless_story_timer, 0, false, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, 2, IW_time_text_offset, "W1:", s_loadless_story_timer, 0, false, false, draw::WHITE); - - timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); - + timerdisp::draw_timer(static_cast(60*s_dummy), "dbg1:", 0, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*s_dummy_2), "dbg2:", 1, draw::WHITE, true); + timerdisp::draw_timer(static_cast(60*mkb::g_storymode_stageselect_state), "dbg3:", 2, draw::WHITE, true); */ -// draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) (reference) -// draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color) (reference) -// timerdisp text offset for 5 characters (includes :) is 54; for 4 characters, try an additional 54 for the x pos, -// if (IlBattleLength(pref::get(pref::U8Pref::IlBattleLength)) == IlBattleLength::Endless); (reference) + } } // namespace storytimer From 94d1fe83572362e25f50bca4d15d1d09f29436db Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 7 Nov 2023 12:01:21 -0600 Subject: [PATCH 09/45] unified timer code, fixed spacing on old timers --- src/mods/cmseg.cpp | 2 +- src/mods/deathcounter.cpp | 2 +- src/mods/iw.cpp | 3 +- src/mods/storytimer.cpp | 36 ++++---- src/mods/timer.cpp | 4 +- src/utils/timerdisp.cpp | 173 +------------------------------------- src/utils/timerdisp.h | 4 +- 7 files changed, 26 insertions(+), 198 deletions(-) diff --git a/src/mods/cmseg.cpp b/src/mods/cmseg.cpp index de33de67..61f5e5d5 100644 --- a/src/mods/cmseg.cpp +++ b/src/mods/cmseg.cpp @@ -365,7 +365,7 @@ void disp() { color = draw::GOLD; else color = draw::WHITE; - timerdisp::draw_timer(static_cast(s_seg_time), "SEG:", 0, color, false); + timerdisp::draw_timer(380, 0, 44, "SEG:", static_cast(s_seg_time), 0, false, false, draw::WHITE); } } diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 0d77c770..b616db9f 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -16,7 +16,7 @@ static bool s_in_story; void tick() { - if ( (mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { + if ( mkb::main_game_mode == mkb::STORY_MODE || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { s_in_story = true; } else{ s_in_story = false; diff --git a/src/mods/iw.cpp b/src/mods/iw.cpp index 6f6c8f1a..f2e4339e 100644 --- a/src/mods/iw.cpp +++ b/src/mods/iw.cpp @@ -123,7 +123,6 @@ void disp() { mkb::main_game_mode != mkb::STORY_MODE || !main::currently_playing_iw || freecam::should_hide_hud()) return; - timerdisp::draw_timer(static_cast(s_iw_time), "IW:", 0, draw::WHITE, false); + timerdisp::draw_timer(392, 0, 32, "IW:", static_cast(s_iw_time), 0, false, false, draw::WHITE); } - } // namespace iw diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index d99f3a07..0cbd5556 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -297,19 +297,19 @@ void disp() { // move the positions of the fullgame and segment timers if the death counter is on if (pref::get(pref::BoolPref::ShowDeathCounter) == true) { - s_fullgame_timer_location_y = 1; + s_fullgame_timer_location_y = 3; } else { - s_fullgame_timer_location_y = 0; + s_fullgame_timer_location_y = 2; } // if the fullgame timer and death counter is off but the segment timer is on, move the segment timer to the top line; if either the fullgame timer or death counter are on but not both are on, // move it to the 2nd line, if all 3 are enabled, put it on the 3rd line if(s_display_story_timer == false && pref::get(pref::BoolPref::ShowDeathCounter) == false ){ - s_segment_timer_location_y = 0; + s_segment_timer_location_y = 2; } else if (s_display_story_timer == false || pref::get(pref::BoolPref::ShowDeathCounter) == false ){ - s_segment_timer_location_y = 1; + s_segment_timer_location_y = 3; } else { - s_segment_timer_location_y = 2; + s_segment_timer_location_y = 4; } switch(FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions))) { @@ -336,14 +336,14 @@ void disp() { } if (s_display_story_timer == true){ - timerdisp::draw_timer_general(fullgame_timer_location_x, s_fullgame_timer_location_y, fullgame_timer_text_offset, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); + timerdisp::draw_timer(fullgame_timer_location_x, s_fullgame_timer_location_y, fullgame_timer_text_offset, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); } switch(SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { case SegmentTimerOptions::S_AlwaysShow: for (s32 k=1; k<11; k++){ if (s_is_on_world[k] == true && s_is_run_complete == false) { - timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); + timerdisp::draw_timer(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); } } @@ -351,7 +351,7 @@ void disp() { case SegmentTimerOptions::S_BetweenWorlds: for (s32 k=1; k<11; k++){ if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_timer_general(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); + timerdisp::draw_timer(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); } } break; @@ -365,16 +365,16 @@ void disp() { if (s_is_run_complete == true) { // I'm so sorry :( // I don't know how to get the text to show "Wk" where k ranges in a for loop - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+1, IW_time_text_offset, "W1:", s_split[1], s_segment_timer[1], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+2, IW_time_text_offset, "W2:", s_split[2], s_segment_timer[2], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+3, IW_time_text_offset, "W3:", s_split[3], s_segment_timer[3], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+4, IW_time_text_offset, "W4:", s_split[4], s_segment_timer[4], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+5, IW_time_text_offset, "W5:", s_split[5], s_segment_timer[5], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+6, IW_time_text_offset, "W6:", s_split[6], s_segment_timer[6], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+7, IW_time_text_offset, "W7:", s_split[7], s_segment_timer[7], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+8, IW_time_text_offset, "W8:", s_split[8], s_segment_timer[8], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+9, IW_time_text_offset, "W9:", s_split[9], s_segment_timer[9], true, false, draw::WHITE); - timerdisp::draw_timer_general(IW_time_location_x, s_segment_timer_location_y+10, IW_time_text_offset, "W10:", s_split[10], s_segment_timer[10], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+1, IW_time_text_offset, "W1:", s_split[1], s_segment_timer[1], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+2, IW_time_text_offset, "W2:", s_split[2], s_segment_timer[2], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+3, IW_time_text_offset, "W3:", s_split[3], s_segment_timer[3], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+4, IW_time_text_offset, "W4:", s_split[4], s_segment_timer[4], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+5, IW_time_text_offset, "W5:", s_split[5], s_segment_timer[5], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+6, IW_time_text_offset, "W6:", s_split[6], s_segment_timer[6], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+7, IW_time_text_offset, "W7:", s_split[7], s_segment_timer[7], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+8, IW_time_text_offset, "W8:", s_split[8], s_segment_timer[8], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+9, IW_time_text_offset, "W9:", s_split[9], s_segment_timer[9], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+10, IW_time_text_offset, "W10:", s_split[10], s_segment_timer[10], true, false, draw::WHITE); } } diff --git a/src/mods/timer.cpp b/src/mods/timer.cpp index e86e428a..54dc49d6 100644 --- a/src/mods/timer.cpp +++ b/src/mods/timer.cpp @@ -53,8 +53,8 @@ void disp() { } if (pref::get(pref::BoolPref::RtaPauseTimer) && !freecam::should_hide_hud()) { - timerdisp::draw_timer(s_rta_timer, "RTA:", 1, draw::WHITE, true); - timerdisp::draw_timer(s_pause_timer, "PAU:", 2, draw::WHITE, true); + timerdisp::draw_timer(380, 1, 44, "RTA:", s_rta_timer, 1, false, true, draw::WHITE); + timerdisp::draw_timer(380, 2, 44, "PAU:", s_pause_timer, 2, false, true, draw::WHITE); } } diff --git a/src/utils/timerdisp.cpp b/src/utils/timerdisp.cpp index 2242dbe4..4d3bf52e 100644 --- a/src/utils/timerdisp.cpp +++ b/src/utils/timerdisp.cpp @@ -12,176 +12,7 @@ static constexpr s32 X = 380; static constexpr s32 X_2 = 18; static constexpr s32 Y = 24; -void draw_timer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds) { - bool positive = frames >= 0; - if (!positive) frames = -frames; - const char* sign = positive ? "" : "-"; - - u32 hours = frames / HOUR_FRAMES; - u32 minutes = frames % HOUR_FRAMES / MINUTE_FRAMES; - u32 seconds = frames % MINUTE_FRAMES / SECOND_FRAMES; - u32 centiseconds = (frames % SECOND_FRAMES) * 100 / 60; - - s32 y = Y + row * 16; - - if (hours > 0 && !show_seconds) { - draw::debug_text(X, y, color, prefix); - draw::debug_text(X + 54, y, color, "%s%d:%02d:%02d.%02d", sign, hours, minutes, seconds, - centiseconds); - } else if (minutes > 0 && !show_seconds) { - draw::debug_text(X, y, color, prefix); - draw::debug_text(X + 54, y, color, "%s%02d:%02d.%02d", sign, minutes, seconds, - centiseconds); - } else { - u32 total_seconds = - seconds + (minutes * MINUTE_FRAMES + hours * HOUR_FRAMES) / SECOND_FRAMES; - draw::debug_text(X, y, color, prefix); - draw::debug_text(X + 54, y, color, "%s%02d.%02d", sign, total_seconds, centiseconds); - } -} - -/* -void draw_storytimer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds) { - bool positive = frames >= 0; - if (!positive) frames = -frames; - const char* sign = positive ? "" : "-"; - - u32 hours = frames / HOUR_FRAMES; - u32 minutes = frames % HOUR_FRAMES / MINUTE_FRAMES; - u32 seconds = frames % MINUTE_FRAMES / SECOND_FRAMES; - u32 centiseconds = (frames % SECOND_FRAMES) * 100 / 60; - - s32 y = Y + (row+2) * 16; - - if (hours > 0 && !show_seconds) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d", sign, hours, minutes, seconds, - centiseconds); - } else if (minutes > 0 && !show_seconds) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d", sign, minutes, seconds, - centiseconds); - } else { - u32 total_seconds = - seconds + (minutes * MINUTE_FRAMES + hours * HOUR_FRAMES) / SECOND_FRAMES; - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d.%02d", sign, total_seconds, centiseconds); - } -} */ - -void draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds, bool second_argument, s32 frames_2) { - bool positive = frames_1 >= 0; - if (!positive) frames_1 = -frames_1; - const char* sign = positive ? "" : "-"; - - u32 hours_1 = frames_1 / HOUR_FRAMES; - u32 minutes_1 = frames_1 % HOUR_FRAMES / MINUTE_FRAMES; - u32 seconds_1 = frames_1 % MINUTE_FRAMES / SECOND_FRAMES; - u32 centiseconds_1 = (frames_1 % SECOND_FRAMES) * 100 / 60; - - u32 hours_2 = frames_2 / HOUR_FRAMES; - u32 minutes_2 = frames_2 % HOUR_FRAMES / MINUTE_FRAMES; - u32 seconds_2 = frames_2 % MINUTE_FRAMES / SECOND_FRAMES; - u32 centiseconds_2 = (frames_2 % SECOND_FRAMES) * 100 / 60; - - s32 y = Y + (row+2) * 16; -/* - if (second_argument == false) { - if (hours_1 > 0 && !show_seconds) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d", sign, hours_1, minutes_1, seconds_1, - centiseconds_1); - } else if (minutes_1 > 0 && !show_seconds) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d", sign, minutes_1, seconds_1, - centiseconds_1); - } else { - u32 total_seconds_1 = - seconds_1 + (minutes_1 * MINUTE_FRAMES + hours_1 * HOUR_FRAMES) / SECOND_FRAMES; - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d.%02d", sign, total_seconds_1, centiseconds_1); - } - } else { - if (hours_1 > 0 && hours_2 > 0 && !show_seconds) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, - centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); - } else if (minutes_1 > 0 && minutes_2 > 0 && !show_seconds) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, minutes_1, seconds_1, - centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); - } else { - u32 total_seconds_2 = - seconds_2 + (minutes_2 * MINUTE_FRAMES + hours_2 * HOUR_FRAMES) / SECOND_FRAMES; - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d.%02d", sign, total_seconds_2, centiseconds_2); - } - } -*/ - if (second_argument == true){ - if (hours_1 > 0) { - if (hours_2 > 0 ) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, - centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); - } else if (minutes_2 > 0) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, - centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); - } else { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d (%s%02d.%02d)", sign, hours_1, minutes_1, seconds_1, - centiseconds_1, sign, seconds_2, centiseconds_2); - } - } else if (minutes_1 > 0) { - if (hours_2 > 0) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, minutes_1, seconds_1, - centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); - } else if (minutes_2 > 0) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d (%s%02d:%02d.%02d)", sign, minutes_1, seconds_1, - centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); - } else { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d (%s%02d.%02d)", sign, minutes_1, seconds_1, - centiseconds_1, sign, seconds_2, centiseconds_2); - } - - } else { - if (hours_2 > 0) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d.%02d (%s%d:%02d:%02d.%02d)", sign, seconds_1, - centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); - } else if (minutes_2 > 0) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d.%02d (%s%d:%02d.%02d)", sign, seconds_1, - centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); - } else { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d.%02d (%s%d.%02d)", sign, seconds_1, - centiseconds_1, sign, seconds_2, centiseconds_2); - } - } - } else { - if (hours_1 > 0 && !show_seconds) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%d:%02d:%02d.%02d", sign, hours_1, minutes_1, seconds_1, - centiseconds_1); - } else if (minutes_1 > 0 && !show_seconds) { - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d:%02d.%02d", sign, minutes_1, seconds_1, - centiseconds_1); - } else { - u32 total_seconds_1 = - seconds_1 + (minutes_1 * MINUTE_FRAMES + hours_1 * HOUR_FRAMES) / SECOND_FRAMES; - draw::debug_text(X_2, y, color, prefix); - draw::debug_text(X_2 + 54, y, color, "%s%02d.%02d", sign, total_seconds_1, centiseconds_1); - } - } -} - -void draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color){ +void draw_timer(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color){ bool positive = frames_1 >= 0; if (!positive) frames_1 = -frames_1; const char* sign = positive ? "" : "-"; @@ -198,7 +29,7 @@ void draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefi s32 A = pos_x; s32 a = A + text_offset; - s32 b = Y + (pos_y+2)*16; + s32 b = Y + (pos_y)*16; if (show_second_argument == true){ if (hours_1 > 0) { diff --git a/src/utils/timerdisp.h b/src/utils/timerdisp.h index b072c95b..645b1b99 100644 --- a/src/utils/timerdisp.h +++ b/src/utils/timerdisp.h @@ -4,8 +4,6 @@ namespace timerdisp { -void draw_timer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, bool show_minutes); -void draw_timer_general(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color); -void draw_storytimer(s32 frames_1, const char* prefix, u32 row, mkb::GXColor color, bool show_seconds_only, bool second_argument, s32 frames_2); +void draw_timer(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color); } From 261494c039b0eb8d1d0d49adc8e2e622cb0d5dbb Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 7 Nov 2023 12:17:37 -0600 Subject: [PATCH 10/45] make the loadless timer count during timeover --- src/mods/storytimer.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 0cbd5556..72ab4a71 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -31,6 +31,7 @@ static u32 s_gameplay_timer; static u32 s_postgoal_timer; static u32 s_exit_game_timer; static u32 s_fallout_timer; +static u32 s_timeover_timer; static u32 s_stage_select_timer; static u32 s_loadless_story_timer; static bool s_is_on_spin_in; @@ -38,6 +39,7 @@ static bool s_is_on_stage_select_screen; static bool s_is_on_gameplay; static bool s_is_on_exit_game_screen; static bool s_is_on_fallout_screen; +static bool s_is_timeover; static bool s_is_postgoal; static bool s_can_increment_stage_counter; static bool s_lower_stage_counter; @@ -151,6 +153,13 @@ void tick() { s_is_on_fallout_screen = false; } + // submodes during timeover + if (mkb:: sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN) { + s_is_timeover = true; + } else { + s_is_timeover = false; + } + if ( (mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { s_in_story = true; } else{ @@ -171,6 +180,7 @@ void tick() { s_game_scenario_return_timer_correction = 0; s_exit_game_timer = 0; s_fallout_timer = 0; + s_timeover_timer = 0; s_lower_stage_counter = false; s_loadless_story_timer = 0; s_completed_stages = 0; @@ -192,7 +202,7 @@ void tick() { } // last 3 terms are correction terms to account for missing frames - s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer + s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer+s_timeover_timer+ +s_spin_in_timer_correction+s_game_scenario_return_timer_correction+ s_world_start_timer_correction; @@ -220,6 +230,10 @@ void tick() { // increment the timer every frame during the fallout sequence and y/n screen s_fallout_timer += 1; } + if (s_is_timeover == true) { + // increment the timer every frame during the timeover sequence + s_timeover_timer += 1; + } for (s32 k=1; k<11; k++) { if (s_is_on_world[k] == true) { From 688050fe8cc6b8f924047f033e70c569f2008977 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Thu, 9 Nov 2023 17:34:31 -0600 Subject: [PATCH 11/45] cut out parts of the timer -timer no longer increments on mkb::STAGE_SELECTED due to (load?) variance -timer no longer increments between the stage select a press and the start of the 10 ball screen spin in bc of variance between emu and console (will test more though to be sure) --- src/mods/storytimer.cpp | 101 ++++++++++++++++++++++++++-------------- src/mods/storytimer.h | 1 + src/mods/timer.cpp | 4 +- src/systems/main.cpp | 1 + 4 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 72ab4a71..139b5d48 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -1,4 +1,4 @@ -#include "iw.h" +#include "storytimer.h" #include "mkb/mkb.h" @@ -29,48 +29,59 @@ namespace storytimer { static u32 s_spin_in_timer; static u32 s_gameplay_timer; static u32 s_postgoal_timer; +static u32 s_stage_select_timer; static u32 s_exit_game_timer; static u32 s_fallout_timer; static u32 s_timeover_timer; -static u32 s_stage_select_timer; +static u32 s_spin_in_timer_correction; +static u32 s_game_scenario_return_timer_correction; +static u32 s_world_start_timer_correction; static u32 s_loadless_story_timer; +static bool s_in_story; +static bool s_is_on_world[11]; +static bool s_is_between_worlds; +static bool s_is_run_complete; static bool s_is_on_spin_in; -static bool s_is_on_stage_select_screen; static bool s_is_on_gameplay; +static bool s_is_postgoal; +static bool s_is_on_stage_select_screen; static bool s_is_on_exit_game_screen; static bool s_is_on_fallout_screen; static bool s_is_timeover; -static bool s_is_postgoal; static bool s_can_increment_stage_counter; static bool s_lower_stage_counter; -static bool s_in_story; +static bool s_cap_postgoal_timer; static u32 s_prev_completed_stage_count; static s32 s_completed_stages; -static u32 s_dummy; -static u32 s_dummy_2; +static u32 s_segment_timer[11]; // IW timer for world k static u32 s_split[11]; // s_split[k] is the loadless time on tape break of the 10th stage of world k static u32 s_segment_start_time[11]; // the loadless time at the start of world k, used to calculate s_segment_timer[k] +static bool s_can_change_segment_start_time[11]; static bool s_display_story_timer; static bool s_display_segment_timer; -static bool s_is_between_worlds; -static bool s_is_run_complete; -static u32 s_segment_timer[11]; -static bool s_is_on_world[11]; -static bool s_can_change_segment_start_time[11]; static u32 s_fullgame_timer_location_y; static u32 s_segment_timer_location_y; -static u32 s_spin_in_timer_correction; -static u32 s_game_scenario_return_timer_correction; -static u32 s_correction_timer; -static u32 s_world_start_timer_correction; static constexpr s32 fullgame_timer_location_x = 18+24; static constexpr s32 fullgame_timer_text_offset = 56; static constexpr s32 segment_timer_location_x = 30+24; static constexpr s32 segment_timer_text_offset = 44; static constexpr s32 IW_time_location_x = 42+24; static constexpr s32 IW_time_text_offset = 32; -static constexpr s32 Y=24; - +static u32 s_dummy; +static u32 s_dummy_2; +static u32 s_dummy_3; + +void init() { + static patch::Tramp s_handle_pause_menu_selection_tramp; + patch::hook_function(s_handle_pause_menu_selection_tramp, mkb::handle_pausemenu_selection, [](int param_1) { + s_handle_pause_menu_selection_tramp.dest(param_1); + if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && mkb::g_current_focused_pause_menu_entry == 4){ + // stage select is on line 4 of the pause menu (top line is line 0) + s_dummy_3 = 1; + } + }); +} + void tick() { // for later use, it's useful to record how many stages we've completed @@ -166,6 +177,15 @@ void tick() { s_in_story = false; } + if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && mkb::g_current_focused_pause_menu_entry == 4 && pad::button_pressed(mkb::PAD_BUTTON_A) == true && s_is_postgoal == true){ + // stage select is on line 4 of the pause menu (top line is line 0) + s_cap_postgoal_timer = true; + } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ + s_cap_postgoal_timer = false; + } + + + // before starting the run, there are several values we zero on the file select screen (this serves to reset the timer) // to do: in the future, have the timer not reset unless the file's data is reset (either manually or by using the IW move up/down feature) @@ -185,6 +205,8 @@ void tick() { s_loadless_story_timer = 0; s_completed_stages = 0; s_prev_completed_stage_count = 0; + s_cap_postgoal_timer = false; + s_dummy_3 = 0; for (s32 k=1; k<11; k++) { // on the file select screen, set these to false just in case you reset while on world k but did not complete 10k stages s_is_on_world[k] = false; @@ -214,12 +236,18 @@ void tick() { //increment the timer every frame during gameplay s_gameplay_timer +=1; } - if (s_is_postgoal == true) { + if (s_is_postgoal == true && s_cap_postgoal_timer == false) { //increment the timer every frame after breaking the tape before returning to story select + // but once stage select is pressed, stop incrementing the timer + // the reason to do this is because even if we ignore completely white frames, the time it takes to *get to* the first completely white frame varies between + // console and emu, so this is necessary for a loadless timer s_postgoal_timer +=1; } - if (s_is_on_stage_select_screen == true) { - //increment the timer every frame on the story mode select screen + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { + //increment the timer every frame on the story mode select screen until the a press input; we do not include the transition time after pressing a afterwards + // even ignoring completely white frames, the time spent on mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be + // highly variable (up to over 40 frames sometimes!), so for the purpose of a loadless timer, it makes sense to cut this out from the timer s_stage_select_timer +=1; } if (s_is_on_exit_game_screen == true) { @@ -379,16 +407,17 @@ void disp() { if (s_is_run_complete == true) { // I'm so sorry :( // I don't know how to get the text to show "Wk" where k ranges in a for loop - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+1, IW_time_text_offset, "W1:", s_split[1], s_segment_timer[1], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+2, IW_time_text_offset, "W2:", s_split[2], s_segment_timer[2], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+3, IW_time_text_offset, "W3:", s_split[3], s_segment_timer[3], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+4, IW_time_text_offset, "W4:", s_split[4], s_segment_timer[4], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+5, IW_time_text_offset, "W5:", s_split[5], s_segment_timer[5], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+6, IW_time_text_offset, "W6:", s_split[6], s_segment_timer[6], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+7, IW_time_text_offset, "W7:", s_split[7], s_segment_timer[7], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+8, IW_time_text_offset, "W8:", s_split[8], s_segment_timer[8], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+9, IW_time_text_offset, "W9:", s_split[9], s_segment_timer[9], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+10, IW_time_text_offset, "W10:", s_split[10], s_segment_timer[10], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y, IW_time_text_offset, "W1:", s_split[1], s_segment_timer[1], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+1, IW_time_text_offset, "W2:", s_split[2], s_segment_timer[2], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+2, IW_time_text_offset, "W3:", s_split[3], s_segment_timer[3], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+3, IW_time_text_offset, "W4:", s_split[4], s_segment_timer[4], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+4, IW_time_text_offset, "W5:", s_split[5], s_segment_timer[5], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+5, IW_time_text_offset, "W6:", s_split[6], s_segment_timer[6], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+6, IW_time_text_offset, "W7:", s_split[7], s_segment_timer[7], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+7, IW_time_text_offset, "W8:", s_split[8], s_segment_timer[8], true, false, draw::WHITE); + timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+8, IW_time_text_offset, "W9:", s_split[9], s_segment_timer[9], true, false, draw::WHITE); + // use segment timer spacing for w10 since "W10" is 3 characters long, not 2 + timerdisp::draw_timer(segment_timer_location_x, s_segment_timer_location_y+9, segment_timer_text_offset, "W10:", s_split[10], s_segment_timer[10], true, false, draw::WHITE); } } @@ -434,7 +463,7 @@ void disp() { */ } - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + if (pad::button_pressed(mkb::PAD_BUTTON_A) == true) { s_dummy_2 = 1; } else{ s_dummy_2 = 0; @@ -445,11 +474,11 @@ void disp() { s_completed_stages = 91; } */ - /* - timerdisp::draw_timer(static_cast(60*s_dummy), "dbg1:", 0, draw::WHITE, true); - timerdisp::draw_timer(static_cast(60*s_dummy_2), "dbg2:", 1, draw::WHITE, true); - timerdisp::draw_timer(static_cast(60*mkb::g_storymode_stageselect_state), "dbg3:", 2, draw::WHITE, true); + if (FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_AlwaysShow){ + timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(60*s_cap_postgoal_timer), 1, false, true, draw::WHITE); + timerdisp::draw_timer(380, 1, 44, "dbg:", static_cast(60*s_dummy_3), 1, false, true, draw::WHITE); + } */ } diff --git a/src/mods/storytimer.h b/src/mods/storytimer.h index 16df1c93..ac7f8a3f 100644 --- a/src/mods/storytimer.h +++ b/src/mods/storytimer.h @@ -2,6 +2,7 @@ namespace storytimer { +void init(); void tick(); void disp(); diff --git a/src/mods/timer.cpp b/src/mods/timer.cpp index 54dc49d6..608a9cf3 100644 --- a/src/mods/timer.cpp +++ b/src/mods/timer.cpp @@ -53,8 +53,8 @@ void disp() { } if (pref::get(pref::BoolPref::RtaPauseTimer) && !freecam::should_hide_hud()) { - timerdisp::draw_timer(380, 1, 44, "RTA:", s_rta_timer, 1, false, true, draw::WHITE); - timerdisp::draw_timer(380, 2, 44, "PAU:", s_pause_timer, 2, false, true, draw::WHITE); + timerdisp::draw_timer(380, 1, 44, "RTA:", s_rta_timer, 0, false, true, draw::WHITE); + timerdisp::draw_timer(380, 2, 44, "PAU:", s_pause_timer, 0, false, true, draw::WHITE); } } diff --git a/src/systems/main.cpp b/src/systems/main.cpp index 5822ce55..f2d758ab 100644 --- a/src/systems/main.cpp +++ b/src/systems/main.cpp @@ -82,6 +82,7 @@ void init() { Tetris::get_instance().init(); physics::init(); iw::init(); + storytimer::init(); libsavest::init(); timer::init(); inputdisp::init(); From b14c1c445486e8e8d11b2b265bba9d00bc32a07e Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Fri, 10 Nov 2023 08:41:27 -0600 Subject: [PATCH 12/45] adjusted timer + fixed death counter bug -the timer now increments for exactly 49 frames during fade out (which is the usual fade out time when stage selecting) after pressing stage select. this fade out time should not vary between sd/usb/dolphin -fixed the death counter bug where it would increment to 1 on the first stage automatically --- src/mods/deathcounter.cpp | 8 +++++--- src/mods/storytimer.cpp | 42 +++++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index b616db9f..f3c3703f 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -31,14 +31,16 @@ void tick() { s_can_die = true; } - if ( (mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT) && s_can_die == true){ - s_death_count += 1; + if (s_can_die == true && (mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT + || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || mkb::sub_mode == mkb:: SMD_GAME_SCENARIO_RETURN)){ + // you can die either by retrying after dropping in, falling out, timing over, or stage selecting after dropping in (but before breaking the tape) + s_death_count += 1; s_can_die = false; } // first framing should not increase the death counter, and retrying after breaking the tape should not increase it either // to do: however, if you retry after breaking the tape on the very first frame (so the frame before goal init), it does count as a death when it should not - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { s_can_die = false; } diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 139b5d48..591ca5c7 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -51,6 +51,8 @@ static bool s_is_timeover; static bool s_can_increment_stage_counter; static bool s_lower_stage_counter; static bool s_cap_postgoal_timer; +static bool s_start_stage_fade_out_timer; +static u32 s_stage_fade_out_timer; static u32 s_prev_completed_stage_count; static s32 s_completed_stages; static u32 s_segment_timer[11]; // IW timer for world k @@ -67,6 +69,7 @@ static constexpr s32 segment_timer_location_x = 30+24; static constexpr s32 segment_timer_text_offset = 44; static constexpr s32 IW_time_location_x = 42+24; static constexpr s32 IW_time_text_offset = 32; +static constexpr s32 stage_fade_out_time = 49; static u32 s_dummy; static u32 s_dummy_2; static u32 s_dummy_3; @@ -177,13 +180,19 @@ void tick() { s_in_story = false; } + // this code is used to halt the timer once the screen becomes completely white when stage selecting out of a level if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && mkb::g_current_focused_pause_menu_entry == 4 && pad::button_pressed(mkb::PAD_BUTTON_A) == true && s_is_postgoal == true){ // stage select is on line 4 of the pause menu (top line is line 0) - s_cap_postgoal_timer = true; + s_start_stage_fade_out_timer = true; } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ - s_cap_postgoal_timer = false; + s_start_stage_fade_out_timer = false; + s_dummy_3 = 0; } - + if (s_start_stage_fade_out_timer == true) { + s_stage_fade_out_timer += 1; + } else { + s_stage_fade_out_timer = 0; + } // before starting the run, there are several values we zero on the file select screen (this serves to reset the timer) @@ -205,7 +214,8 @@ void tick() { s_loadless_story_timer = 0; s_completed_stages = 0; s_prev_completed_stage_count = 0; - s_cap_postgoal_timer = false; + s_start_stage_fade_out_timer = false; + s_stage_fade_out_timer = 0; s_dummy_3 = 0; for (s32 k=1; k<11; k++) { // on the file select screen, set these to false just in case you reset while on world k but did not complete 10k stages @@ -236,11 +246,10 @@ void tick() { //increment the timer every frame during gameplay s_gameplay_timer +=1; } - if (s_is_postgoal == true && s_cap_postgoal_timer == false) { - //increment the timer every frame after breaking the tape before returning to story select - // but once stage select is pressed, stop incrementing the timer - // the reason to do this is because even if we ignore completely white frames, the time it takes to *get to* the first completely white frame varies between - // console and emu, so this is necessary for a loadless timer + if (s_is_postgoal == true && s_stage_fade_out_timer < stage_fade_out_time+1) { + // increment the timer every frame after game goal init happens; once you press stage select, a separate 49 frame timer is started (fade out from stage select + // to the first completely white frame takes 49 frames). once the timer hits 49 frames, stop incrementing the timer + // until the 10 ball screen starts spinning in s_postgoal_timer +=1; } if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || mkb::g_storymode_stageselect_state == 3 || @@ -269,11 +278,13 @@ void tick() { s_world_start_timer_correction = 2*k; } } - - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - // need to add 1 frame to the timer when stage selecting to the 10 ball screen - s_game_scenario_return_timer_correction += 1; + + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % 10 != 0) { + // need to add 2 frames to the timer when stage selecting to the 10 ball screen, but don't correct if on the last stage of a world + // since the next frame the timer should increment on is covered by s_world_start_timer_correction + s_game_scenario_return_timer_correction += 2; } + } if (s_completed_stages == 100) { @@ -477,9 +488,10 @@ void disp() { /* if (FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_AlwaysShow){ timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(60*s_cap_postgoal_timer), 1, false, true, draw::WHITE); - timerdisp::draw_timer(380, 1, 44, "dbg:", static_cast(60*s_dummy_3), 1, false, true, draw::WHITE); + timerdisp::draw_timer(380, 1, 44, "dbg:", static_cast(60*s_start_stage_fade_out_timer), 1, false, true, draw::WHITE); + timerdisp::draw_timer(380, 2, 44, "dbg:", static_cast(60*s_stage_fade_out_timer), 1, false, true, draw::WHITE); } - */ +*/ } From e7f7c67a62e191bdb9829a79d2565045d524d5c6 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Fri, 10 Nov 2023 21:22:34 -0600 Subject: [PATCH 13/45] some cleanup --- src/mods/deathcounter.cpp | 2 ++ src/mods/storytimer.cpp | 75 ++------------------------------------- src/mods/storytimer.h | 1 - src/systems/main.cpp | 1 - src/systems/menu_impl.cpp | 2 +- src/systems/pref.cpp | 2 +- 6 files changed, 6 insertions(+), 77 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index f3c3703f..30f6ebf6 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -1,3 +1,5 @@ +#include "mods/deathcounter.h" + #include "mkb/mkb.h" #include "mods/freecam.h" diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 591ca5c7..f7e02209 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -50,7 +50,6 @@ static bool s_is_on_fallout_screen; static bool s_is_timeover; static bool s_can_increment_stage_counter; static bool s_lower_stage_counter; -static bool s_cap_postgoal_timer; static bool s_start_stage_fade_out_timer; static u32 s_stage_fade_out_timer; static u32 s_prev_completed_stage_count; @@ -70,20 +69,6 @@ static constexpr s32 segment_timer_text_offset = 44; static constexpr s32 IW_time_location_x = 42+24; static constexpr s32 IW_time_text_offset = 32; static constexpr s32 stage_fade_out_time = 49; -static u32 s_dummy; -static u32 s_dummy_2; -static u32 s_dummy_3; - -void init() { - static patch::Tramp s_handle_pause_menu_selection_tramp; - patch::hook_function(s_handle_pause_menu_selection_tramp, mkb::handle_pausemenu_selection, [](int param_1) { - s_handle_pause_menu_selection_tramp.dest(param_1); - if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && mkb::g_current_focused_pause_menu_entry == 4){ - // stage select is on line 4 of the pause menu (top line is line 0) - s_dummy_3 = 1; - } - }); -} void tick() { @@ -186,7 +171,6 @@ void tick() { s_start_stage_fade_out_timer = true; } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ s_start_stage_fade_out_timer = false; - s_dummy_3 = 0; } if (s_start_stage_fade_out_timer == true) { s_stage_fade_out_timer += 1; @@ -216,7 +200,6 @@ void tick() { s_prev_completed_stage_count = 0; s_start_stage_fade_out_timer = false; s_stage_fade_out_timer = 0; - s_dummy_3 = 0; for (s32 k=1; k<11; k++) { // on the file select screen, set these to false just in case you reset while on world k but did not complete 10k stages s_is_on_world[k] = false; @@ -246,7 +229,7 @@ void tick() { //increment the timer every frame during gameplay s_gameplay_timer +=1; } - if (s_is_postgoal == true && s_stage_fade_out_timer < stage_fade_out_time+1) { + if (s_is_postgoal == true && s_stage_fade_out_timer <= stage_fade_out_time) { // increment the timer every frame after game goal init happens; once you press stage select, a separate 49 frame timer is started (fade out from stage select // to the first completely white frame takes 49 frames). once the timer hits 49 frames, stop incrementing the timer // until the 10 ball screen starts spinning in @@ -315,7 +298,7 @@ void tick() { } if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_can_change_segment_start_time[k] == true) { - s_segment_start_time[k] = s_loadless_story_timer+2; + s_segment_start_time[k] = s_loadless_story_timer; } if ( ( (10*(k-1) <= s_completed_stages) && (s_completed_stages <= (10*k-2) ) ) || (s_completed_stages == (10*k-1) && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT) ){ @@ -438,61 +421,7 @@ void disp() { // mkb::g_storymode_mode 21 is the name entry screen, not sure if it has a name in ghidra draw::debug_text(460, 425, draw::RED, "Timer Not On!"); } - - // debugging - if (s_is_between_worlds == true){ - s_dummy = 1; - } else { - s_dummy = 0; - /* things tested that didn't work for exit game so far - SMD_GAME_FORCE_EXIT_MAIN=93 - SMD_GAME_FORCE_OVER_MAIN=96 - SMD_GAME_OVER_POINT_MAIN=86 - - things that do work - SMD_GAME_SUGG_SAVE_MAIN, doesn't include playpoint text, only the save data question after - SMD_GAME_INTR_SEL_MAIN is the playpoint text - - fallout submode testing - test: 50, 51, 58, 59, 90, 91, 48, 49, - - SMD_GAME_READY_INIT=48, - SMD_GAME_READY_MAIN=49, - SMD_GAME_RINGOUT_INIT=58, - SMD_GAME_RINGOUT_MAIN=59 - SMD_GAME_RETRY_INIT=90, - SMD_GAME_RETRY_MAIN=91 - - conclusion: ringout = fallout submode, game retry init/main = y/n menu - - FOR LATER, TRY THESE: - SMD_GAME_SCENSCNPLAY_RETURN=94 (missing frame on world entry?) - SMD_AUTHOR_PLAY_INIT=247, - SMD_AUTHOR_PLAY_MAIN=248, - SMD_AUTHOR_PLAY_STORY_INIT=249, - - */ - } - if (pad::button_pressed(mkb::PAD_BUTTON_A) == true) { - s_dummy_2 = 1; - } else{ - s_dummy_2 = 0; - } - - /* - if (pad::button_pressed(mkb::PAD_BUTTON_DOWN)) { - s_completed_stages = 91; - } - */ - /* - if (FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_AlwaysShow){ - timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(60*s_cap_postgoal_timer), 1, false, true, draw::WHITE); - timerdisp::draw_timer(380, 1, 44, "dbg:", static_cast(60*s_start_stage_fade_out_timer), 1, false, true, draw::WHITE); - timerdisp::draw_timer(380, 2, 44, "dbg:", static_cast(60*s_stage_fade_out_timer), 1, false, true, draw::WHITE); - } -*/ - } } // namespace storytimer diff --git a/src/mods/storytimer.h b/src/mods/storytimer.h index ac7f8a3f..16df1c93 100644 --- a/src/mods/storytimer.h +++ b/src/mods/storytimer.h @@ -2,7 +2,6 @@ namespace storytimer { -void init(); void tick(); void disp(); diff --git a/src/systems/main.cpp b/src/systems/main.cpp index f2d758ab..5822ce55 100644 --- a/src/systems/main.cpp +++ b/src/systems/main.cpp @@ -82,7 +82,6 @@ void init() { Tetris::get_instance().init(); physics::init(); iw::init(); - storytimer::init(); libsavest::init(); timer::init(); inputdisp::init(); diff --git a/src/systems/menu_impl.cpp b/src/systems/menu_impl.cpp index 94a74cc2..f6f97702 100644 --- a/src/systems/menu_impl.cpp +++ b/src/systems/menu_impl.cpp @@ -414,7 +414,7 @@ static void draw_help(const Widget& widget) { "Reset"); break; } - case WidgetType::InputSelect: { + case WidgetType::InputSelect: { draw::debug_text(START, Y_HEIGHT, draw::LIGHT_GREEN, "A"); draw::debug_text(BUTTON_START + 1 * BLOCK_WIDTH, Y_HEIGHT, draw::WHITE, ":"); draw::debug_text(BUTTON_START + 1 * BLOCK_WIDTH + HALF_SPACE, Y_HEIGHT, draw::WHITE, diff --git a/src/systems/pref.cpp b/src/systems/pref.cpp index 146e8c33..41901417 100644 --- a/src/systems/pref.cpp +++ b/src/systems/pref.cpp @@ -358,7 +358,7 @@ static DefaultU8Pref s_default_u8_prefs[] = { // struct PrefState { - u8 bool_prefs[8]; // up to 64 bool prefs + u8 bool_prefs[9]; // up to 64 bool prefs u8 u8_prefs[27]; // 27 u8 prefs }; From e8623d97d331a7ea7bb7f9569875911707ba9ac4 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sat, 11 Nov 2023 18:30:19 -0600 Subject: [PATCH 14/45] small fixes before tackling bigger issues -now using 1 enum class for both timers instead of 2 --- src/mods/deathcounter.cpp | 44 ++-- src/mods/storytimer.cpp | 443 ++++++++++++++++++++++---------------- src/systems/menu_defn.cpp | 17 +- src/systems/pref.cpp | 4 +- src/utils/timerdisp.cpp | 1 - 5 files changed, 283 insertions(+), 226 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 30f6ebf6..8950ce62 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -17,10 +17,10 @@ static u32 s_death_count; static bool s_in_story; void tick() { - - if ( mkb::main_game_mode == mkb::STORY_MODE || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { - s_in_story = true; - } else{ + if (mkb::main_game_mode == mkb::STORY_MODE || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || + mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { + s_in_story = true; + } else { s_in_story = false; } @@ -33,31 +33,33 @@ void tick() { s_can_die = true; } - if (s_can_die == true && (mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT - || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || mkb::sub_mode == mkb:: SMD_GAME_SCENARIO_RETURN)){ - // you can die either by retrying after dropping in, falling out, timing over, or stage selecting after dropping in (but before breaking the tape) + if (s_can_die == true && + (mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || + mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN)) { + // you can die either by retrying after dropping in, falling out, timing over, or stage + // selecting after dropping in (but before breaking the tape) s_death_count += 1; s_can_die = false; } - // first framing should not increase the death counter, and retrying after breaking the tape should not increase it either - // to do: however, if you retry after breaking the tape on the very first frame (so the frame before goal init), it does count as a death when it should not - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + // first framing should not increase the death counter, and retrying after breaking the tape + // should not increase it either to do: however, if you retry after breaking the tape on the + // very first frame (so the frame before goal init), it does count as a death when it should not + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { s_can_die = false; } - } void disp() { + if (s_in_story == false || freecam::should_hide_hud() || + pref::get(pref::BoolPref::ShowDeathCounter) == false) { + return; + } + draw::debug_text(18, 56, draw::WHITE, "Deaths: "); + draw::debug_text(98, 56, draw::WHITE, "%d", s_death_count); - if (s_in_story == false || freecam::should_hide_hud() || pref::get(pref::BoolPref::ShowDeathCounter) == false ){ - return; - } - draw::debug_text(18, 56, draw::WHITE, "Deaths: "); - draw::debug_text(98, 56, draw::WHITE, "%d", s_death_count); - - // to do so I don't forget: get pref for the storytimers so that the the text doesn't overlap - -} +} -} // namespace deathcounter +} // namespace deathcounter diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index f7e02209..50a73e38 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -12,19 +12,12 @@ namespace storytimer { - enum class FullgameTimerOptions { - F_DontShow = 0, - F_AlwaysShow = 1, - F_BetweenWorlds = 2, - F_EndOfRun = 3, - }; - - enum class SegmentTimerOptions { - S_DontShow = 0, - S_AlwaysShow = 1, - S_BetweenWorlds = 2, - S_EndOfRun = 3, - }; +enum class TimerOptions { + DontShow = 0, + AlwaysShow = 1, + BetweenWorlds = 2, + EndOfRun = 3, +}; static u32 s_spin_in_timer; static u32 s_gameplay_timer; @@ -38,154 +31,173 @@ static u32 s_game_scenario_return_timer_correction; static u32 s_world_start_timer_correction; static u32 s_loadless_story_timer; static bool s_in_story; -static bool s_is_on_world[11]; +static bool s_is_on_world[11]; static bool s_is_between_worlds; static bool s_is_run_complete; static bool s_is_on_spin_in; static bool s_is_on_gameplay; static bool s_is_postgoal; -static bool s_is_on_stage_select_screen; +static bool s_is_on_stage_select_screen; static bool s_is_on_exit_game_screen; static bool s_is_on_fallout_screen; static bool s_is_timeover; static bool s_can_increment_stage_counter; static bool s_lower_stage_counter; -static bool s_start_stage_fade_out_timer; -static u32 s_stage_fade_out_timer; +static bool s_start_STAGE_FADE_OUT_TIMEr; +static u32 s_STAGE_FADE_OUT_TIMEr; static u32 s_prev_completed_stage_count; static s32 s_completed_stages; -static u32 s_segment_timer[11]; // IW timer for world k -static u32 s_split[11]; // s_split[k] is the loadless time on tape break of the 10th stage of world k -static u32 s_segment_start_time[11]; // the loadless time at the start of world k, used to calculate s_segment_timer[k] +static u32 s_segment_timer[11]; // IW timer for world k +static u32 s_split[11]; // s_split[k] is the loadless time on tape break of the 10th stage of world + // k +static u32 s_segment_start_time[11]; // the loadless time at the start of world k, used to + // calculate s_segment_timer[k] static bool s_can_change_segment_start_time[11]; static bool s_display_story_timer; static bool s_display_segment_timer; static u32 s_fullgame_timer_location_y; static u32 s_segment_timer_location_y; -static constexpr s32 fullgame_timer_location_x = 18+24; -static constexpr s32 fullgame_timer_text_offset = 56; -static constexpr s32 segment_timer_location_x = 30+24; -static constexpr s32 segment_timer_text_offset = 44; -static constexpr s32 IW_time_location_x = 42+24; -static constexpr s32 IW_time_text_offset = 32; -static constexpr s32 stage_fade_out_time = 49; - +static constexpr s32 FULLGAME_TIMER_LOCATION_X = 18 + 24; +static constexpr s32 FULLGAME_TIMER_TEXT_OFFSET = 56; +static constexpr s32 SEGMENT_TIMER_LOCATION_X = 30 + 24; +static constexpr s32 SEGMENT_TIMER_TEXT_OFFSET = 44; +static constexpr s32 IW_TIME_LOCATION_X = 42 + 24; +static constexpr s32 IW_TIME_TEXT_OFFSET = 32; +static constexpr s32 STAGE_FADE_OUT_TIME = 49; + void tick() { - // for later use, it's useful to record how many stages we've completed - // there is likely a simpler way to increment the stage counter in a way that works when you retry after breaking the tape and also does not break if you pause during - // game goal init or game goal main + // there is likely a simpler way to increment the stage counter in a way that works when you + // retry after breaking the tape and also does not break if you pause during game goal init or + // game goal main - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { // not allowed to increment the stage counter on goal init because of first framing s_can_increment_stage_counter = true; } - if ( (s_completed_stages - s_prev_completed_stage_count) > 0 ) { - // if we've incremented the stage counter already, we're not allowed to increment again until the next game goal main + if ((s_completed_stages - s_prev_completed_stage_count) > 0) { + // if we've incremented the stage counter already, we're not allowed to increment again + // until the next game goal main s_can_increment_stage_counter = false; // however, if you retry after breaking the tape, lower the counter - if (mkb::sub_mode==mkb::SMD_GAME_READY_INIT) { + if (mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { s_lower_stage_counter = true; } else if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { s_lower_stage_counter = false; - s_prev_completed_stage_count = s_completed_stages; + s_prev_completed_stage_count = s_completed_stages; } } if (s_can_increment_stage_counter == true) { - s_completed_stages += 1; + s_completed_stages += 1; } - if (s_lower_stage_counter == true && ((s_completed_stages - s_prev_completed_stage_count) > 0 )) { + if (s_lower_stage_counter == true && + ((s_completed_stages - s_prev_completed_stage_count) > 0)) { s_completed_stages += -1; s_lower_stage_counter = false; } - // for later, it's useful to record what submodes correspond to spin in, gameplay, etc. - // splitting up the timer this way also makes it easier in the future if I decide to implement features such as menuing timeloss + // for later, it's useful to record what submodes correspond to spin in, gameplay, etc. + // splitting up the timer this way also makes it easier in the future if I decide to implement + // features such as menuing timeloss // submodes during spin in - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_INIT || mkb::sub_mode==mkb::SMD_GAME_READY_MAIN) { + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode == mkb::SMD_GAME_READY_INIT || + mkb::sub_mode == mkb::SMD_GAME_READY_MAIN) { s_is_on_spin_in = true; } else { s_is_on_spin_in = false; } // story mode states entered during the story select screen - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE || mkb::g_storymode_stageselect_state == 5 || mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || + mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE || + mkb::g_storymode_stageselect_state == 5 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { // 3, 5 unlabelled inits s_is_on_stage_select_screen = true; - } else { - s_is_on_stage_select_screen = false; - } + } else { + s_is_on_stage_select_screen = false; + } // submodes during gameplay - if (mkb::sub_mode==mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_PLAY_MAIN) { + if (mkb::sub_mode == mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { s_is_on_gameplay = true; } else { s_is_on_gameplay = false; } // submodes entered when exiting game - if (mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT || mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_MAIN - || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_INIT || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_MAIN) { + if (mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT || + mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_MAIN || + mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_INIT || + mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_MAIN) { s_is_on_exit_game_screen = true; - } else{ + } else { s_is_on_exit_game_screen = false; } // submodes entered when breaking the goal tape - if (mkb::sub_mode==mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode==mkb::SMD_GAME_GOAL_MAIN || - mkb::sub_mode==mkb::SMD_GAME_GOAL_REPLAY_INIT || mkb::sub_mode==mkb::SMD_GAME_GOAL_REPLAY_MAIN || mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN || + mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_INIT || + mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_MAIN || + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { s_is_postgoal = true; } else { s_is_postgoal = false; } // submodes for the fallout and y/n screen - if (mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_MAIN - || mkb::sub_mode == mkb::SMD_GAME_RETRY_INIT || mkb::sub_mode == mkb::SMD_GAME_RETRY_MAIN) { + if (mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || + mkb::sub_mode == mkb::SMD_GAME_RINGOUT_MAIN || mkb::sub_mode == mkb::SMD_GAME_RETRY_INIT || + mkb::sub_mode == mkb::SMD_GAME_RETRY_MAIN) { s_is_on_fallout_screen = true; } else { - s_is_on_fallout_screen = false; + s_is_on_fallout_screen = false; } // submodes during timeover - if (mkb:: sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN) { + if (mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || + mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN) { s_is_timeover = true; } else { s_is_timeover = false; } - if ( (mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { - s_in_story = true; - } else{ + if ((mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || + mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { + s_in_story = true; + } else { s_in_story = false; } - // this code is used to halt the timer once the screen becomes completely white when stage selecting out of a level - if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && mkb::g_current_focused_pause_menu_entry == 4 && pad::button_pressed(mkb::PAD_BUTTON_A) == true && s_is_postgoal == true){ - // stage select is on line 4 of the pause menu (top line is line 0) - s_start_stage_fade_out_timer = true; - } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE){ - s_start_stage_fade_out_timer = false; - } - if (s_start_stage_fade_out_timer == true) { - s_stage_fade_out_timer += 1; + // this code is used to halt the timer once the screen becomes completely white when stage + // selecting out of a level + if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && + mkb::g_current_focused_pause_menu_entry == 4 && + pad::button_pressed(mkb::PAD_BUTTON_A) == true && s_is_postgoal == true) { + // stage select is on line 4 of the pause menu (top line is line 0) + s_start_STAGE_FADE_OUT_TIMEr = true; + } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + s_start_STAGE_FADE_OUT_TIMEr = false; + } + if (s_start_STAGE_FADE_OUT_TIMEr == true) { + s_STAGE_FADE_OUT_TIMEr += 1; } else { - s_stage_fade_out_timer = 0; + s_STAGE_FADE_OUT_TIMEr = 0; } + // before starting the run, there are several values we zero on the file select screen (this + // serves to reset the timer) to do: in the future, have the timer not reset unless the file's + // data is reset (either manually or by using the IW move up/down feature) - // before starting the run, there are several values we zero on the file select screen (this serves to reset the timer) - // to do: in the future, have the timer not reset unless the file's data is reset (either manually or by using the IW move up/down feature) - - if (mkb::g_storymode_mode == 5){ + if (mkb::g_storymode_mode == 5) { // zero the timer on the file select screen and set the number of completed stages to 0 s_spin_in_timer_correction = 0; - s_spin_in_timer = 0 ; + s_spin_in_timer = 0; s_gameplay_timer = 0; s_postgoal_timer = 0; s_stage_select_timer = 0; @@ -198,53 +210,60 @@ void tick() { s_loadless_story_timer = 0; s_completed_stages = 0; s_prev_completed_stage_count = 0; - s_start_stage_fade_out_timer = false; - s_stage_fade_out_timer = 0; - for (s32 k=1; k<11; k++) { - // on the file select screen, set these to false just in case you reset while on world k but did not complete 10k stages + s_start_STAGE_FADE_OUT_TIMEr = false; + s_STAGE_FADE_OUT_TIMEr = 0; + for (s32 k = 1; k < 11; k++) { + // on the file select screen, set these to false just in case you reset while on world k + // but did not complete 10k stages s_is_on_world[k] = false; } - - } + } if (s_in_story == true) { - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - // need to add 1 additional frame to the timer during spin in - // putting this code before the code below for s_loadless_story_timer makes the timer tick up more naturally when transitioning from the 10 ball screen to spin in, - // more specifically, this prevents the timer from skipping ahead for a few frames, then pausing for a few frames to even itself out (I don't understand why that happens) + // need to add 1 additional frame to the timer during spin in + // putting this code before the code below for s_loadless_story_timer makes the timer + // tick up more naturally when transitioning from the 10 ball screen to spin in, more + // specifically, this prevents the timer from skipping ahead for a few frames, then + // pausing for a few frames to even itself out (I don't understand why that happens) s_spin_in_timer_correction += 1; } // last 3 terms are correction terms to account for missing frames - s_loadless_story_timer = s_spin_in_timer+s_gameplay_timer+s_postgoal_timer+s_stage_select_timer+s_exit_game_timer+s_fallout_timer+s_timeover_timer+ - +s_spin_in_timer_correction+s_game_scenario_return_timer_correction+ s_world_start_timer_correction; - + s_loadless_story_timer = + s_spin_in_timer + s_gameplay_timer + s_postgoal_timer + s_stage_select_timer + + s_exit_game_timer + s_fallout_timer + s_timeover_timer + +s_spin_in_timer_correction + + s_game_scenario_return_timer_correction + s_world_start_timer_correction; if (s_is_on_spin_in == true) { // increment the timer every frame during spin in - s_spin_in_timer +=1; + s_spin_in_timer += 1; } if (s_is_on_gameplay == true) { - //increment the timer every frame during gameplay - s_gameplay_timer +=1; + // increment the timer every frame during gameplay + s_gameplay_timer += 1; } - if (s_is_postgoal == true && s_stage_fade_out_timer <= stage_fade_out_time) { - // increment the timer every frame after game goal init happens; once you press stage select, a separate 49 frame timer is started (fade out from stage select - // to the first completely white frame takes 49 frames). once the timer hits 49 frames, stop incrementing the timer - // until the 10 ball screen starts spinning in - s_postgoal_timer +=1; + if (s_is_postgoal == true && s_STAGE_FADE_OUT_TIMEr <= STAGE_FADE_OUT_TIME) { + // increment the timer every frame after game goal init happens; once you press stage + // select, a separate 49 frame timer is started (fade out from stage select to the first + // completely white frame takes 49 frames). once the timer hits 49 frames, stop + // incrementing the timer until the 10 ball screen starts spinning in + s_postgoal_timer += 1; } - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { - //increment the timer every frame on the story mode select screen until the a press input; we do not include the transition time after pressing a afterwards - // even ignoring completely white frames, the time spent on mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be - // highly variable (up to over 40 frames sometimes!), so for the purpose of a loadless timer, it makes sense to cut this out from the timer - s_stage_select_timer +=1; + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || + mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { + // increment the timer every frame on the story mode select screen until the a press + // input; we do not include the transition time after pressing a afterwards + // even ignoring completely white frames, the time spent on + // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly variable (up + // to over 40 frames sometimes!), so for the purpose of a loadless timer, it makes + // sense to cut this out from the timer + s_stage_select_timer += 1; } if (s_is_on_exit_game_screen == true) { // increment the timer every frame on the exit game screen - s_exit_game_timer +=1; + s_exit_game_timer += 1; } if (s_is_on_fallout_screen == true) { // increment the timer every frame during the fallout sequence and y/n screen @@ -255,81 +274,92 @@ void tick() { s_timeover_timer += 1; } - for (s32 k=1; k<11; k++) { + for (s32 k = 1; k < 11; k++) { if (s_is_on_world[k] == true) { // need to add 2 frames to the timer at the start of each world - s_world_start_timer_correction = 2*k; + s_world_start_timer_correction = 2 * k; } } - + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % 10 != 0) { - // need to add 2 frames to the timer when stage selecting to the 10 ball screen, but don't correct if on the last stage of a world - // since the next frame the timer should increment on is covered by s_world_start_timer_correction - s_game_scenario_return_timer_correction += 2; - } - + // need to add 2 frames to the timer when stage selecting to the 10 ball screen, but + // don't correct if on the last stage of a world since the next frame the timer should + // increment on is covered by s_world_start_timer_correction + s_game_scenario_return_timer_correction += 2; + } } if (s_completed_stages == 100) { s_is_run_complete = true; - // s_segment_timer[k] is already corrected for tape break (see code below), so no further corrections needed to get an accurate time - s_loadless_story_timer = s_segment_start_time[10]+s_segment_timer[10]; + // s_segment_timer[k] is already corrected for tape break (see code below), so no further + // corrections needed to get an accurate time + s_loadless_story_timer = s_segment_start_time[10] + s_segment_timer[10]; } else { s_is_run_complete = false; } // it is useful to know when we are between worlds (for the "between worlds" option in the menu) - if ( (s_completed_stages % 10 == 0) && s_completed_stages != 0 && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN){ - s_is_between_worlds = true; - } else if ( (s_completed_stages % 10 == 0 && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) || s_completed_stages % 10 !=0 ){ - // no longer "between worlds" if you enter the next worlds 10 ball screen, or if you break the tape on the last stage - // of the current world, but retry - s_is_between_worlds = false; - } + if ((s_completed_stages % 10 == 0) && s_completed_stages != 0 && + mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { + s_is_between_worlds = true; + } else if ((s_completed_stages % 10 == 0 && + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) || + s_completed_stages % 10 != 0) { + // no longer "between worlds" if you enter the next worlds 10 ball screen, or if you break + // the tape on the last stage of the current world, but retry + s_is_between_worlds = false; + } // code for handling loadless split and segment times - for (s32 k=1; k<11; k++){ - - // if you enter the first stage of the next world but then stage select, do not restart the segment timer - if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { + for (s32 k = 1; k < 11; k++) { + // if you enter the first stage of the next world but then stage select, do not restart the + // segment timer + if (s_completed_stages == 10 * (k - 1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { s_can_change_segment_start_time[k] = true; - } else if (s_completed_stages == 10*(k-1) && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + } else if (s_completed_stages == 10 * (k - 1) && + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { s_can_change_segment_start_time[k] = false; } - if (s_completed_stages == 10*(k-1) && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_can_change_segment_start_time[k] == true) { + if (s_completed_stages == 10 * (k - 1) && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && + s_can_change_segment_start_time[k] == true) { s_segment_start_time[k] = s_loadless_story_timer; } - - if ( ( (10*(k-1) <= s_completed_stages) && (s_completed_stages <= (10*k-2) ) ) || (s_completed_stages == (10*k-1) && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT) ){ + + if (((10 * (k - 1) <= s_completed_stages) && (s_completed_stages <= (10 * k - 2))) || + (s_completed_stages == (10 * k - 1) && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT)) { s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k]; - } else if (s_completed_stages == (10*k-1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { - // I don't know a better way of doing this to make the timer show the time at tape break - // if we show the segment timer at all times, since the timer will run for 2 frames after breaking the tape - s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k] -3; + } else if (s_completed_stages == (10 * k - 1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { + // I don't know a better way of doing this to make the timer show the time at tape break + // if we show the segment timer at all times, since the timer will run for 2 frames + // after breaking the tape + s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k] - 3; } - // fullgame loadless time upon breaking the tape on the last stage of world k - s_split[k] = s_segment_start_time[k]+s_segment_timer[k]; + // fullgame loadless time upon breaking the tape on the last stage of world k + s_split[k] = s_segment_start_time[k] + s_segment_timer[k]; - if ( ( (10*(k-1) +1)<= s_completed_stages) && (s_completed_stages <= (10*k-1)) ) { - s_is_on_world[k] = true; - } else if (s_completed_stages == 10*(k-1) && (s_is_on_stage_select_screen == true || s_is_on_spin_in == true || s_is_on_gameplay == true) ){ - // if you've completed 10*(k-1) stages, are in world k, but haven't completed the first stage yet, then you are not in world k-1 - s_is_on_world[k-1] = false; + if (((10 * (k - 1) + 1) <= s_completed_stages) && (s_completed_stages <= (10 * k - 1))) { + s_is_on_world[k] = true; + } else if (s_completed_stages == 10 * (k - 1) && + (s_is_on_stage_select_screen == true || s_is_on_spin_in == true || + s_is_on_gameplay == true)) { + // if you've completed 10*(k-1) stages, are in world k, but haven't completed the first + // stage yet, then you are not in world k-1 + s_is_on_world[k - 1] = false; s_is_on_world[k] = true; - } else if (s_completed_stages == 10*k && s_is_postgoal == true && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT && mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN) { + } else if (s_completed_stages == 10 * k && s_is_postgoal == true && + mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT && + mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN) { s_is_on_world[k] = true; } } - } void disp() { - - if (s_in_story == false || freecam::should_hide_hud() ){ - return; - } + if (s_in_story == false || freecam::should_hide_hud()) { + return; + } // move the positions of the fullgame and segment timers if the death counter is on if (pref::get(pref::BoolPref::ShowDeathCounter) == true) { @@ -338,90 +368,123 @@ void disp() { s_fullgame_timer_location_y = 2; } - // if the fullgame timer and death counter is off but the segment timer is on, move the segment timer to the top line; if either the fullgame timer or death counter are on but not both are on, - // move it to the 2nd line, if all 3 are enabled, put it on the 3rd line - if(s_display_story_timer == false && pref::get(pref::BoolPref::ShowDeathCounter) == false ){ + // if the fullgame timer and death counter is off but the segment timer is on, move the segment + // timer to the top line; if either the fullgame timer or death counter are on but not both are + // on, move it to the 2nd line, if all 3 are enabled, put it on the 3rd line + if (s_display_story_timer == false && pref::get(pref::BoolPref::ShowDeathCounter) == false) { s_segment_timer_location_y = 2; - } else if (s_display_story_timer == false || pref::get(pref::BoolPref::ShowDeathCounter) == false ){ - s_segment_timer_location_y = 3; - } else { - s_segment_timer_location_y = 4; - } + } else if (s_display_story_timer == false || + pref::get(pref::BoolPref::ShowDeathCounter) == false) { + s_segment_timer_location_y = 3; + } else { + s_segment_timer_location_y = 4; + } - switch(FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions))) { - case FullgameTimerOptions::F_AlwaysShow: + switch (TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions))) { + case TimerOptions::AlwaysShow: s_display_story_timer = true; break; - case FullgameTimerOptions::F_BetweenWorlds: + case TimerOptions::BetweenWorlds: if (s_is_between_worlds == true) { s_display_story_timer = true; } else { s_display_story_timer = false; } break; - case FullgameTimerOptions::F_EndOfRun: - if (s_is_run_complete == true){ + case TimerOptions::EndOfRun: + if (s_is_run_complete == true) { s_display_story_timer = true; } else { s_display_story_timer = false; } break; - case FullgameTimerOptions::F_DontShow: + case TimerOptions::DontShow: s_display_story_timer = false; break; } - if (s_display_story_timer == true){ - timerdisp::draw_timer(fullgame_timer_location_x, s_fullgame_timer_location_y, fullgame_timer_text_offset, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); + if (s_display_story_timer == true) { + timerdisp::draw_timer(FULLGAME_TIMER_LOCATION_X, s_fullgame_timer_location_y, + FULLGAME_TIMER_TEXT_OFFSET, "Time:", s_loadless_story_timer, 0, false, + false, draw::WHITE); } - switch(SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { - case SegmentTimerOptions::S_AlwaysShow: - for (s32 k=1; k<11; k++){ + switch (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { + case TimerOptions::AlwaysShow: + for (s32 k = 1; k < 11; k++) { if (s_is_on_world[k] == true && s_is_run_complete == false) { - timerdisp::draw_timer(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); + timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, + SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, + false, false, draw::WHITE); } - } break; - case SegmentTimerOptions::S_BetweenWorlds: - for (s32 k=1; k<11; k++){ + case TimerOptions::BetweenWorlds: + for (s32 k = 1; k < 11; k++) { if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { - timerdisp::draw_timer(segment_timer_location_x, s_segment_timer_location_y, segment_timer_text_offset, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); - } + timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, + SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, + false, false, draw::WHITE); + } } break; - case SegmentTimerOptions::S_DontShow: + case TimerOptions::DontShow: s_display_segment_timer = false; break; } - // if the segment timer is enabled in any capacity, show all 10 split times + iw times after the tape is broken on the last stage - if (SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != SegmentTimerOptions::S_DontShow) { - if (s_is_run_complete == true) { + // if the segment timer is enabled in any capacity, show all 10 split times + iw times after the + // tape is broken on the last stage + if (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != + TimerOptions::DontShow) { + if (s_is_run_complete == true) { // I'm so sorry :( // I don't know how to get the text to show "Wk" where k ranges in a for loop - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y, IW_time_text_offset, "W1:", s_split[1], s_segment_timer[1], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+1, IW_time_text_offset, "W2:", s_split[2], s_segment_timer[2], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+2, IW_time_text_offset, "W3:", s_split[3], s_segment_timer[3], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+3, IW_time_text_offset, "W4:", s_split[4], s_segment_timer[4], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+4, IW_time_text_offset, "W5:", s_split[5], s_segment_timer[5], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+5, IW_time_text_offset, "W6:", s_split[6], s_segment_timer[6], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+6, IW_time_text_offset, "W7:", s_split[7], s_segment_timer[7], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+7, IW_time_text_offset, "W8:", s_split[8], s_segment_timer[8], true, false, draw::WHITE); - timerdisp::draw_timer(IW_time_location_x, s_segment_timer_location_y+8, IW_time_text_offset, "W9:", s_split[9], s_segment_timer[9], true, false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y, + IW_TIME_TEXT_OFFSET, "W1:", s_split[1], s_segment_timer[1], true, + false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 1, + IW_TIME_TEXT_OFFSET, "W2:", s_split[2], s_segment_timer[2], true, + false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 2, + IW_TIME_TEXT_OFFSET, "W3:", s_split[3], s_segment_timer[3], true, + false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 3, + IW_TIME_TEXT_OFFSET, "W4:", s_split[4], s_segment_timer[4], true, + false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 4, + IW_TIME_TEXT_OFFSET, "W5:", s_split[5], s_segment_timer[5], true, + false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 5, + IW_TIME_TEXT_OFFSET, "W6:", s_split[6], s_segment_timer[6], true, + false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 6, + IW_TIME_TEXT_OFFSET, "W7:", s_split[7], s_segment_timer[7], true, + false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 7, + IW_TIME_TEXT_OFFSET, "W8:", s_split[8], s_segment_timer[8], true, + false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 8, + IW_TIME_TEXT_OFFSET, "W9:", s_split[9], s_segment_timer[9], true, + false, draw::WHITE); // use segment timer spacing for w10 since "W10" is 3 characters long, not 2 - timerdisp::draw_timer(segment_timer_location_x, s_segment_timer_location_y+9, segment_timer_text_offset, "W10:", s_split[10], s_segment_timer[10], true, false, draw::WHITE); - } + timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y + 9, + SEGMENT_TIMER_TEXT_OFFSET, "W10:", s_split[10], + s_segment_timer[10], true, false, draw::WHITE); + } } - // show warning on the name entry screen if no timers are on (if the toggle for the warning is turned on) - if (pref::get(pref::BoolPref::StoryTimerWarning) == true && FullgameTimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == FullgameTimerOptions::F_DontShow - && SegmentTimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) == SegmentTimerOptions::S_DontShow && mkb::g_storymode_mode == 21){ + // show warning on the name entry screen if no timers are on (if the toggle for the warning is + // turned on) + if (pref::get(pref::BoolPref::StoryTimerWarning) == true && + TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == + TimerOptions::DontShow && + TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) == + TimerOptions::DontShow && + mkb::g_storymode_mode == 21) { // mkb::g_storymode_mode 21 is the name entry screen, not sure if it has a name in ghidra draw::debug_text(460, 425, draw::RED, "Timer Not On!"); } +} -} - -} // namespace storytimer +} // namespace storytimer diff --git a/src/systems/menu_defn.cpp b/src/systems/menu_defn.cpp index b5e031b0..99c0b5fd 100644 --- a/src/systems/menu_defn.cpp +++ b/src/systems/menu_defn.cpp @@ -658,14 +658,7 @@ static Widget s_cm_seg_widgets[] = { }, }; -static const char* FULLGAME_TIMER_OPTIONS[] = { - "Don't show", - "Always show", - "Between worlds", - "End of run", -}; - -static const char* SEGMENT_TIMER_OPTIONS[] = { +static const char* TIMER_OPTIONS[] = { "Don't show", "Always show", "Between worlds", @@ -678,8 +671,8 @@ static Widget s_loadless_timers_widgets[] = { .choose = { .label = "Fullgame Timer", - .choices = FULLGAME_TIMER_OPTIONS, - .num_choices = LEN(FULLGAME_TIMER_OPTIONS), + .choices = TIMER_OPTIONS, + .num_choices = LEN(TIMER_OPTIONS), .pref = pref::U8Pref::FullgameTimerOptions, }, }, @@ -688,8 +681,8 @@ static Widget s_loadless_timers_widgets[] = { .choose = { .label = "Segment Timer", - .choices = SEGMENT_TIMER_OPTIONS, - .num_choices = LEN(SEGMENT_TIMER_OPTIONS), + .choices = TIMER_OPTIONS, + .num_choices = LEN(TIMER_OPTIONS), .pref = pref::U8Pref::SegmentTimerOptions, }, }, diff --git a/src/systems/pref.cpp b/src/systems/pref.cpp index 41901417..27ecb3e0 100644 --- a/src/systems/pref.cpp +++ b/src/systems/pref.cpp @@ -358,8 +358,8 @@ static DefaultU8Pref s_default_u8_prefs[] = { // struct PrefState { - u8 bool_prefs[9]; // up to 64 bool prefs - u8 u8_prefs[27]; // 27 u8 prefs + u8 bool_prefs[9]; + u8 u8_prefs[27]; }; static PrefState s_pref_state, s_default_pref_state; diff --git a/src/utils/timerdisp.cpp b/src/utils/timerdisp.cpp index 4d3bf52e..9c5e1d04 100644 --- a/src/utils/timerdisp.cpp +++ b/src/utils/timerdisp.cpp @@ -9,7 +9,6 @@ static constexpr u32 MINUTE_FRAMES = SECOND_FRAMES * 60; static constexpr u32 HOUR_FRAMES = MINUTE_FRAMES * 60; static constexpr s32 X = 380; -static constexpr s32 X_2 = 18; static constexpr s32 Y = 24; void draw_timer(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color){ From 3286dfa37a21ac498416417329f39e7997658f63 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sat, 11 Nov 2023 18:33:25 -0600 Subject: [PATCH 15/45] =?UTF-8?q?Delete=20storytimer.cpp=EF=80=BAZone.Iden?= =?UTF-8?q?tifier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "src/mods/storytimer.cpp\357\200\272Zone.Identifier" | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 "src/mods/storytimer.cpp\357\200\272Zone.Identifier" diff --git "a/src/mods/storytimer.cpp\357\200\272Zone.Identifier" "b/src/mods/storytimer.cpp\357\200\272Zone.Identifier" deleted file mode 100644 index 43a1a01e..00000000 --- "a/src/mods/storytimer.cpp\357\200\272Zone.Identifier" +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=https://github.com/ From 475cffec0b659a38d9e8d0fc9aec44e70fe55d2b Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Mon, 13 Nov 2023 16:51:47 -0600 Subject: [PATCH 16/45] small changes -rewrote completed stages code (will probably try and simplify still) -small changes to death counter --- src/mods/deathcounter.cpp | 27 ++++----- src/mods/storytimer.cpp | 112 ++++++++++++++++++++++++++------------ 2 files changed, 89 insertions(+), 50 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 8950ce62..8a420e0d 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -14,16 +14,9 @@ namespace deathcounter { static bool s_can_die; static u32 s_death_count; -static bool s_in_story; void tick() { - if (mkb::main_game_mode == mkb::STORY_MODE || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || - mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { - s_in_story = true; - } else { - s_in_story = false; - } - + // bool paused_now = *reinterpret_cast(0x805BC474) & 8; // set the death count to 0 on the file select screen if (mkb::g_storymode_mode == 5) { s_death_count = 0; @@ -33,12 +26,14 @@ void tick() { s_can_die = true; } - if (s_can_die == true && + if (s_can_die && (mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || - mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN)) { - // you can die either by retrying after dropping in, falling out, timing over, or stage - // selecting after dropping in (but before breaking the tape) + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN || + mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT)) { + // you can die either by retrying after dropping in, falling out, timing over, stage + // selecting after dropping in (but before breaking the tape), or exiting game after + // dropping in (but before breaking the tape) s_death_count += 1; s_can_die = false; } @@ -50,16 +45,18 @@ void tick() { mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { s_can_die = false; } + + } void disp() { - if (s_in_story == false || freecam::should_hide_hud() || - pref::get(pref::BoolPref::ShowDeathCounter) == false) { + if ((mkb::main_game_mode != mkb::STORY_MODE && mkb::sub_mode != mkb::SMD_AUTHOR_PLAY_INIT && + mkb::sub_mode != mkb::SMD_AUTHOR_PLAY_MAIN) || + freecam::should_hide_hud() || pref::get(pref::BoolPref::ShowDeathCounter) == false) { return; } draw::debug_text(18, 56, draw::WHITE, "Deaths: "); draw::debug_text(98, 56, draw::WHITE, "%d", s_death_count); - } } // namespace deathcounter diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 50a73e38..8a24245c 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -41,8 +41,7 @@ static bool s_is_on_stage_select_screen; static bool s_is_on_exit_game_screen; static bool s_is_on_fallout_screen; static bool s_is_timeover; -static bool s_can_increment_stage_counter; -static bool s_lower_stage_counter; +static bool s_can_lower_stage_counter; static bool s_start_STAGE_FADE_OUT_TIMEr; static u32 s_STAGE_FADE_OUT_TIMEr; static u32 s_prev_completed_stage_count; @@ -64,39 +63,30 @@ static constexpr s32 SEGMENT_TIMER_TEXT_OFFSET = 44; static constexpr s32 IW_TIME_LOCATION_X = 42 + 24; static constexpr s32 IW_TIME_TEXT_OFFSET = 32; static constexpr s32 STAGE_FADE_OUT_TIME = 49; +static u32 s_dummy; +static u32 s_dummy_2; +static u32 s_dummy_3; void tick() { // for later use, it's useful to record how many stages we've completed - // there is likely a simpler way to increment the stage counter in a way that works when you - // retry after breaking the tape and also does not break if you pause during game goal init or - // game goal main - - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { - // not allowed to increment the stage counter on goal init because of first framing - s_can_increment_stage_counter = true; - } - - if ((s_completed_stages - s_prev_completed_stage_count) > 0) { - // if we've incremented the stage counter already, we're not allowed to increment again - // until the next game goal main - s_can_increment_stage_counter = false; - // however, if you retry after breaking the tape, lower the counter - if (mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { - s_lower_stage_counter = true; - } else if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - s_lower_stage_counter = false; - s_prev_completed_stage_count = s_completed_stages; - } - } - - if (s_can_increment_stage_counter == true) { + // increment the completed stages by 1 during the init + // need to check that the game is not paused to ensure the counter only goes up by 1 + bool paused_now = *reinterpret_cast(0x805BC474) & 8; + if (!paused_now && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { s_completed_stages += 1; + s_can_lower_stage_counter = true; } - if (s_lower_stage_counter == true && - ((s_completed_stages - s_prev_completed_stage_count) > 0)) { + // if you retry after SMD_GAME_GOAL_INIT but before returning to the stage select screen, lower the counter by exactly 1 + if (s_can_lower_stage_counter && mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { s_completed_stages += -1; - s_lower_stage_counter = false; + s_can_lower_stage_counter = false; + } + + // once you leave a stage, set this to false to ensure the completed stage count is not lowered + // when entering spin in on the next stage + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + s_can_lower_stage_counter = false; } // for later, it's useful to record what submodes correspond to spin in, gameplay, etc. @@ -206,7 +196,7 @@ void tick() { s_exit_game_timer = 0; s_fallout_timer = 0; s_timeover_timer = 0; - s_lower_stage_counter = false; + s_can_lower_stage_counter = false; s_loadless_story_timer = 0; s_completed_stages = 0; s_prev_completed_stage_count = 0; @@ -435,8 +425,7 @@ void disp() { // if the segment timer is enabled in any capacity, show all 10 split times + iw times after the // tape is broken on the last stage - if (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != - TimerOptions::DontShow) { + if (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != TimerOptions::DontShow) { if (s_is_run_complete == true) { // I'm so sorry :( // I don't know how to get the text to show "Wk" where k ranges in a for loop @@ -477,14 +466,67 @@ void disp() { // show warning on the name entry screen if no timers are on (if the toggle for the warning is // turned on) if (pref::get(pref::BoolPref::StoryTimerWarning) == true && - TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == - TimerOptions::DontShow && - TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) == - TimerOptions::DontShow && + TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == TimerOptions::DontShow && + TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) == TimerOptions::DontShow && mkb::g_storymode_mode == 21) { // mkb::g_storymode_mode 21 is the name entry screen, not sure if it has a name in ghidra draw::debug_text(460, 425, draw::RED, "Timer Not On!"); } + + // debugging + + if (s_is_between_worlds == true) { + s_dummy = 1; + } else { + s_dummy = 0; + /* things tested that didn't work for exit game so far + SMD_GAME_FORCE_EXIT_MAIN=93 + SMD_GAME_FORCE_OVER_MAIN=96 + SMD_GAME_OVER_POINT_MAIN=86 + + things that do work + SMD_GAME_SUGG_SAVE_MAIN, doesn't include playpoint text, only the save data question after + SMD_GAME_INTR_SEL_MAIN is the playpoint text + + fallout submode testing + test: 50, 51, 58, 59, 90, 91, 48, 49, + + SMD_GAME_READY_INIT=48, + SMD_GAME_READY_MAIN=49, + SMD_GAME_RINGOUT_INIT=58, + SMD_GAME_RINGOUT_MAIN=59 + SMD_GAME_RETRY_INIT=90, + SMD_GAME_RETRY_MAIN=91 + + conclusion: ringout = fallout submode, game retry init/main = y/n menu + + FOR LATER, TRY THESE: + SMD_GAME_SCENSCNPLAY_RETURN=94 (missing frame on world entry?) + SMD_AUTHOR_PLAY_INIT=247, + SMD_AUTHOR_PLAY_MAIN=248, + SMD_AUTHOR_PLAY_STORY_INIT=249, + + */ + } + if (pad::button_pressed(mkb::PAD_BUTTON_A) == true) { + s_dummy_2 = 1; + } else { + s_dummy_2 = 0; + } + + /* + if (pad::button_pressed(mkb::PAD_BUTTON_DOWN)) { + s_completed_stages = 91; + } + */ + + if (TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == TimerOptions::AlwaysShow) { + timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(60 * s_completed_stages), 1, + false, true, draw::WHITE); + timerdisp::draw_timer(380, 1, 44, "dbg:", static_cast(60*mkb::get_world_unbeaten_stage_count(0)), 1, false, true, draw::WHITE); + //timerdisp::draw_timer(380, 2, 44, "dbg:", static_cast(60*), 1, false, true, draw::WHITE); + } + // mkb::scen_info.world } } // namespace storytimer From 2f1d3c78e3735e2e45491145533728ccadfa51c5 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Mon, 13 Nov 2023 21:45:16 -0600 Subject: [PATCH 17/45] updated names to match new ghidra header --- src/mods/deathcounter.cpp | 4 +--- src/mods/storytimer.cpp | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 8a420e0d..53e2223c 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -18,7 +18,7 @@ static u32 s_death_count; void tick() { // bool paused_now = *reinterpret_cast(0x805BC474) & 8; // set the death count to 0 on the file select screen - if (mkb::g_storymode_mode == 5) { + if (mkb::scen_info.mode == 5) { s_death_count = 0; } @@ -45,8 +45,6 @@ void tick() { mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { s_can_die = false; } - - } void disp() { diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 39028d0a..8e36f36d 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -80,7 +80,8 @@ void tick() { s_can_lower_stage_counter = true; } - // if you retry after SMD_GAME_GOAL_INIT but before returning to the stage select screen, lower the counter by exactly 1 + // if you retry after SMD_GAME_GOAL_INIT but before returning to the stage select screen, lower + // the counter by exactly 1 if (s_can_lower_stage_counter && mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { s_completed_stages += -1; s_can_lower_stage_counter = false; @@ -187,7 +188,7 @@ void tick() { // serves to reset the timer) to do: in the future, have the timer not reset unless the file's // data is reset (either manually or by using the IW move up/down feature) - if (mkb::g_storymode_mode == 5) { + if (mkb::scen_info.mode == 5) { // zero the timer on the file select screen and set the number of completed stages to 0 s_spin_in_timer_correction = 0; s_spin_in_timer = 0; @@ -471,8 +472,8 @@ void disp() { if (pref::get(pref::BoolPref::StoryTimerWarning) == true && TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == TimerOptions::DontShow && TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) == TimerOptions::DontShow && - mkb::g_storymode_mode == 21) { - // mkb::g_storymode_mode 21 is the name entry screen, not sure if it has a name in ghidra + mkb::scen_info.mode == 21) { + // mkb::scen_info.mode 21 is the name entry screen, not sure if it has a name in ghidra draw::debug_text(460, 425, draw::RED, "Timer Not On!"); } @@ -524,10 +525,14 @@ void disp() { */ if (TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == TimerOptions::AlwaysShow) { - timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(60*s_completed_stages), 1, + timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(60 * s_completed_stages), 1, + false, true, draw::WHITE); + timerdisp::draw_timer(380, 1, 44, + "dbg:", static_cast(60 * mkb::get_world_unbeaten_stage_count(0)), + 1, false, true, draw::WHITE); + timerdisp::draw_timer(380, 2, 44, + "dbg:", static_cast(60 * mkb::mode_info.g_selected_world_idx), 1, false, true, draw::WHITE); - timerdisp::draw_timer(380, 1, 44, "dbg:", static_cast(60*mkb::get_world_unbeaten_stage_count(0)), 1, false, true, draw::WHITE); - timerdisp::draw_timer(380, 2, 44, "dbg:", static_cast(60*mkb::mode_info.g_selected_world_idx), 1, false, true, draw::WHITE); } // mkb::scen_info.world // 10*mkb::scen_info.world+mkb::get_world_unbeaten_stage_count(mkb::scen_info.world) From 4a69bcd5e42db75c9126edaa744676a2d348d8ec Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 14 Nov 2023 16:13:40 -0600 Subject: [PATCH 18/45] starting to rewrite segment timer code (not finished) --- src/mods/storytimer.cpp | 244 ++++++++++++++++++++++++++++++++-------- 1 file changed, 198 insertions(+), 46 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 8e36f36d..4a387b5c 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -31,8 +31,21 @@ static u32 s_game_scenario_return_timer_correction; static u32 s_world_start_timer_correction; static u32 s_loadless_story_timer; struct TimerGroup { - static u32 test; + u32 segment; + u32 full_world; + u32 spin_in; + u32 spin_in_correction; + u32 gameplay; + u32 postgoal; + u32 stage_select; + u32 game_scenario_return_correction; + u32 world_start_correction; + u32 exit_game; + u32 fallout; + u32 timeover; + u32 last_stage_postgoal; }; +static TimerGroup s_timer_group[10]; static bool s_in_story; static bool s_is_on_world[11]; static bool s_is_between_worlds; @@ -46,9 +59,10 @@ static bool s_is_on_fallout_screen; static bool s_is_timeover; static bool s_can_lower_stage_counter; static bool s_start_STAGE_FADE_OUT_TIMEr; -static u32 s_STAGE_FADE_OUT_TIMEr; +static u32 s_stage_fade_out_timer; static u32 s_prev_completed_stage_count; static s32 s_completed_stages; +static s32 s_completed_stages_world[10]; static u32 s_segment_timer[11]; // IW timer for world k static u32 s_split[11]; // s_split[k] is the loadless time on tape break of the 10th stage of world // k @@ -66,43 +80,61 @@ static constexpr s32 SEGMENT_TIMER_TEXT_OFFSET = 44; static constexpr s32 IW_TIME_LOCATION_X = 42 + 24; static constexpr s32 IW_TIME_TEXT_OFFSET = 32; static constexpr s32 STAGE_FADE_OUT_TIME = 49; +static constexpr u32 WORLD_START_CORRECTION = 2; static u32 s_dummy; static u32 s_dummy_2; static u32 s_dummy_3; void tick() { + bool paused_now = *reinterpret_cast(0x805BC474) & 8; // for later use, it's useful to record how many stages we've completed // increment the completed stages by 1 during the init // need to check that the game is not paused to ensure the counter only goes up by 1 - bool paused_now = *reinterpret_cast(0x805BC474) & 8; - if (!paused_now && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { - s_completed_stages += 1; - s_can_lower_stage_counter = true; - } + for (s32 k = 0; k < 10; k++) { + if (mkb::scen_info.world == k) { + if (!paused_now && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { + s_completed_stages += 1; + s_completed_stages_world[k] += 1; + s_can_lower_stage_counter = true; + } - // if you retry after SMD_GAME_GOAL_INIT but before returning to the stage select screen, lower - // the counter by exactly 1 - if (s_can_lower_stage_counter && mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { - s_completed_stages += -1; - s_can_lower_stage_counter = false; - } + // if you retry after SMD_GAME_GOAL_INIT but before returning to the stage select + // screen, lower the counter by exactly 1 + if (s_can_lower_stage_counter && mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { + s_completed_stages += -1; + s_completed_stages_world[k] += 1; + s_can_lower_stage_counter = false; + } - // once you leave a stage, set this to false to ensure the completed stage count is not lowered - // when entering spin in on the next stage - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - s_can_lower_stage_counter = false; + // once you leave a stage, set this to false to ensure the completed stage count is not + // lowered when entering spin in on the next stage + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + s_can_lower_stage_counter = false; + } + } } // for later, it's useful to record what submodes correspond to spin in, gameplay, etc. // splitting up the timer this way also makes it easier in the future if I decide to implement // features such as menuing timeloss + bool is_on_spin_in = 0; + bool is_on_stage_select = 0; + bool is_on_gameplay = 0; + bool is_on_exit_game = 0; + bool is_postgoal = 0; + bool is_on_fallout = 0; + bool is_timeover = 0; + bool in_story = 0; + // submodes during spin in if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_READY_MAIN) { s_is_on_spin_in = true; + is_on_spin_in = true; } else { s_is_on_spin_in = false; + is_on_spin_in = false; } // story mode states entered during the story select screen @@ -113,15 +145,19 @@ void tick() { mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { // 3, 5 unlabelled inits s_is_on_stage_select_screen = true; + is_on_stage_select = true; } else { s_is_on_stage_select_screen = false; + is_on_stage_select = false; } // submodes during gameplay if (mkb::sub_mode == mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { s_is_on_gameplay = true; + is_on_gameplay = true; } else { s_is_on_gameplay = false; + is_on_gameplay = false; } // submodes entered when exiting game @@ -130,8 +166,10 @@ void tick() { mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_INIT || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_MAIN) { s_is_on_exit_game_screen = true; + is_on_exit_game = true; } else { s_is_on_exit_game_screen = false; + is_on_exit_game = false; } // submodes entered when breaking the goal tape @@ -140,8 +178,10 @@ void tick() { mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_MAIN || mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { s_is_postgoal = true; + is_postgoal = true; } else { s_is_postgoal = false; + is_postgoal = false; } // submodes for the fallout and y/n screen @@ -149,23 +189,29 @@ void tick() { mkb::sub_mode == mkb::SMD_GAME_RINGOUT_MAIN || mkb::sub_mode == mkb::SMD_GAME_RETRY_INIT || mkb::sub_mode == mkb::SMD_GAME_RETRY_MAIN) { s_is_on_fallout_screen = true; + is_on_fallout = true; } else { s_is_on_fallout_screen = false; + is_on_fallout = false; } // submodes during timeover if (mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN) { s_is_timeover = true; + is_timeover = true; } else { s_is_timeover = false; + is_timeover = false; } if ((mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { s_in_story = true; + in_story = true; } else { s_in_story = false; + in_story = false; } // this code is used to halt the timer once the screen becomes completely white when stage @@ -179,17 +225,18 @@ void tick() { s_start_STAGE_FADE_OUT_TIMEr = false; } if (s_start_STAGE_FADE_OUT_TIMEr == true) { - s_STAGE_FADE_OUT_TIMEr += 1; + s_stage_fade_out_timer += 1; } else { - s_STAGE_FADE_OUT_TIMEr = 0; + s_stage_fade_out_timer = 0; } // before starting the run, there are several values we zero on the file select screen (this // serves to reset the timer) to do: in the future, have the timer not reset unless the file's // data is reset (either manually or by using the IW move up/down feature) - if (mkb::scen_info.mode == 5) { - // zero the timer on the file select screen and set the number of completed stages to 0 + if (mkb::scen_info.mode == 5 || mkb::scen_info.mode == 21) { + // zero the timer on the file select screen & name entry screen, and set the number of + // completed stages to 0 s_spin_in_timer_correction = 0; s_spin_in_timer = 0; s_gameplay_timer = 0; @@ -205,14 +252,118 @@ void tick() { s_completed_stages = 0; s_prev_completed_stage_count = 0; s_start_STAGE_FADE_OUT_TIMEr = false; - s_STAGE_FADE_OUT_TIMEr = 0; + s_stage_fade_out_timer = 0; + for (s32 k = 0; k < 10; k++) { + s_timer_group[k] = {}; + s_completed_stages_world[k] = 0; + } + /* for (s32 k = 1; k < 11; k++) { // on the file select screen, set these to false just in case you reset while on world k // but did not complete 10k stages s_is_on_world[k] = false; } + */ } + if (s_in_story == true) { + for (s32 k = 0; k < 10; k++) { + if (mkb::scen_info.world == k) { + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { + // need to add 1 additional frame to the timer during spin in + // putting this code before the code below for s_loadless_story_timer makes the + // timer tick up more naturally when transitioning from the 10 ball screen to + // spin in, more specifically, this prevents the timer from skipping ahead for a + // few frames, then pausing for a few frames to even itself out (I don't + // understand why that happens) + s_timer_group[k].spin_in_correction += 1; + } + + // last 3 terms are correction terms to account for missing frames + s_timer_group[k].full_world = + s_timer_group[k].spin_in + s_timer_group[k].spin_in_correction + + s_timer_group[k].gameplay + s_timer_group[k].postgoal + + s_timer_group[k].stage_select + + s_timer_group[k].game_scenario_return_correction + s_timer_group[k].exit_game + + s_timer_group[k].fallout + s_timer_group[k].timeover + + s_timer_group[k].world_start_correction + s_timer_group[k].last_stage_postgoal; + + if (s_completed_stages_world[k] <= 8 || + (s_completed_stages_world[k] == 9 && !is_postgoal)) { + s_timer_group[k].segment = s_timer_group[k].full_world; + } else if (s_completed_stages_world[k] == 9 && + mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { + s_timer_group[k].segment += -2; + } + + if (is_on_spin_in) { + // increment the timer every frame during spin in + s_timer_group[k].spin_in += 1; + } + if (is_on_gameplay) { + // increment the timer every frame during gameplay + s_timer_group[k].gameplay += 1; + } + if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { + // increment the timer every frame after game goal init happens; once you press + // stage select, a separate 49 frame timer is started (fade out from stage + // select to the first completely white frame takes 49 frames). once the timer + // hits 49 frames, stop incrementing the timer until the 10 ball screen starts + // spinning in + if (mkb::get_world_unbeaten_stage_count(k) <= 8) { + s_timer_group[k].postgoal += 1; + } else if (mkb::get_world_unbeaten_stage_count(k) == 9) { + s_timer_group[k].last_stage_postgoal += 1; + } + } + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || + mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { + // increment the timer every frame on the story mode select screen until the a + // press input; we do not include the transition time after pressing a + // afterwards + // even ignoring completely white frames, the time spent on + // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly + // variable (up to over 40 frames sometimes!), so for the purpose of a loadless + // timer, it makes sense to cut this out from the timer + s_timer_group[k].stage_select += 1; + } + if (is_on_exit_game) { + // increment the timer every frame on the exit game screen + s_timer_group[k].exit_game += 1; + } + if (is_on_fallout) { + // increment the timer every frame during the fallout sequence and y/n screen + s_timer_group[k].fallout += 1; + } + if (is_timeover) { + // increment the timer every frame during the timeover sequence + s_timer_group[k].timeover += 1; + } + + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && + s_completed_stages % 10 != 0) { + // need to add 2 frames to the timer when stage selecting to the 10 ball screen, + // but don't correct if on the last stage of a world since the next frame the + // timer should increment on is covered by s_world_start_timer_correction + s_game_scenario_return_timer_correction += 2; + } + + // this only gets set to 2 when you enter world k + s_timer_group[k].world_start_correction = 2; + } + } + } + /* + // the fullgame timer is the sum of the segment timers; however, since the segment timers + // stop on tape break on the last stage of a world, we need to include this time for all worlds + // except for world 10 + for (s32 k = 0; k < 9; k++) { + s_loadless_story_timer = s_loadless_story_timer + s_timer_group[k].full_world + + s_timer_group[9].segment; + } + */ + if (s_in_story == true) { if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { // need to add 1 additional frame to the timer during spin in @@ -237,7 +388,7 @@ void tick() { // increment the timer every frame during gameplay s_gameplay_timer += 1; } - if (s_is_postgoal == true && s_STAGE_FADE_OUT_TIMEr <= STAGE_FADE_OUT_TIME) { + if (s_is_postgoal == true && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { // increment the timer every frame after game goal init happens; once you press stage // select, a separate 49 frame timer is started (fade out from stage select to the first // completely white frame takes 49 frames). once the timer hits 49 frames, stop @@ -269,7 +420,7 @@ void tick() { } for (s32 k = 1; k < 11; k++) { - if (s_is_on_world[k] == true) { + if (mkb::scen_info.world == k - 1) { // need to add 2 frames to the timer at the start of each world s_world_start_timer_correction = 2 * k; } @@ -304,6 +455,7 @@ void tick() { s_is_between_worlds = false; } + /* // code for handling loadless split and segment times for (s32 k = 1; k < 11; k++) { // if you enter the first stage of the next world but then stage select, do not restart the @@ -332,22 +484,23 @@ void tick() { // fullgame loadless time upon breaking the tape on the last stage of world k s_split[k] = s_segment_start_time[k] + s_segment_timer[k]; - - if (((10 * (k - 1) + 1) <= s_completed_stages) && (s_completed_stages <= (10 * k - 1))) { - s_is_on_world[k] = true; - } else if (s_completed_stages == 10 * (k - 1) && - (s_is_on_stage_select_screen == true || s_is_on_spin_in == true || - s_is_on_gameplay == true)) { - // if you've completed 10*(k-1) stages, are in world k, but haven't completed the first - // stage yet, then you are not in world k-1 - s_is_on_world[k - 1] = false; - s_is_on_world[k] = true; - } else if (s_completed_stages == 10 * k && s_is_postgoal == true && - mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT && - mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN) { - s_is_on_world[k] = true; - } + */ + /* + if (((10 * (k - 1) + 1) <= s_completed_stages) && (s_completed_stages <= (10 * k - 1))) { + s_is_on_world[k] = true; + } else if (s_completed_stages == 10 * (k - 1) && + (s_is_on_stage_select_screen == true || s_is_on_spin_in == true || + s_is_on_gameplay == true)) { + // if you've completed 10*(k-1) stages, are in world k, but haven't completed the first + // stage yet, then you are not in world k-1 + s_is_on_world[k - 1] = false; + s_is_on_world[k] = true; + } else if (s_completed_stages == 10 * k && s_is_postgoal == true && + mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT && + mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN) { + s_is_on_world[k] = true; } + */ } void disp() { @@ -406,7 +559,7 @@ void disp() { switch (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { case TimerOptions::AlwaysShow: for (s32 k = 1; k < 11; k++) { - if (s_is_on_world[k] == true && s_is_run_complete == false) { + if (mkb::scen_info.world == k - 1 && s_is_run_complete == false) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); @@ -415,7 +568,7 @@ void disp() { break; case TimerOptions::BetweenWorlds: for (s32 k = 1; k < 11; k++) { - if (s_is_between_worlds == true && s_is_on_world[k] == true && k != 10) { + if (s_is_between_worlds == true && mkb::scen_info.world == k - 1 && k != 10) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); @@ -525,13 +678,12 @@ void disp() { */ if (TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == TimerOptions::AlwaysShow) { - timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(60 * s_completed_stages), 1, - false, true, draw::WHITE); + timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(s_timer_group[0].segment), 1, + false, false, draw::WHITE); timerdisp::draw_timer(380, 1, 44, - "dbg:", static_cast(60 * mkb::get_world_unbeaten_stage_count(0)), + "dbg:", static_cast(60 * mkb::get_world_unbeaten_stage_count(1)), 1, false, true, draw::WHITE); - timerdisp::draw_timer(380, 2, 44, - "dbg:", static_cast(60 * mkb::mode_info.g_selected_world_idx), 1, + timerdisp::draw_timer(380, 2, 44, "dbg:", static_cast(60 * mkb::scen_info.world), 1, false, true, draw::WHITE); } // mkb::scen_info.world From 19d253c8c872465fd14aa2df7312610223a644b9 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 14 Nov 2023 17:09:59 -0600 Subject: [PATCH 19/45] another approach --- src/mods/storytimer.cpp | 204 ++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 90 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 4a387b5c..e25598ec 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -45,7 +45,7 @@ struct TimerGroup { u32 timeover; u32 last_stage_postgoal; }; -static TimerGroup s_timer_group[10]; +static TimerGroup s_timer_group; static bool s_in_story; static bool s_is_on_world[11]; static bool s_is_between_worlds; @@ -102,7 +102,7 @@ void tick() { // screen, lower the counter by exactly 1 if (s_can_lower_stage_counter && mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { s_completed_stages += -1; - s_completed_stages_world[k] += 1; + s_completed_stages_world[k] += -1; s_can_lower_stage_counter = false; } @@ -253,10 +253,13 @@ void tick() { s_prev_completed_stage_count = 0; s_start_STAGE_FADE_OUT_TIMEr = false; s_stage_fade_out_timer = 0; + s_timer_group = {}; + /* for (s32 k = 0; k < 10; k++) { s_timer_group[k] = {}; s_completed_stages_world[k] = 0; } + */ /* for (s32 k = 1; k < 11; k++) { // on the file select screen, set these to false just in case you reset while on world k @@ -267,93 +270,112 @@ void tick() { } if (s_in_story == true) { - for (s32 k = 0; k < 10; k++) { - if (mkb::scen_info.world == k) { - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - // need to add 1 additional frame to the timer during spin in - // putting this code before the code below for s_loadless_story_timer makes the - // timer tick up more naturally when transitioning from the 10 ball screen to - // spin in, more specifically, this prevents the timer from skipping ahead for a - // few frames, then pausing for a few frames to even itself out (I don't - // understand why that happens) - s_timer_group[k].spin_in_correction += 1; - } + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { + // need to add 1 additional frame to the timer during spin in + // putting this code before the code below for s_loadless_story_timer makes the + // timer tick up more naturally when transitioning from the 10 ball screen to + // spin in, more specifically, this prevents the timer from skipping ahead for a + // few frames, then pausing for a few frames to even itself out (I don't + // understand why that happens) + s_timer_group.spin_in_correction += 1; + } - // last 3 terms are correction terms to account for missing frames - s_timer_group[k].full_world = - s_timer_group[k].spin_in + s_timer_group[k].spin_in_correction + - s_timer_group[k].gameplay + s_timer_group[k].postgoal + - s_timer_group[k].stage_select + - s_timer_group[k].game_scenario_return_correction + s_timer_group[k].exit_game + - s_timer_group[k].fallout + s_timer_group[k].timeover + - s_timer_group[k].world_start_correction + s_timer_group[k].last_stage_postgoal; - - if (s_completed_stages_world[k] <= 8 || - (s_completed_stages_world[k] == 9 && !is_postgoal)) { - s_timer_group[k].segment = s_timer_group[k].full_world; - } else if (s_completed_stages_world[k] == 9 && - mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { - s_timer_group[k].segment += -2; - } + // last 3 terms are correction terms to account for missing frames + s_loadless_story_timer = + s_timer_group.spin_in + s_timer_group.spin_in_correction + s_timer_group.gameplay + + s_timer_group.postgoal + s_timer_group.stage_select + + s_timer_group.game_scenario_return_correction + s_timer_group.exit_game + + s_timer_group.fallout + s_timer_group.timeover + s_timer_group.world_start_correction; - if (is_on_spin_in) { - // increment the timer every frame during spin in - s_timer_group[k].spin_in += 1; - } - if (is_on_gameplay) { - // increment the timer every frame during gameplay - s_timer_group[k].gameplay += 1; - } - if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { - // increment the timer every frame after game goal init happens; once you press - // stage select, a separate 49 frame timer is started (fade out from stage - // select to the first completely white frame takes 49 frames). once the timer - // hits 49 frames, stop incrementing the timer until the 10 ball screen starts - // spinning in - if (mkb::get_world_unbeaten_stage_count(k) <= 8) { - s_timer_group[k].postgoal += 1; - } else if (mkb::get_world_unbeaten_stage_count(k) == 9) { - s_timer_group[k].last_stage_postgoal += 1; - } - } - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || - mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { - // increment the timer every frame on the story mode select screen until the a - // press input; we do not include the transition time after pressing a - // afterwards - // even ignoring completely white frames, the time spent on - // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly - // variable (up to over 40 frames sometimes!), so for the purpose of a loadless - // timer, it makes sense to cut this out from the timer - s_timer_group[k].stage_select += 1; - } - if (is_on_exit_game) { - // increment the timer every frame on the exit game screen - s_timer_group[k].exit_game += 1; - } - if (is_on_fallout) { - // increment the timer every frame during the fallout sequence and y/n screen - s_timer_group[k].fallout += 1; - } - if (is_timeover) { - // increment the timer every frame during the timeover sequence - s_timer_group[k].timeover += 1; - } + /* + if (s_completed_stages_world[k] <= 8 || + (s_completed_stages_world[k] == 9 && !is_postgoal)) { + s_timer_group[k].segment = s_timer_group[k].full_world; + } else if (s_completed_stages_world[k] == 9 && + mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { + s_timer_group[k].segment += -2; + } + */ - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && - s_completed_stages % 10 != 0) { - // need to add 2 frames to the timer when stage selecting to the 10 ball screen, - // but don't correct if on the last stage of a world since the next frame the - // timer should increment on is covered by s_world_start_timer_correction - s_game_scenario_return_timer_correction += 2; - } + if (is_on_spin_in) { + // increment the timer every frame during spin in + s_timer_group.spin_in += 1; + } + if (is_on_gameplay) { + // increment the timer every frame during gameplay + s_timer_group.gameplay += 1; + } + if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { + // increment the timer every frame after game goal init happens; once you press + // stage select, a separate 49 frame timer is started (fade out from stage + // select to the first completely white frame takes 49 frames). once the timer + // hits 49 frames, stop incrementing the timer until the 10 ball screen starts + // spinning in + /* + if (mkb::get_world_unbeaten_stage_count(k) <= 8) { + s_timer_group[k].postgoal += 1; + } else if (mkb::get_world_unbeaten_stage_count(k) == 9) { + s_timer_group[k].last_stage_postgoal += 1; + } + */ + s_timer_group.postgoal += 1; + } + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || + mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { + // increment the timer every frame on the story mode select screen until the a + // press input; we do not include the transition time after pressing a + // afterwards + // even ignoring completely white frames, the time spent on + // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly + // variable (up to over 40 frames sometimes!), so for the purpose of a loadless + // timer, it makes sense to cut this out from the timer + s_timer_group.stage_select += 1; + } + if (is_on_exit_game) { + // increment the timer every frame on the exit game screen + s_timer_group.exit_game += 1; + } + if (is_on_fallout) { + // increment the timer every frame during the fallout sequence and y/n screen + s_timer_group.fallout += 1; + } + if (is_timeover) { + // increment the timer every frame during the timeover sequence + s_timer_group.timeover += 1; + } + + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % 10 != 0) { + // need to add 2 frames to the timer when stage selecting to the 10 ball screen, + // but don't correct if on the last stage of a world since the next frame the + // timer should increment on is covered by s_world_start_timer_correction + s_game_scenario_return_timer_correction += 2; + } - // this only gets set to 2 when you enter world k - s_timer_group[k].world_start_correction = 2; + // this only gets set to 2 when you enter world k + // s_timer_group[k].world_start_correction = 2; + for (s32 k = 0; k < 9; k++) { + if (mkb::scen_info.world == k) { + s_timer_group.world_start_correction = 2 * (k + 1); } } } + + s_segment_start_time[0] = 0; + for (s32 k = 0; k < 9; k++) { + if (k != 0 && mkb::scen_info.world == k - 1 && + mkb::get_world_unbeaten_stage_count(k - 1) == 9 && + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + s_segment_start_time[k] = s_loadless_story_timer; + } + if (s_completed_stages_world[k] <= 8 || + (s_completed_stages_world[k] == 9 && !is_postgoal)) { + s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k]; + } else if (s_completed_stages_world[k] == 9 && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && + !paused_now) { + s_segment_timer[k] += -2; + } + } /* // the fullgame timer is the sum of the segment timers; however, since the segment timers // stop on tape break on the last stage of a world, we need to include this time for all worlds @@ -363,7 +385,7 @@ void tick() { s_timer_group[9].segment; } */ - + /* if (s_in_story == true) { if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { // need to add 1 additional frame to the timer during spin in @@ -433,6 +455,7 @@ void tick() { s_game_scenario_return_timer_correction += 2; } } + */ if (s_completed_stages == 100) { s_is_run_complete = true; @@ -558,8 +581,8 @@ void disp() { switch (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { case TimerOptions::AlwaysShow: - for (s32 k = 1; k < 11; k++) { - if (mkb::scen_info.world == k - 1 && s_is_run_complete == false) { + for (s32 k = 0; k < 10; k++) { + if (mkb::scen_info.world == k && s_is_run_complete == false) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); @@ -567,8 +590,8 @@ void disp() { } break; case TimerOptions::BetweenWorlds: - for (s32 k = 1; k < 11; k++) { - if (s_is_between_worlds == true && mkb::scen_info.world == k - 1 && k != 10) { + for (s32 k = 0; k < 10; k++) { + if (s_is_between_worlds == true && mkb::scen_info.world == k && k != 9) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); @@ -665,7 +688,8 @@ void disp() { */ } - if (pad::button_pressed(mkb::PAD_BUTTON_A) == true) { + if (mkb::scen_info.world == 0 && mkb::get_world_unbeaten_stage_count(0) == 9 && + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { s_dummy_2 = 1; } else { s_dummy_2 = 0; @@ -678,10 +702,10 @@ void disp() { */ if (TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == TimerOptions::AlwaysShow) { - timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(s_timer_group[0].segment), 1, + timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(s_completed_stages_world[0]), 1, false, false, draw::WHITE); timerdisp::draw_timer(380, 1, 44, - "dbg:", static_cast(60 * mkb::get_world_unbeaten_stage_count(1)), + "dbg:", static_cast(60 * mkb::get_world_unbeaten_stage_count(0)), 1, false, true, draw::WHITE); timerdisp::draw_timer(380, 2, 44, "dbg:", static_cast(60 * mkb::scen_info.world), 1, false, true, draw::WHITE); From eca1c36d5cfc1fbc5d98cc18cd9a674c37ed6372 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 14 Nov 2023 20:52:13 -0600 Subject: [PATCH 20/45] fixed some issues with the rewrite --- src/mods/storytimer.cpp | 210 ++++++++---------- ...storytimer.cpp\357\200\272Zone.Identifier" | 3 + 2 files changed, 95 insertions(+), 118 deletions(-) create mode 100644 "src/mods/storytimer.cpp\357\200\272Zone.Identifier" diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index e25598ec..39e6b536 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -45,7 +45,7 @@ struct TimerGroup { u32 timeover; u32 last_stage_postgoal; }; -static TimerGroup s_timer_group; +static TimerGroup s_timer_group[10]; static bool s_in_story; static bool s_is_on_world[11]; static bool s_is_between_worlds; @@ -253,13 +253,10 @@ void tick() { s_prev_completed_stage_count = 0; s_start_STAGE_FADE_OUT_TIMEr = false; s_stage_fade_out_timer = 0; - s_timer_group = {}; - /* for (s32 k = 0; k < 10; k++) { s_timer_group[k] = {}; s_completed_stages_world[k] = 0; } - */ /* for (s32 k = 1; k < 11; k++) { // on the file select screen, set these to false just in case you reset while on world k @@ -270,122 +267,100 @@ void tick() { } if (s_in_story == true) { - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - // need to add 1 additional frame to the timer during spin in - // putting this code before the code below for s_loadless_story_timer makes the - // timer tick up more naturally when transitioning from the 10 ball screen to - // spin in, more specifically, this prevents the timer from skipping ahead for a - // few frames, then pausing for a few frames to even itself out (I don't - // understand why that happens) - s_timer_group.spin_in_correction += 1; - } - - // last 3 terms are correction terms to account for missing frames - s_loadless_story_timer = - s_timer_group.spin_in + s_timer_group.spin_in_correction + s_timer_group.gameplay + - s_timer_group.postgoal + s_timer_group.stage_select + - s_timer_group.game_scenario_return_correction + s_timer_group.exit_game + - s_timer_group.fallout + s_timer_group.timeover + s_timer_group.world_start_correction; + for (s32 k = 0; k < 10; k++) { + if (mkb::scen_info.world == k) { + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { + // need to add 1 additional frame to the timer during spin in + // putting this code before the code below for s_loadless_story_timer makes the + // timer tick up more naturally when transitioning from the 10 ball screen to + // spin in, more specifically, this prevents the timer from skipping ahead for a + // few frames, then pausing for a few frames to even itself out (I don't + // understand why that happens) + s_timer_group[k].spin_in_correction += 1; + } - /* - if (s_completed_stages_world[k] <= 8 || - (s_completed_stages_world[k] == 9 && !is_postgoal)) { - s_timer_group[k].segment = s_timer_group[k].full_world; - } else if (s_completed_stages_world[k] == 9 && - mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { - s_timer_group[k].segment += -2; - } - */ + // last 3 terms are correction terms to account for missing frames + s_timer_group[k].full_world = + s_timer_group[k].spin_in + s_timer_group[k].spin_in_correction + + s_timer_group[k].gameplay + s_timer_group[k].postgoal + + s_timer_group[k].stage_select + + s_timer_group[k].game_scenario_return_correction + s_timer_group[k].exit_game + + s_timer_group[k].fallout + s_timer_group[k].timeover + + s_timer_group[k].world_start_correction + s_timer_group[k].last_stage_postgoal; + + if (s_completed_stages_world[k] <= 8 || (s_completed_stages_world[k] == 9)) { + s_timer_group[k].segment = s_timer_group[k].full_world; + } else if (s_completed_stages_world[k] == 10 && + mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { + s_timer_group[k].segment += -2; + } - if (is_on_spin_in) { - // increment the timer every frame during spin in - s_timer_group.spin_in += 1; - } - if (is_on_gameplay) { - // increment the timer every frame during gameplay - s_timer_group.gameplay += 1; - } - if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { - // increment the timer every frame after game goal init happens; once you press - // stage select, a separate 49 frame timer is started (fade out from stage - // select to the first completely white frame takes 49 frames). once the timer - // hits 49 frames, stop incrementing the timer until the 10 ball screen starts - // spinning in - /* - if (mkb::get_world_unbeaten_stage_count(k) <= 8) { - s_timer_group[k].postgoal += 1; - } else if (mkb::get_world_unbeaten_stage_count(k) == 9) { - s_timer_group[k].last_stage_postgoal += 1; - } - */ - s_timer_group.postgoal += 1; - } - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || - mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { - // increment the timer every frame on the story mode select screen until the a - // press input; we do not include the transition time after pressing a - // afterwards - // even ignoring completely white frames, the time spent on - // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly - // variable (up to over 40 frames sometimes!), so for the purpose of a loadless - // timer, it makes sense to cut this out from the timer - s_timer_group.stage_select += 1; - } - if (is_on_exit_game) { - // increment the timer every frame on the exit game screen - s_timer_group.exit_game += 1; - } - if (is_on_fallout) { - // increment the timer every frame during the fallout sequence and y/n screen - s_timer_group.fallout += 1; - } - if (is_timeover) { - // increment the timer every frame during the timeover sequence - s_timer_group.timeover += 1; - } + if (is_on_spin_in) { + // increment the timer every frame during spin in + s_timer_group[k].spin_in += 1; + } + if (is_on_gameplay) { + // increment the timer every frame during gameplay + s_timer_group[k].gameplay += 1; + } + if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { + // increment the timer every frame after game goal init happens; once you press + // stage select, a separate 49 frame timer is started (fade out from stage + // select to the first completely white frame takes 49 frames). once the timer + // hits 49 frames, stop incrementing the timer until the 10 ball screen starts + // spinning in + if (mkb::get_world_unbeaten_stage_count(k) <= 8) { + s_timer_group[k].postgoal += 1; + } else if (mkb::get_world_unbeaten_stage_count(k) == 9) { + s_timer_group[k].last_stage_postgoal += 1; + } + } + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || + mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { + // increment the timer every frame on the story mode select screen until the a + // press input; we do not include the transition time after pressing a + // afterwards + // even ignoring completely white frames, the time spent on + // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly + // variable (up to over 40 frames sometimes!), so for the purpose of a loadless + // timer, it makes sense to cut this out from the timer + s_timer_group[k].stage_select += 1; + } + if (is_on_exit_game) { + // increment the timer every frame on the exit game screen + s_timer_group[k].exit_game += 1; + } + if (is_on_fallout) { + // increment the timer every frame during the fallout sequence and y/n screen + s_timer_group[k].fallout += 1; + } + if (is_timeover) { + // increment the timer every frame during the timeover sequence + s_timer_group[k].timeover += 1; + } - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % 10 != 0) { - // need to add 2 frames to the timer when stage selecting to the 10 ball screen, - // but don't correct if on the last stage of a world since the next frame the - // timer should increment on is covered by s_world_start_timer_correction - s_game_scenario_return_timer_correction += 2; - } + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && + s_completed_stages % 10 != 0) { + // need to add 2 frames to the timer when stage selecting to the 10 ball screen, + // but don't correct if on the last stage of a world since the next frame the + // timer should increment on is covered by s_world_start_timer_correction + s_timer_group[k].game_scenario_return_correction += 2; + } - // this only gets set to 2 when you enter world k - // s_timer_group[k].world_start_correction = 2; - for (s32 k = 0; k < 9; k++) { - if (mkb::scen_info.world == k) { - s_timer_group.world_start_correction = 2 * (k + 1); + // this only gets set to 2 when you enter world k + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + s_timer_group[k].world_start_correction = 2; + } } } } - - s_segment_start_time[0] = 0; - for (s32 k = 0; k < 9; k++) { - if (k != 0 && mkb::scen_info.world == k - 1 && - mkb::get_world_unbeaten_stage_count(k - 1) == 9 && - mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - s_segment_start_time[k] = s_loadless_story_timer; - } - if (s_completed_stages_world[k] <= 8 || - (s_completed_stages_world[k] == 9 && !is_postgoal)) { - s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k]; - } else if (s_completed_stages_world[k] == 9 && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && - !paused_now) { - s_segment_timer[k] += -2; - } - } /* - // the fullgame timer is the sum of the segment timers; however, since the segment timers - // stop on tape break on the last stage of a world, we need to include this time for all worlds - // except for world 10 for (s32 k = 0; k < 9; k++) { - s_loadless_story_timer = s_loadless_story_timer + s_timer_group[k].full_world + - s_timer_group[9].segment; + s_loadless_story_timer += + s_timer_group[k].full_world + s_timer_group[9].segment; } */ - /* + if (s_in_story == true) { if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { // need to add 1 additional frame to the timer during spin in @@ -455,7 +430,6 @@ void tick() { s_game_scenario_return_timer_correction += 2; } } - */ if (s_completed_stages == 100) { s_is_run_complete = true; @@ -581,8 +555,8 @@ void disp() { switch (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { case TimerOptions::AlwaysShow: - for (s32 k = 0; k < 10; k++) { - if (mkb::scen_info.world == k && s_is_run_complete == false) { + for (s32 k = 1; k < 11; k++) { + if (mkb::scen_info.world == k - 1 && s_is_run_complete == false) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); @@ -590,8 +564,8 @@ void disp() { } break; case TimerOptions::BetweenWorlds: - for (s32 k = 0; k < 10; k++) { - if (s_is_between_worlds == true && mkb::scen_info.world == k && k != 9) { + for (s32 k = 1; k < 11; k++) { + if (s_is_between_worlds == true && mkb::scen_info.world == k - 1 && k != 10) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, false, false, draw::WHITE); @@ -688,8 +662,7 @@ void disp() { */ } - if (mkb::scen_info.world == 0 && mkb::get_world_unbeaten_stage_count(0) == 9 && - mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + if (pad::button_pressed(mkb::PAD_BUTTON_A) == true) { s_dummy_2 = 1; } else { s_dummy_2 = 0; @@ -702,16 +675,17 @@ void disp() { */ if (TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == TimerOptions::AlwaysShow) { - timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(s_completed_stages_world[0]), 1, + timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(s_timer_group[0].segment), 1, false, false, draw::WHITE); timerdisp::draw_timer(380, 1, 44, - "dbg:", static_cast(60 * mkb::get_world_unbeaten_stage_count(0)), + "dbg:", static_cast(60 * mkb::get_world_unbeaten_stage_count(1)), 1, false, true, draw::WHITE); timerdisp::draw_timer(380, 2, 44, "dbg:", static_cast(60 * mkb::scen_info.world), 1, false, true, draw::WHITE); } // mkb::scen_info.world // 10*mkb::scen_info.world+mkb::get_world_unbeaten_stage_count(mkb::scen_info.world) + // mkb::scen_info.next_world == 10 } } // namespace storytimer diff --git "a/src/mods/storytimer.cpp\357\200\272Zone.Identifier" "b/src/mods/storytimer.cpp\357\200\272Zone.Identifier" new file mode 100644 index 00000000..2d45b2b2 --- /dev/null +++ "b/src/mods/storytimer.cpp\357\200\272Zone.Identifier" @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +HostUrl=about:internet From b5eeeff0643e1d6b387a5903e9700d9530382d57 Mon Sep 17 00:00:00 2001 From: eddynya Date: Wed, 15 Nov 2023 22:41:31 -0600 Subject: [PATCH 21/45] pre cleanup backup --- src/mods/storytimer.cpp | 438 ++++++++++++++-------------------------- 1 file changed, 152 insertions(+), 286 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 39e6b536..527bb4ff 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -19,16 +19,6 @@ enum class TimerOptions { EndOfRun = 3, }; -static u32 s_spin_in_timer; -static u32 s_gameplay_timer; -static u32 s_postgoal_timer; -static u32 s_stage_select_timer; -static u32 s_exit_game_timer; -static u32 s_fallout_timer; -static u32 s_timeover_timer; -static u32 s_spin_in_timer_correction; -static u32 s_game_scenario_return_timer_correction; -static u32 s_world_start_timer_correction; static u32 s_loadless_story_timer; struct TimerGroup { u32 segment; @@ -47,28 +37,20 @@ struct TimerGroup { }; static TimerGroup s_timer_group[10]; static bool s_in_story; -static bool s_is_on_world[11]; static bool s_is_between_worlds; static bool s_is_run_complete; -static bool s_is_on_spin_in; -static bool s_is_on_gameplay; -static bool s_is_postgoal; -static bool s_is_on_stage_select_screen; -static bool s_is_on_exit_game_screen; -static bool s_is_on_fallout_screen; -static bool s_is_timeover; static bool s_can_lower_stage_counter; -static bool s_start_STAGE_FADE_OUT_TIMEr; +static bool s_start_stage_fade_out_timer; static u32 s_stage_fade_out_timer; static u32 s_prev_completed_stage_count; static s32 s_completed_stages; static s32 s_completed_stages_world[10]; -static u32 s_segment_timer[11]; // IW timer for world k -static u32 s_split[11]; // s_split[k] is the loadless time on tape break of the 10th stage of world +static u32 s_segment_timer[10]; // IW timer for world k +static u32 s_split[10]; // s_split[k] is the loadless time on tape break of the 10th stage of world // k -static u32 s_segment_start_time[11]; // the loadless time at the start of world k, used to +static u32 s_segment_start_time[10]; // the loadless time at the start of world k, used to // calculate s_segment_timer[k] -static bool s_can_change_segment_start_time[11]; +static bool s_can_change_segment_start_time[10]; static bool s_display_story_timer; static bool s_display_segment_timer; static u32 s_fullgame_timer_location_y; @@ -86,6 +68,24 @@ static u32 s_dummy_2; static u32 s_dummy_3; void tick() { + // before starting the run, there are several values we zero on the file select screen (this + // serves to reset the timer) to do: in the future, have the timer not reset unless the file's + // data is reset (either manually or by using the IW move up/down feature) + + if (mkb::scen_info.mode == 5 || mkb::scen_info.mode == 21) { + // zero the timer on the file select screen & name entry screen, and set the number of + // completed stages to 0 + s_can_lower_stage_counter = false; + s_loadless_story_timer = 0; + s_completed_stages = 0; + s_start_stage_fade_out_timer = false; + s_stage_fade_out_timer = 0; + for (s32 k = 0; k < 10; k++) { + s_timer_group[k] = {}; + s_completed_stages_world[k] = 0; + } + } + bool paused_now = *reinterpret_cast(0x805BC474) & 8; // for later use, it's useful to record how many stages we've completed // increment the completed stages by 1 during the init @@ -93,7 +93,6 @@ void tick() { for (s32 k = 0; k < 10; k++) { if (mkb::scen_info.world == k) { if (!paused_now && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { - s_completed_stages += 1; s_completed_stages_world[k] += 1; s_can_lower_stage_counter = true; } @@ -101,7 +100,6 @@ void tick() { // if you retry after SMD_GAME_GOAL_INIT but before returning to the stage select // screen, lower the counter by exactly 1 if (s_can_lower_stage_counter && mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { - s_completed_stages += -1; s_completed_stages_world[k] += -1; s_can_lower_stage_counter = false; } @@ -112,6 +110,7 @@ void tick() { s_can_lower_stage_counter = false; } } + s_completed_stages += s_completed_stages_world[k]; } // for later, it's useful to record what submodes correspond to spin in, gameplay, etc. @@ -130,10 +129,8 @@ void tick() { // submodes during spin in if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_READY_MAIN) { - s_is_on_spin_in = true; is_on_spin_in = true; } else { - s_is_on_spin_in = false; is_on_spin_in = false; } @@ -144,19 +141,15 @@ void tick() { mkb::g_storymode_stageselect_state == 5 || mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { // 3, 5 unlabelled inits - s_is_on_stage_select_screen = true; is_on_stage_select = true; } else { - s_is_on_stage_select_screen = false; is_on_stage_select = false; } // submodes during gameplay if (mkb::sub_mode == mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { - s_is_on_gameplay = true; is_on_gameplay = true; } else { - s_is_on_gameplay = false; is_on_gameplay = false; } @@ -165,10 +158,8 @@ void tick() { mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_MAIN || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_INIT || mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_MAIN) { - s_is_on_exit_game_screen = true; is_on_exit_game = true; } else { - s_is_on_exit_game_screen = false; is_on_exit_game = false; } @@ -177,10 +168,8 @@ void tick() { mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_INIT || mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_MAIN || mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - s_is_postgoal = true; is_postgoal = true; } else { - s_is_postgoal = false; is_postgoal = false; } @@ -188,85 +177,43 @@ void tick() { if (mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_MAIN || mkb::sub_mode == mkb::SMD_GAME_RETRY_INIT || mkb::sub_mode == mkb::SMD_GAME_RETRY_MAIN) { - s_is_on_fallout_screen = true; is_on_fallout = true; } else { - s_is_on_fallout_screen = false; is_on_fallout = false; } // submodes during timeover if (mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN) { - s_is_timeover = true; is_timeover = true; } else { - s_is_timeover = false; is_timeover = false; } - if ((mkb::main_mode == mkb::MD_GAME && mkb::main_game_mode == mkb::STORY_MODE) || - mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { - s_in_story = true; + if (mkb::main_game_mode == mkb::STORY_MODE || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || + mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { in_story = true; } else { - s_in_story = false; in_story = false; } // this code is used to halt the timer once the screen becomes completely white when stage // selecting out of a level if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && - mkb::g_current_focused_pause_menu_entry == 4 && - pad::button_pressed(mkb::PAD_BUTTON_A) == true && s_is_postgoal == true) { + mkb::g_current_focused_pause_menu_entry == 4 && pad::button_pressed(mkb::PAD_BUTTON_A) && + is_postgoal) { // stage select is on line 4 of the pause menu (top line is line 0) - s_start_STAGE_FADE_OUT_TIMEr = true; + s_start_stage_fade_out_timer = true; } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_start_STAGE_FADE_OUT_TIMEr = false; + s_start_stage_fade_out_timer = false; } - if (s_start_STAGE_FADE_OUT_TIMEr == true) { + if (s_start_stage_fade_out_timer) { s_stage_fade_out_timer += 1; } else { s_stage_fade_out_timer = 0; } - // before starting the run, there are several values we zero on the file select screen (this - // serves to reset the timer) to do: in the future, have the timer not reset unless the file's - // data is reset (either manually or by using the IW move up/down feature) - - if (mkb::scen_info.mode == 5 || mkb::scen_info.mode == 21) { - // zero the timer on the file select screen & name entry screen, and set the number of - // completed stages to 0 - s_spin_in_timer_correction = 0; - s_spin_in_timer = 0; - s_gameplay_timer = 0; - s_postgoal_timer = 0; - s_stage_select_timer = 0; - s_world_start_timer_correction = 0; - s_game_scenario_return_timer_correction = 0; - s_exit_game_timer = 0; - s_fallout_timer = 0; - s_timeover_timer = 0; - s_can_lower_stage_counter = false; - s_loadless_story_timer = 0; - s_completed_stages = 0; - s_prev_completed_stage_count = 0; - s_start_STAGE_FADE_OUT_TIMEr = false; - s_stage_fade_out_timer = 0; - for (s32 k = 0; k < 10; k++) { - s_timer_group[k] = {}; - s_completed_stages_world[k] = 0; - } - /* - for (s32 k = 1; k < 11; k++) { - // on the file select screen, set these to false just in case you reset while on world k - // but did not complete 10k stages - s_is_on_world[k] = false; - } - */ - } - - if (s_in_story == true) { + if (in_story == true) { for (s32 k = 0; k < 10; k++) { if (mkb::scen_info.world == k) { if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { @@ -279,7 +226,6 @@ void tick() { s_timer_group[k].spin_in_correction += 1; } - // last 3 terms are correction terms to account for missing frames s_timer_group[k].full_world = s_timer_group[k].spin_in + s_timer_group[k].spin_in_correction + s_timer_group[k].gameplay + s_timer_group[k].postgoal + @@ -288,7 +234,7 @@ void tick() { s_timer_group[k].fallout + s_timer_group[k].timeover + s_timer_group[k].world_start_correction + s_timer_group[k].last_stage_postgoal; - if (s_completed_stages_world[k] <= 8 || (s_completed_stages_world[k] == 9)) { + if (s_completed_stages_world[k] <= 9) { s_timer_group[k].segment = s_timer_group[k].full_world; } else if (s_completed_stages_world[k] == 10 && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { @@ -355,220 +301,139 @@ void tick() { } } } + // s_split[k] is just the fullgame time at tape break on the last stage of world k; to calculate + // that, we just add the corresponding world timers + u32 sum[10] = {}; + for (s32 k = 1; k < 10; k++) { + for (s32 j = 0; j < k; j++) { + sum[k] += s_timer_group[j].full_world; + } + s_split[k] = sum[k] + s_timer_group[k].segment; + } + s_split[0] = s_timer_group[0].segment; + s_loadless_story_timer = s_split[9]; + /* + u32 sum = 0; for (s32 k = 0; k < 9; k++) { - s_loadless_story_timer += + s_timer_group[k].full_world + s_timer_group[9].segment; + sum += s_timer_group[k].full_world; // doesn't work :( + for (s32 j = 0; j < k; j++) { + s_split[k] += s_timer_group[j].full_world + s_timer_group[k].segment; + } } + s_loadless_story_timer = sum + s_timer_group[9].segment; */ - if (s_in_story == true) { - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - // need to add 1 additional frame to the timer during spin in - // putting this code before the code below for s_loadless_story_timer makes the timer - // tick up more naturally when transitioning from the 10 ball screen to spin in, more - // specifically, this prevents the timer from skipping ahead for a few frames, then - // pausing for a few frames to even itself out (I don't understand why that happens) - s_spin_in_timer_correction += 1; - } - - // last 3 terms are correction terms to account for missing frames - s_loadless_story_timer = - s_spin_in_timer + s_gameplay_timer + s_postgoal_timer + s_stage_select_timer + - s_exit_game_timer + s_fallout_timer + s_timeover_timer + +s_spin_in_timer_correction + - s_game_scenario_return_timer_correction + s_world_start_timer_correction; - - if (s_is_on_spin_in == true) { - // increment the timer every frame during spin in - s_spin_in_timer += 1; - } - if (s_is_on_gameplay == true) { - // increment the timer every frame during gameplay - s_gameplay_timer += 1; - } - if (s_is_postgoal == true && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { - // increment the timer every frame after game goal init happens; once you press stage - // select, a separate 49 frame timer is started (fade out from stage select to the first - // completely white frame takes 49 frames). once the timer hits 49 frames, stop - // incrementing the timer until the 10 ball screen starts spinning in - s_postgoal_timer += 1; - } - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || - mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { - // increment the timer every frame on the story mode select screen until the a press - // input; we do not include the transition time after pressing a afterwards - // even ignoring completely white frames, the time spent on - // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly variable (up - // to over 40 frames sometimes!), so for the purpose of a loadless timer, it makes - // sense to cut this out from the timer - s_stage_select_timer += 1; - } - if (s_is_on_exit_game_screen == true) { - // increment the timer every frame on the exit game screen - s_exit_game_timer += 1; - } - if (s_is_on_fallout_screen == true) { - // increment the timer every frame during the fallout sequence and y/n screen - s_fallout_timer += 1; - } - if (s_is_timeover == true) { - // increment the timer every frame during the timeover sequence - s_timeover_timer += 1; - } - - for (s32 k = 1; k < 11; k++) { - if (mkb::scen_info.world == k - 1) { - // need to add 2 frames to the timer at the start of each world - s_world_start_timer_correction = 2 * k; - } - } - - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % 10 != 0) { - // need to add 2 frames to the timer when stage selecting to the 10 ball screen, but - // don't correct if on the last stage of a world since the next frame the timer should - // increment on is covered by s_world_start_timer_correction - s_game_scenario_return_timer_correction += 2; - } - } + /* + s_loadless_story_timer = s_timer_group[0].full_world + s_timer_group[1].full_world + + s_timer_group[2].full_world + s_timer_group[3].full_world + + s_timer_group[4].full_world + s_timer_group[5].full_world + + s_timer_group[6].full_world + s_timer_group[7].full_world + + s_timer_group[8].full_world + s_timer_group[9].segment; + */ - if (s_completed_stages == 100) { - s_is_run_complete = true; - // s_segment_timer[k] is already corrected for tape break (see code below), so no further - // corrections needed to get an accurate time - s_loadless_story_timer = s_segment_start_time[10] + s_segment_timer[10]; - } else { - s_is_run_complete = false; - } + // s_loadless_story_timer = s_split[9]; // it is useful to know when we are between worlds (for the "between worlds" option in the menu) + /* + bool is_between_worlds = 0; if ((s_completed_stages % 10 == 0) && s_completed_stages != 0 && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { s_is_between_worlds = true; + is_between_worlds = true; } else if ((s_completed_stages % 10 == 0 && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) || s_completed_stages % 10 != 0) { // no longer "between worlds" if you enter the next worlds 10 ball screen, or if you break // the tape on the last stage of the current world, but retry s_is_between_worlds = false; - } - - /* - // code for handling loadless split and segment times - for (s32 k = 1; k < 11; k++) { - // if you enter the first stage of the next world but then stage select, do not restart the - // segment timer - if (s_completed_stages == 10 * (k - 1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { - s_can_change_segment_start_time[k] = true; - } else if (s_completed_stages == 10 * (k - 1) && - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_can_change_segment_start_time[k] = false; - } - - if (s_completed_stages == 10 * (k - 1) && mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && - s_can_change_segment_start_time[k] == true) { - s_segment_start_time[k] = s_loadless_story_timer; - } - - if (((10 * (k - 1) <= s_completed_stages) && (s_completed_stages <= (10 * k - 2))) || - (s_completed_stages == (10 * k - 1) && mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT)) { - s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k]; - } else if (s_completed_stages == (10 * k - 1) && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { - // I don't know a better way of doing this to make the timer show the time at tape break - // if we show the segment timer at all times, since the timer will run for 2 frames - // after breaking the tape - s_segment_timer[k] = s_loadless_story_timer - s_segment_start_time[k] - 3; - } - - // fullgame loadless time upon breaking the tape on the last stage of world k - s_split[k] = s_segment_start_time[k] + s_segment_timer[k]; - */ - /* - if (((10 * (k - 1) + 1) <= s_completed_stages) && (s_completed_stages <= (10 * k - 1))) { - s_is_on_world[k] = true; - } else if (s_completed_stages == 10 * (k - 1) && - (s_is_on_stage_select_screen == true || s_is_on_spin_in == true || - s_is_on_gameplay == true)) { - // if you've completed 10*(k-1) stages, are in world k, but haven't completed the first - // stage yet, then you are not in world k-1 - s_is_on_world[k - 1] = false; - s_is_on_world[k] = true; - } else if (s_completed_stages == 10 * k && s_is_postgoal == true && - mkb::sub_mode != mkb::SMD_GAME_GOAL_INIT && - mkb::sub_mode != mkb::SMD_GAME_SCENARIO_RETURN) { - s_is_on_world[k] = true; + is_between_worlds = false; } */ } void disp() { - if (s_in_story == false || freecam::should_hide_hud()) { + if ((mkb::main_game_mode != mkb::STORY_MODE && mkb::sub_mode != mkb::SMD_AUTHOR_PLAY_INIT && + mkb::sub_mode != mkb::SMD_AUTHOR_PLAY_MAIN) || + freecam::should_hide_hud()) { return; } - // move the positions of the fullgame and segment timers if the death counter is on - if (pref::get(pref::BoolPref::ShowDeathCounter) == true) { - s_fullgame_timer_location_y = 3; - } else { - s_fullgame_timer_location_y = 2; + bool is_between_worlds = 0; + if ((s_completed_stages % 10 == 0) && s_completed_stages != 0 && + mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { + is_between_worlds = true; + } else if ((s_completed_stages % 10 == 0 && + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) || + s_completed_stages % 10 != 0) { + // no longer "between worlds" if you enter the next worlds 10 ball screen, or if you break + // the tape on the last stage of the current world, but retry + is_between_worlds = false; } - // if the fullgame timer and death counter is off but the segment timer is on, move the segment - // timer to the top line; if either the fullgame timer or death counter are on but not both are - // on, move it to the 2nd line, if all 3 are enabled, put it on the 3rd line - if (s_display_story_timer == false && pref::get(pref::BoolPref::ShowDeathCounter) == false) { - s_segment_timer_location_y = 2; - } else if (s_display_story_timer == false || - pref::get(pref::BoolPref::ShowDeathCounter) == false) { - s_segment_timer_location_y = 3; + bool is_run_complete = 0; + is_run_complete = (mkb::scen_info.world == 9 && s_completed_stages_world[9] == 10); + + // move the positions of the fullgame and segment timers if the death counter is on + u32 fullgame_timer_location_y = 2; + if (pref::get(pref::BoolPref::ShowDeathCounter)) { + fullgame_timer_location_y = 3; } else { - s_segment_timer_location_y = 4; + fullgame_timer_location_y = 2; } + bool display_story_timer = 0; switch (TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions))) { case TimerOptions::AlwaysShow: - s_display_story_timer = true; + display_story_timer = true; break; case TimerOptions::BetweenWorlds: - if (s_is_between_worlds == true) { - s_display_story_timer = true; - } else { - s_display_story_timer = false; - } + display_story_timer = is_between_worlds; break; case TimerOptions::EndOfRun: - if (s_is_run_complete == true) { - s_display_story_timer = true; - } else { - s_display_story_timer = false; - } + display_story_timer = is_run_complete; break; case TimerOptions::DontShow: - s_display_story_timer = false; + display_story_timer = false; break; } - if (s_display_story_timer == true) { - timerdisp::draw_timer(FULLGAME_TIMER_LOCATION_X, s_fullgame_timer_location_y, + // if the fullgame timer and death counter is off but the segment timer is on, move the segment + // timer to the top line; if either the fullgame timer or death counter are on but not both are + // on, move it to the 2nd line, if all 3 are enabled, put it on the 3rd line + u32 segment_timer_location_y = 2; + if (!display_story_timer && !pref::get(pref::BoolPref::ShowDeathCounter)) { + segment_timer_location_y = 2; + } else if (!display_story_timer || !pref::get(pref::BoolPref::ShowDeathCounter)) { + segment_timer_location_y = 3; + } else { + segment_timer_location_y = 4; + } + + if (display_story_timer) { + timerdisp::draw_timer(FULLGAME_TIMER_LOCATION_X, fullgame_timer_location_y, FULLGAME_TIMER_TEXT_OFFSET, "Time:", s_loadless_story_timer, 0, false, false, draw::WHITE); } switch (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { case TimerOptions::AlwaysShow: - for (s32 k = 1; k < 11; k++) { - if (mkb::scen_info.world == k - 1 && s_is_run_complete == false) { - timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, - SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, - false, false, draw::WHITE); + for (s32 k = 0; k < 10; k++) { + if (mkb::scen_info.world == k && !is_run_complete) { + timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y, + SEGMENT_TIMER_TEXT_OFFSET, + "Seg:", s_timer_group[k].segment, 0, false, false, + draw::WHITE); } } break; case TimerOptions::BetweenWorlds: - for (s32 k = 1; k < 11; k++) { - if (s_is_between_worlds == true && mkb::scen_info.world == k - 1 && k != 10) { - timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y, - SEGMENT_TIMER_TEXT_OFFSET, "Seg:", s_segment_timer[k], 0, - false, false, draw::WHITE); + for (s32 k = 0; k < 10; k++) { + if (is_between_worlds && mkb::scen_info.world == k && k != 9) { + timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y, + SEGMENT_TIMER_TEXT_OFFSET, + "Seg:", s_timer_group[k].segment, 0, false, false, + draw::WHITE); } } break; @@ -580,46 +445,46 @@ void disp() { // if the segment timer is enabled in any capacity, show all 10 split times + iw times after the // tape is broken on the last stage if (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != TimerOptions::DontShow) { - if (s_is_run_complete == true) { + if (s_completed_stages_world[9] == 10) { // I'm so sorry :( // I don't know how to get the text to show "Wk" where k ranges in a for loop - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y, - IW_TIME_TEXT_OFFSET, "W1:", s_split[1], s_segment_timer[1], true, - false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 1, - IW_TIME_TEXT_OFFSET, "W2:", s_split[2], s_segment_timer[2], true, - false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 2, - IW_TIME_TEXT_OFFSET, "W3:", s_split[3], s_segment_timer[3], true, - false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 3, - IW_TIME_TEXT_OFFSET, "W4:", s_split[4], s_segment_timer[4], true, - false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 4, - IW_TIME_TEXT_OFFSET, "W5:", s_split[5], s_segment_timer[5], true, - false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 5, - IW_TIME_TEXT_OFFSET, "W6:", s_split[6], s_segment_timer[6], true, - false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 6, - IW_TIME_TEXT_OFFSET, "W7:", s_split[7], s_segment_timer[7], true, - false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 7, - IW_TIME_TEXT_OFFSET, "W8:", s_split[8], s_segment_timer[8], true, - false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, s_segment_timer_location_y + 8, - IW_TIME_TEXT_OFFSET, "W9:", s_split[9], s_segment_timer[9], true, - false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y, IW_TIME_TEXT_OFFSET, + "W1:", s_split[0], s_timer_group[0].segment, true, false, + draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 1, + IW_TIME_TEXT_OFFSET, "W2:", s_split[1], s_timer_group[1].segment, + true, false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 2, + IW_TIME_TEXT_OFFSET, "W3:", s_split[2], s_timer_group[2].segment, + true, false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 3, + IW_TIME_TEXT_OFFSET, "W4:", s_split[3], s_timer_group[3].segment, + true, false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 4, + IW_TIME_TEXT_OFFSET, "W5:", s_split[4], s_timer_group[4].segment, + true, false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 5, + IW_TIME_TEXT_OFFSET, "W6:", s_split[5], s_timer_group[5].segment, + true, false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 6, + IW_TIME_TEXT_OFFSET, "W7:", s_split[6], s_timer_group[6].segment, + true, false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 7, + IW_TIME_TEXT_OFFSET, "W8:", s_split[7], s_timer_group[7].segment, + true, false, draw::WHITE); + timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 8, + IW_TIME_TEXT_OFFSET, "W9:", s_split[8], s_timer_group[8].segment, + true, false, draw::WHITE); // use segment timer spacing for w10 since "W10" is 3 characters long, not 2 - timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, s_segment_timer_location_y + 9, - SEGMENT_TIMER_TEXT_OFFSET, "W10:", s_split[10], - s_segment_timer[10], true, false, draw::WHITE); + timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y + 9, + SEGMENT_TIMER_TEXT_OFFSET, "W10:", s_split[9], + s_timer_group[9].segment, true, false, draw::WHITE); } } // show warning on the name entry screen if no timers are on (if the toggle for the warning is // turned on) - if (pref::get(pref::BoolPref::StoryTimerWarning) == true && + if (pref::get(pref::BoolPref::StoryTimerWarning) && TimerOptions(pref::get(pref::U8Pref::FullgameTimerOptions)) == TimerOptions::DontShow && TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) == TimerOptions::DontShow && mkb::scen_info.mode == 21) { @@ -678,10 +543,11 @@ void disp() { timerdisp::draw_timer(380, 0, 44, "dbg:", static_cast(s_timer_group[0].segment), 1, false, false, draw::WHITE); timerdisp::draw_timer(380, 1, 44, - "dbg:", static_cast(60 * mkb::get_world_unbeaten_stage_count(1)), - 1, false, true, draw::WHITE); - timerdisp::draw_timer(380, 2, 44, "dbg:", static_cast(60 * mkb::scen_info.world), 1, - false, true, draw::WHITE); + "dbg:", static_cast(60 * s_completed_stages_world[0]), 1, false, + true, draw::WHITE); + timerdisp::draw_timer(380, 2, 44, + "dbg:", static_cast(60 * s_completed_stages_world[1]), 1, false, + true, draw::WHITE); } // mkb::scen_info.world // 10*mkb::scen_info.world+mkb::get_world_unbeaten_stage_count(mkb::scen_info.world) From cb66e06e2c3a628fed97c54c9dd37b580d051784 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Wed, 15 Nov 2023 23:58:55 -0600 Subject: [PATCH 22/45] clean up arc 2 part 1 --- src/mods/storytimer.cpp | 494 ++++++++++++++-------------------------- 1 file changed, 165 insertions(+), 329 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 527bb4ff..036cc39e 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -21,8 +21,10 @@ enum class TimerOptions { static u32 s_loadless_story_timer; struct TimerGroup { - u32 segment; - u32 full_world; + u32 segment; // the time taken to complete a world up until tape break on the last stage + u32 full_world; // the time taken to complete a world until the fade to white on the last stage + u32 split; // the time from the start of the run until tape break of the last stage of the + // world u32 spin_in; u32 spin_in_correction; u32 gameplay; @@ -35,26 +37,13 @@ struct TimerGroup { u32 timeover; u32 last_stage_postgoal; }; -static TimerGroup s_timer_group[10]; -static bool s_in_story; -static bool s_is_between_worlds; -static bool s_is_run_complete; +static TimerGroup s_timer_group[10]; // each world has its own TimerGroup structure static bool s_can_lower_stage_counter; static bool s_start_stage_fade_out_timer; static u32 s_stage_fade_out_timer; -static u32 s_prev_completed_stage_count; -static s32 s_completed_stages; -static s32 s_completed_stages_world[10]; -static u32 s_segment_timer[10]; // IW timer for world k -static u32 s_split[10]; // s_split[k] is the loadless time on tape break of the 10th stage of world - // k -static u32 s_segment_start_time[10]; // the loadless time at the start of world k, used to - // calculate s_segment_timer[k] -static bool s_can_change_segment_start_time[10]; -static bool s_display_story_timer; +static s32 s_completed_stages; // the completed stages for the whole run +static s32 s_completed_stages_world[10]; // the completed stages in world k static bool s_display_segment_timer; -static u32 s_fullgame_timer_location_y; -static u32 s_segment_timer_location_y; static constexpr s32 FULLGAME_TIMER_LOCATION_X = 18 + 24; static constexpr s32 FULLGAME_TIMER_TEXT_OFFSET = 56; static constexpr s32 SEGMENT_TIMER_LOCATION_X = 30 + 24; @@ -63,18 +52,12 @@ static constexpr s32 IW_TIME_LOCATION_X = 42 + 24; static constexpr s32 IW_TIME_TEXT_OFFSET = 32; static constexpr s32 STAGE_FADE_OUT_TIME = 49; static constexpr u32 WORLD_START_CORRECTION = 2; -static u32 s_dummy; -static u32 s_dummy_2; -static u32 s_dummy_3; void tick() { - // before starting the run, there are several values we zero on the file select screen (this - // serves to reset the timer) to do: in the future, have the timer not reset unless the file's - // data is reset (either manually or by using the IW move up/down feature) - + // before starting the run, there are several values we zero on the file select and name entry + // screen (this serves to reset the timer) if (mkb::scen_info.mode == 5 || mkb::scen_info.mode == 21) { - // zero the timer on the file select screen & name entry screen, and set the number of - // completed stages to 0 + // 5 is the file select screen, 21 is the name entry screen s_can_lower_stage_counter = false; s_loadless_story_timer = 0; s_completed_stages = 0; @@ -117,85 +100,37 @@ void tick() { // splitting up the timer this way also makes it easier in the future if I decide to implement // features such as menuing timeloss - bool is_on_spin_in = 0; - bool is_on_stage_select = 0; - bool is_on_gameplay = 0; - bool is_on_exit_game = 0; - bool is_postgoal = 0; - bool is_on_fallout = 0; - bool is_timeover = 0; - bool in_story = 0; - // submodes during spin in - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode == mkb::SMD_GAME_READY_INIT || - mkb::sub_mode == mkb::SMD_GAME_READY_MAIN) { - is_on_spin_in = true; - } else { - is_on_spin_in = false; - } - - // story mode states entered during the story select screen - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || - mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE || - mkb::g_storymode_stageselect_state == 5 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED) { - // 3, 5 unlabelled inits - is_on_stage_select = true; - } else { - is_on_stage_select = false; - } + bool is_on_spin_in = + (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || mkb::sub_mode == mkb::SMD_GAME_READY_INIT || + mkb::sub_mode == mkb::SMD_GAME_READY_MAIN); // submodes during gameplay - if (mkb::sub_mode == mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { - is_on_gameplay = true; - } else { - is_on_gameplay = false; - } + bool is_on_gameplay = + (mkb::sub_mode == mkb::SMD_GAME_PLAY_INIT || mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN); // submodes entered when exiting game - if (mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT || - mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_MAIN || - mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_INIT || - mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_MAIN) { - is_on_exit_game = true; - } else { - is_on_exit_game = false; - } + bool is_on_exit_game = (mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT || + mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_MAIN || + mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_INIT || + mkb::sub_mode == mkb::SMD_GAME_SUGG_SAVE_MAIN); // submodes entered when breaking the goal tape - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN || - mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_INIT || - mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_MAIN || - mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - is_postgoal = true; - } else { - is_postgoal = false; - } + bool is_postgoal = + (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN || + mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_INIT || + mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_MAIN || + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN); // submodes for the fallout and y/n screen - if (mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || - mkb::sub_mode == mkb::SMD_GAME_RINGOUT_MAIN || mkb::sub_mode == mkb::SMD_GAME_RETRY_INIT || - mkb::sub_mode == mkb::SMD_GAME_RETRY_MAIN) { - is_on_fallout = true; - } else { - is_on_fallout = false; - } + bool is_on_fallout = + (mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || + mkb::sub_mode == mkb::SMD_GAME_RINGOUT_MAIN || mkb::sub_mode == mkb::SMD_GAME_RETRY_INIT || + mkb::sub_mode == mkb::SMD_GAME_RETRY_MAIN); // submodes during timeover - if (mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || - mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN) { - is_timeover = true; - } else { - is_timeover = false; - } - - if (mkb::main_game_mode == mkb::STORY_MODE || mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_INIT || - mkb::sub_mode == mkb::SMD_AUTHOR_PLAY_MAIN) { - in_story = true; - } else { - in_story = false; - } + bool is_timeover = (mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || + mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN); // this code is used to halt the timer once the screen becomes completely white when stage // selecting out of a level @@ -213,143 +148,107 @@ void tick() { s_stage_fade_out_timer = 0; } - if (in_story == true) { - for (s32 k = 0; k < 10; k++) { - if (mkb::scen_info.world == k) { - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - // need to add 1 additional frame to the timer during spin in - // putting this code before the code below for s_loadless_story_timer makes the - // timer tick up more naturally when transitioning from the 10 ball screen to - // spin in, more specifically, this prevents the timer from skipping ahead for a - // few frames, then pausing for a few frames to even itself out (I don't - // understand why that happens) - s_timer_group[k].spin_in_correction += 1; - } + for (s32 k = 0; k < 10; k++) { + if (mkb::scen_info.world == k) { + if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { + // need to add 1 additional frame to the timer during spin in + // putting this code before the code below for s_timer_group[k].full_world makes + // the timer tick up more naturally when transitioning from the 10 ball screen + // to spin in, more specifically, this prevents the timer from skipping ahead + // for a few frames, then pausing for a few frames to even itself out (I don't + // understand why that happens) + s_timer_group[k].spin_in_correction += 1; + } - s_timer_group[k].full_world = - s_timer_group[k].spin_in + s_timer_group[k].spin_in_correction + - s_timer_group[k].gameplay + s_timer_group[k].postgoal + - s_timer_group[k].stage_select + - s_timer_group[k].game_scenario_return_correction + s_timer_group[k].exit_game + - s_timer_group[k].fallout + s_timer_group[k].timeover + - s_timer_group[k].world_start_correction + s_timer_group[k].last_stage_postgoal; - - if (s_completed_stages_world[k] <= 9) { - s_timer_group[k].segment = s_timer_group[k].full_world; - } else if (s_completed_stages_world[k] == 10 && - mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { - s_timer_group[k].segment += -2; - } + s_timer_group[k].full_world = + s_timer_group[k].spin_in + s_timer_group[k].spin_in_correction + + s_timer_group[k].gameplay + s_timer_group[k].postgoal + + s_timer_group[k].stage_select + s_timer_group[k].game_scenario_return_correction + + s_timer_group[k].exit_game + s_timer_group[k].fallout + s_timer_group[k].timeover + + s_timer_group[k].world_start_correction + s_timer_group[k].last_stage_postgoal; + + if (s_completed_stages_world[k] <= 9) { + s_timer_group[k].segment = s_timer_group[k].full_world; + } else if (s_completed_stages_world[k] == 10 && + mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { + // stop world k's segment timer on tape break of the last stage of the world; we + // need to correct by 2f since SMD_GAME_GOAL_INIT happens 2f after tape break + s_timer_group[k].segment += -2; + } - if (is_on_spin_in) { - // increment the timer every frame during spin in - s_timer_group[k].spin_in += 1; - } - if (is_on_gameplay) { - // increment the timer every frame during gameplay - s_timer_group[k].gameplay += 1; - } - if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { - // increment the timer every frame after game goal init happens; once you press - // stage select, a separate 49 frame timer is started (fade out from stage - // select to the first completely white frame takes 49 frames). once the timer - // hits 49 frames, stop incrementing the timer until the 10 ball screen starts - // spinning in - if (mkb::get_world_unbeaten_stage_count(k) <= 8) { - s_timer_group[k].postgoal += 1; - } else if (mkb::get_world_unbeaten_stage_count(k) == 9) { - s_timer_group[k].last_stage_postgoal += 1; - } - } - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || - mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { - // increment the timer every frame on the story mode select screen until the a - // press input; we do not include the transition time after pressing a - // afterwards - // even ignoring completely white frames, the time spent on - // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly - // variable (up to over 40 frames sometimes!), so for the purpose of a loadless - // timer, it makes sense to cut this out from the timer - s_timer_group[k].stage_select += 1; - } - if (is_on_exit_game) { - // increment the timer every frame on the exit game screen - s_timer_group[k].exit_game += 1; - } - if (is_on_fallout) { - // increment the timer every frame during the fallout sequence and y/n screen - s_timer_group[k].fallout += 1; - } - if (is_timeover) { - // increment the timer every frame during the timeover sequence - s_timer_group[k].timeover += 1; + if (is_on_spin_in) { + // increment the timer every frame during spin in + s_timer_group[k].spin_in += 1; + } + if (is_on_gameplay) { + // increment the timer every frame during gameplay + s_timer_group[k].gameplay += 1; + } + if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { + // increment the timer every frame after game goal init happens; once you press + // stage select, a separate 49 frame timer is started (fade out from stage + // select to the first completely white frame takes 49 frames). once the timer + // hits 49 frames, stop incrementing the timer until the 10 ball screen starts + // spinning in + if (mkb::get_world_unbeaten_stage_count(k) <= 8) { + s_timer_group[k].postgoal += 1; + } else if (mkb::get_world_unbeaten_stage_count(k) == 9) { + // also note that get_world_unbeaten_stage_count only increases once the + // fade to white happens + s_timer_group[k].last_stage_postgoal += 1; } + } + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || + mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { + // increment the timer every frame on the story mode stage select screen until + // the a press input; we do not include the transition time after pressing a + // afterwards. even ignoring completely white frames, the time spent on + // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly + // variable (up to over 40 frames sometimes!), so for the purpose of a loadless + // timer, it makes sense to cut this out from the timer + s_timer_group[k].stage_select += 1; + } + if (is_on_exit_game) { + // increment the timer every frame on the exit game screen + s_timer_group[k].exit_game += 1; + } + if (is_on_fallout) { + // increment the timer every frame during the fallout sequence and y/n screen + s_timer_group[k].fallout += 1; + } + if (is_timeover) { + // increment the timer every frame during the timeover sequence + s_timer_group[k].timeover += 1; + } - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && - s_completed_stages % 10 != 0) { - // need to add 2 frames to the timer when stage selecting to the 10 ball screen, - // but don't correct if on the last stage of a world since the next frame the - // timer should increment on is covered by s_world_start_timer_correction - s_timer_group[k].game_scenario_return_correction += 2; - } + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % 10 != 0) { + // need to add 2 frames to the timer when stage selecting to the 10 ball screen, + // but don't correct if on the last stage of a world since the next frame the + // timer should increment on is covered by s_world_start_timer_correction + s_timer_group[k].game_scenario_return_correction += 2; + } - // this only gets set to 2 when you enter world k - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_timer_group[k].world_start_correction = 2; - } + // this only gets set to 2 when you enter world k; this is needed since otherwise + // the timer will not capture the first 2f of the 10 ball spin in when entering + // a new world + if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { + s_timer_group[k].world_start_correction = 2; } } } - // s_split[k] is just the fullgame time at tape break on the last stage of world k; to calculate - // that, we just add the corresponding world timers + // s_timer_group[k].split is just the fullgame time at tape break on the last stage of world k; + // to calculate this, just add s_timer_group[j].full_world (j(s_timer_group[0].segment), 1, - false, false, draw::WHITE); - timerdisp::draw_timer(380, 1, 44, - "dbg:", static_cast(60 * s_completed_stages_world[0]), 1, false, - true, draw::WHITE); - timerdisp::draw_timer(380, 2, 44, - "dbg:", static_cast(60 * s_completed_stages_world[1]), 1, false, - true, draw::WHITE); - } - // mkb::scen_info.world - // 10*mkb::scen_info.world+mkb::get_world_unbeaten_stage_count(mkb::scen_info.world) - // mkb::scen_info.next_world == 10 } -} // namespace storytimer +} // namespace storytimer \ No newline at end of file From 9a38703cdd5497ac305a5f23b403e838069debab Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Fri, 17 Nov 2023 18:47:23 -0600 Subject: [PATCH 23/45] added count deaths on stage 1 toggle to deathcounter --- src/mods/deathcounter.cpp | 20 +++++++++++++++----- src/mods/storytimer.cpp | 2 ++ src/mods/storytimer.h | 3 +++ src/systems/menu_defn.cpp | 31 +++++++++++++++++++++++++++++-- src/systems/pref.cpp | 9 +++++++-- src/systems/pref.h | 1 + 6 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 53e2223c..a8bab02a 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -3,6 +3,7 @@ #include "mkb/mkb.h" #include "mods/freecam.h" +#include "mods/storytimer.h" #include "systems/assembly.h" #include "systems/pad.h" #include "systems/pref.h" @@ -16,14 +17,22 @@ static bool s_can_die; static u32 s_death_count; void tick() { - // bool paused_now = *reinterpret_cast(0x805BC474) & 8; // set the death count to 0 on the file select screen if (mkb::scen_info.mode == 5) { s_death_count = 0; + s_can_die = false; } - if (mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { - s_can_die = true; + // Don't increment the death counter on stage 1 if the setting is ticked + if (!pref::get(pref::BoolPref::CountStage1Deaths)) { + if (mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN && + storytimer::get_completed_stagecount() != 0) { + s_can_die = true; + } + } else { + if (mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { + s_can_die = true; + } } if (s_can_die && @@ -35,7 +44,8 @@ void tick() { // selecting after dropping in (but before breaking the tape), or exiting game after // dropping in (but before breaking the tape) s_death_count += 1; - s_can_die = false; + s_can_die = false; // once the death counter is incremented, set this to false so we only + // increment it by 1 } // first framing should not increase the death counter, and retrying after breaking the tape @@ -50,7 +60,7 @@ void tick() { void disp() { if ((mkb::main_game_mode != mkb::STORY_MODE && mkb::sub_mode != mkb::SMD_AUTHOR_PLAY_INIT && mkb::sub_mode != mkb::SMD_AUTHOR_PLAY_MAIN) || - freecam::should_hide_hud() || pref::get(pref::BoolPref::ShowDeathCounter) == false) { + freecam::should_hide_hud() || !pref::get(pref::BoolPref::ShowDeathCounter)) { return; } draw::debug_text(18, 56, draw::WHITE, "Deaths: "); diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 036cc39e..40575d09 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -53,6 +53,8 @@ static constexpr s32 IW_TIME_TEXT_OFFSET = 32; static constexpr s32 STAGE_FADE_OUT_TIME = 49; static constexpr u32 WORLD_START_CORRECTION = 2; +u32 get_completed_stagecount() { return s_completed_stages; } + void tick() { // before starting the run, there are several values we zero on the file select and name entry // screen (this serves to reset the timer) diff --git a/src/mods/storytimer.h b/src/mods/storytimer.h index 16df1c93..fcc9a2c3 100644 --- a/src/mods/storytimer.h +++ b/src/mods/storytimer.h @@ -1,8 +1,11 @@ #pragma once +#include "mkb/mkb.h" + namespace storytimer { void tick(); void disp(); +u32 get_completed_stagecount(); } // namespace storytimer \ No newline at end of file diff --git a/src/systems/menu_defn.cpp b/src/systems/menu_defn.cpp index e61c5506..c45cb372 100644 --- a/src/systems/menu_defn.cpp +++ b/src/systems/menu_defn.cpp @@ -708,7 +708,7 @@ static Widget s_loadless_timers_widgets[] = { .pref = pref::U8Pref::SegmentTimerOptions, }, }, - { + { .type = WidgetType::Checkbox, .checkbox = { @@ -718,7 +718,27 @@ static Widget s_loadless_timers_widgets[] = { }, }; -static Widget s_timers_widgets[] = { // I might want to reorganize this with the addition of a loadless timer +static Widget s_deathcounter_widgets[] = { + { + .type = WidgetType::Checkbox, + .checkbox = + { + .label = "Show Death Counter", + .pref = pref::BoolPref::ShowDeathCounter, + }, + }, + { + .type = WidgetType::Checkbox, + .checkbox = + { + .label = "Count Stage 1 Deaths", + .pref = pref::BoolPref::CountStage1Deaths, + }, + }, +}; + +static Widget s_timers_widgets[] = { + // I might want to reorganize this with the addition of a loadless timer {.type = WidgetType::Header, .header = {"Realtime Timers"}}, { .type = WidgetType::Checkbox, @@ -1301,7 +1321,9 @@ static Widget s_displays_widgets[] = { .pref = pref::BoolPref::BananaCounter9999, }, }, + /* { + // del .type = WidgetType::Checkbox, .checkbox = { @@ -1309,6 +1331,11 @@ static Widget s_displays_widgets[] = { .pref = pref::BoolPref::ShowDeathCounter, }, }, + */ + { + .type = WidgetType::Menu, + .menu = {"Death Counter", s_deathcounter_widgets, LEN(s_deathcounter_widgets)}, + }, }; static Widget s_enabled_physics_widgets[] = { diff --git a/src/systems/pref.cpp b/src/systems/pref.cpp index 3c416077..1fc05e22 100644 --- a/src/systems/pref.cpp +++ b/src/systems/pref.cpp @@ -98,6 +98,7 @@ enum class PrefId : u16 { SegmentTimerOptions = 78, StoryTimerWarning = 79, ShowDeathCounter = 80, + CountStage1Deaths = 81, }; // Verbatim list of preference IDs we iterate over when writing savefile back out @@ -179,6 +180,7 @@ static const PrefId s_pref_ids[] = { PrefId::SegmentTimerOptions, PrefId::StoryTimerWarning, PrefId::ShowDeathCounter, + PrefId::CountStage1Deaths, }; static std::optional pref_id_to_bool_pref(PrefId id) { @@ -283,6 +285,8 @@ static std::optional pref_id_to_bool_pref(PrefId id) { return BoolPref::StoryTimerWarning; case PrefId::ShowDeathCounter: return BoolPref::ShowDeathCounter; + case PrefId::CountStage1Deaths: + return BoolPref::CountStage1Deaths; default: return {}; } @@ -363,6 +367,7 @@ static BoolPref s_default_on_bool_prefs[] = { BoolPref::FreecamHideHud, BoolPref::IlBattleShowTime, BoolPref::IlBattleShowScore, + BoolPref::CountStage1Deaths, }; struct DefaultU8Pref { @@ -386,8 +391,8 @@ static DefaultU8Pref s_default_u8_prefs[] = { // struct PrefState { - u8 bool_prefs[9]; - u8 u8_prefs[28]; + u8 bool_prefs[10]; + u8 u8_prefs[28]; }; static PrefState s_pref_state, s_default_pref_state; diff --git a/src/systems/pref.h b/src/systems/pref.h index e8df563a..8fc16606 100644 --- a/src/systems/pref.h +++ b/src/systems/pref.h @@ -58,6 +58,7 @@ enum class BoolPref : u8 { ReverseMode, StoryTimerWarning, ShowDeathCounter, + CountStage1Deaths, }; enum class U8Pref : u8 { From 290410a0168325755bc34a489e19d4b35ab1bcbd Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Fri, 17 Nov 2023 19:23:46 -0600 Subject: [PATCH 24/45] optimized memory used by timer removed some static u32 variables that were being kept track of --- src/mods/storytimer.cpp | 53 +++++-------------- ...storytimer.cpp\357\200\272Zone.Identifier" | 3 -- 2 files changed, 13 insertions(+), 43 deletions(-) delete mode 100644 "src/mods/storytimer.cpp\357\200\272Zone.Identifier" diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 40575d09..b2f17564 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -25,17 +25,9 @@ struct TimerGroup { u32 full_world; // the time taken to complete a world until the fade to white on the last stage u32 split; // the time from the start of the run until tape break of the last stage of the // world - u32 spin_in; - u32 spin_in_correction; u32 gameplay; - u32 postgoal; - u32 stage_select; - u32 game_scenario_return_correction; + u32 non_gameplay; u32 world_start_correction; - u32 exit_game; - u32 fallout; - u32 timeover; - u32 last_stage_postgoal; }; static TimerGroup s_timer_group[10]; // each world has its own TimerGroup structure static bool s_can_lower_stage_counter; @@ -159,15 +151,12 @@ void tick() { // to spin in, more specifically, this prevents the timer from skipping ahead // for a few frames, then pausing for a few frames to even itself out (I don't // understand why that happens) - s_timer_group[k].spin_in_correction += 1; + s_timer_group[k].non_gameplay += 1; } - s_timer_group[k].full_world = - s_timer_group[k].spin_in + s_timer_group[k].spin_in_correction + - s_timer_group[k].gameplay + s_timer_group[k].postgoal + - s_timer_group[k].stage_select + s_timer_group[k].game_scenario_return_correction + - s_timer_group[k].exit_game + s_timer_group[k].fallout + s_timer_group[k].timeover + - s_timer_group[k].world_start_correction + s_timer_group[k].last_stage_postgoal; + s_timer_group[k].full_world = s_timer_group[k].gameplay + + s_timer_group[k].non_gameplay + + s_timer_group[k].world_start_correction; if (s_completed_stages_world[k] <= 9) { s_timer_group[k].segment = s_timer_group[k].full_world; @@ -178,10 +167,12 @@ void tick() { s_timer_group[k].segment += -2; } - if (is_on_spin_in) { - // increment the timer every frame during spin in - s_timer_group[k].spin_in += 1; + if (is_on_spin_in || is_on_exit_game || is_on_fallout || is_timeover) { + // increment the timer during every frame on spin in, exit game, fallout, and + // timeover + s_timer_group[k].non_gameplay += 1; } + if (is_on_gameplay) { // increment the timer every frame during gameplay s_timer_group[k].gameplay += 1; @@ -192,13 +183,7 @@ void tick() { // select to the first completely white frame takes 49 frames). once the timer // hits 49 frames, stop incrementing the timer until the 10 ball screen starts // spinning in - if (mkb::get_world_unbeaten_stage_count(k) <= 8) { - s_timer_group[k].postgoal += 1; - } else if (mkb::get_world_unbeaten_stage_count(k) == 9) { - // also note that get_world_unbeaten_stage_count only increases once the - // fade to white happens - s_timer_group[k].last_stage_postgoal += 1; - } + s_timer_group[k].non_gameplay += 1; } if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || mkb::g_storymode_stageselect_state == 3 || @@ -209,26 +194,14 @@ void tick() { // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly // variable (up to over 40 frames sometimes!), so for the purpose of a loadless // timer, it makes sense to cut this out from the timer - s_timer_group[k].stage_select += 1; - } - if (is_on_exit_game) { - // increment the timer every frame on the exit game screen - s_timer_group[k].exit_game += 1; - } - if (is_on_fallout) { - // increment the timer every frame during the fallout sequence and y/n screen - s_timer_group[k].fallout += 1; - } - if (is_timeover) { - // increment the timer every frame during the timeover sequence - s_timer_group[k].timeover += 1; + s_timer_group[k].non_gameplay += 1; } if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % 10 != 0) { // need to add 2 frames to the timer when stage selecting to the 10 ball screen, // but don't correct if on the last stage of a world since the next frame the // timer should increment on is covered by s_world_start_timer_correction - s_timer_group[k].game_scenario_return_correction += 2; + s_timer_group[k].non_gameplay += 2; } // this only gets set to 2 when you enter world k; this is needed since otherwise diff --git "a/src/mods/storytimer.cpp\357\200\272Zone.Identifier" "b/src/mods/storytimer.cpp\357\200\272Zone.Identifier" deleted file mode 100644 index 2d45b2b2..00000000 --- "a/src/mods/storytimer.cpp\357\200\272Zone.Identifier" +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=about:internet From 066e8d0e9e6949fefb51448207e338ed907f5cc1 Mon Sep 17 00:00:00 2001 From: eddynya Date: Tue, 21 Nov 2023 17:42:03 -0600 Subject: [PATCH 25/45] pre merge commit --- src/systems/menu_defn.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/systems/menu_defn.cpp b/src/systems/menu_defn.cpp index c45cb372..b5fca1af 100644 --- a/src/systems/menu_defn.cpp +++ b/src/systems/menu_defn.cpp @@ -1321,17 +1321,6 @@ static Widget s_displays_widgets[] = { .pref = pref::BoolPref::BananaCounter9999, }, }, - /* - { - // del - .type = WidgetType::Checkbox, - .checkbox = - { - .label = "Show Death Counter", - .pref = pref::BoolPref::ShowDeathCounter, - }, - }, - */ { .type = WidgetType::Menu, .menu = {"Death Counter", s_deathcounter_widgets, LEN(s_deathcounter_widgets)}, From 00df2a776a9bbb6e4daf42a055335bc3772cc0f6 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 21 Nov 2023 17:43:55 -0600 Subject: [PATCH 26/45] Update pref.cpp --- src/systems/pref.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/systems/pref.cpp b/src/systems/pref.cpp index 1fc05e22..792f7f4a 100644 --- a/src/systems/pref.cpp +++ b/src/systems/pref.cpp @@ -391,7 +391,7 @@ static DefaultU8Pref s_default_u8_prefs[] = { // struct PrefState { - u8 bool_prefs[10]; + u8 bool_prefs[8]; u8 u8_prefs[28]; }; From e2f6eaaab157a80675d0b03d136e55fc35af71a4 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 21 Nov 2023 22:58:49 -0600 Subject: [PATCH 27/45] fixed deathcounter bug retrying on the tape break frame no longer increases the death counter --- scripts/gen_compile_commands.py | 0 scripts/genfunc.py | 0 scripts/go.sh | 0 scripts/str2hex.py | 0 scripts/subtrees.sh | 0 src/mods/deathcounter.cpp | 17 +++++++++++------ src/mods/deathcounter.h | 1 + src/mods/storytimer.cpp | 8 ++++++++ src/mods/storytimer.h | 1 + src/mods/validate.cpp | 2 ++ src/mods/validate.h | 1 + src/systems/main.cpp | 2 ++ src/systems/menu_defn.cpp | 2 +- src/systems/pref.cpp | 10 +++++----- src/systems/pref.h | 2 +- 15 files changed, 33 insertions(+), 13 deletions(-) mode change 100755 => 100644 scripts/gen_compile_commands.py mode change 100755 => 100644 scripts/genfunc.py mode change 100755 => 100644 scripts/go.sh mode change 100755 => 100644 scripts/str2hex.py mode change 100755 => 100644 scripts/subtrees.sh diff --git a/scripts/gen_compile_commands.py b/scripts/gen_compile_commands.py old mode 100755 new mode 100644 diff --git a/scripts/genfunc.py b/scripts/genfunc.py old mode 100755 new mode 100644 diff --git a/scripts/go.sh b/scripts/go.sh old mode 100755 new mode 100644 diff --git a/scripts/str2hex.py b/scripts/str2hex.py old mode 100755 new mode 100644 diff --git a/scripts/subtrees.sh b/scripts/subtrees.sh old mode 100755 new mode 100644 diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index a8bab02a..4087f6d1 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -4,6 +4,7 @@ #include "mods/freecam.h" #include "mods/storytimer.h" +#include "mods/validate.h" #include "systems/assembly.h" #include "systems/pad.h" #include "systems/pref.h" @@ -16,6 +17,12 @@ namespace deathcounter { static bool s_can_die; static u32 s_death_count; +void on_goal_entry() { + if (!validate::has_entered_goal()) { + s_can_die = false; + } +} + void tick() { // set the death count to 0 on the file select screen if (mkb::scen_info.mode == 5) { @@ -24,13 +31,11 @@ void tick() { } // Don't increment the death counter on stage 1 if the setting is ticked - if (!pref::get(pref::BoolPref::CountStage1Deaths)) { - if (mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN && - storytimer::get_completed_stagecount() != 0) { + if (mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN && !validate::has_entered_goal()) { + if (pref::get(pref::BoolPref::CountFirstStageDeaths)) { s_can_die = true; - } - } else { - if (mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { + } else if (!pref::get(pref::BoolPref::CountFirstStageDeaths) && + storytimer::get_completed_stagecount() != 0) { s_can_die = true; } } diff --git a/src/mods/deathcounter.h b/src/mods/deathcounter.h index 68d11abb..e5f653fd 100644 --- a/src/mods/deathcounter.h +++ b/src/mods/deathcounter.h @@ -2,6 +2,7 @@ namespace deathcounter { +void on_goal_entry(); void tick(); void disp(); diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index b2f17564..5d0612da 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -3,6 +3,7 @@ #include "mkb/mkb.h" #include "mods/freecam.h" +#include "mods/validate.h" #include "systems/assembly.h" #include "systems/pad.h" #include "systems/pref.h" @@ -20,6 +21,7 @@ enum class TimerOptions { }; static u32 s_loadless_story_timer; +static bool s_entered_goal; struct TimerGroup { u32 segment; // the time taken to complete a world up until tape break on the last stage u32 full_world; // the time taken to complete a world until the fade to white on the last stage @@ -47,6 +49,12 @@ static constexpr u32 WORLD_START_CORRECTION = 2; u32 get_completed_stagecount() { return s_completed_stages; } +void on_goal_entry() { + if (!validate::has_entered_goal()) { + // no code yet + } +} + void tick() { // before starting the run, there are several values we zero on the file select and name entry // screen (this serves to reset the timer) diff --git a/src/mods/storytimer.h b/src/mods/storytimer.h index fcc9a2c3..f3902e9a 100644 --- a/src/mods/storytimer.h +++ b/src/mods/storytimer.h @@ -4,6 +4,7 @@ namespace storytimer { +void on_goal_entry(); void tick(); void disp(); u32 get_completed_stagecount(); diff --git a/src/mods/validate.cpp b/src/mods/validate.cpp index d1719104..64d81231 100644 --- a/src/mods/validate.cpp +++ b/src/mods/validate.cpp @@ -194,6 +194,8 @@ void init() { }); } +bool has_entered_goal() { return s_entered_goal; } + void tick() { if (mkb::sub_mode == mkb::SMD_GAME_PLAY_INIT) { s_entered_goal = false; diff --git a/src/mods/validate.h b/src/mods/validate.h index 136065ea..11df5c1a 100644 --- a/src/mods/validate.h +++ b/src/mods/validate.h @@ -5,6 +5,7 @@ namespace validate { void validate_run(); +bool has_entered_goal(); bool was_run_valid(bool mods_allowed); void disable_invalidating_settings(); u32 get_framesave(); diff --git a/src/systems/main.cpp b/src/systems/main.cpp index 00df6f69..7344dadf 100644 --- a/src/systems/main.cpp +++ b/src/systems/main.cpp @@ -198,6 +198,8 @@ void init() { validate::validate_run(); ilmark::validate_attempt(); ilbattle::validate_attempt(); + storytimer::on_goal_entry(); + deathcounter::on_goal_entry(); }); jump::patch_minimap(); } diff --git a/src/systems/menu_defn.cpp b/src/systems/menu_defn.cpp index dafd7c06..ecec5f56 100644 --- a/src/systems/menu_defn.cpp +++ b/src/systems/menu_defn.cpp @@ -753,7 +753,7 @@ static Widget s_deathcounter_widgets[] = { .checkbox = { .label = "Count Stage 1 Deaths", - .pref = pref::BoolPref::CountStage1Deaths, + .pref = pref::BoolPref::CountFirstStageDeaths, }, }, }; diff --git a/src/systems/pref.cpp b/src/systems/pref.cpp index 2a4b3b60..f073c0d1 100644 --- a/src/systems/pref.cpp +++ b/src/systems/pref.cpp @@ -105,7 +105,7 @@ enum class PrefId : u16 { SegmentTimerOptions = 85, StoryTimerWarning = 86, ShowDeathCounter = 87, - CountStage1Deaths = 88, + CountFirstStageDeaths = 88, }; // Verbatim list of preference IDs we iterate over when writing savefile back out @@ -192,7 +192,7 @@ static const PrefId s_pref_ids[] = { PrefId::SegmentTimerOptions, PrefId::StoryTimerWarning, PrefId::ShowDeathCounter, - PrefId::CountStage1Deaths, + PrefId::CountFirstStageDeaths, }; static std::optional pref_id_to_bool_pref(PrefId id) { @@ -299,8 +299,8 @@ static std::optional pref_id_to_bool_pref(PrefId id) { return BoolPref::StoryTimerWarning; case PrefId::ShowDeathCounter: return BoolPref::ShowDeathCounter; - case PrefId::CountStage1Deaths: - return BoolPref::CountStage1Deaths; + case PrefId::CountFirstStageDeaths: + return BoolPref::CountFirstStageDeaths; default: return {}; } @@ -394,7 +394,7 @@ static BoolPref s_default_on_bool_prefs[] = { BoolPref::JumpChangePhysics, BoolPref::JumpAllowWalljumps, BoolPref::CustomPhysicsDisp, - BoolPref::CountStage1Deaths, + BoolPref::CountFirstStageDeaths, }; struct DefaultU8Pref { diff --git a/src/systems/pref.h b/src/systems/pref.h index 2da4b18c..18a1efe6 100644 --- a/src/systems/pref.h +++ b/src/systems/pref.h @@ -58,7 +58,7 @@ enum class BoolPref : u8 { CustomPhysicsDisp, StoryTimerWarning, ShowDeathCounter, - CountStage1Deaths, + CountFirstStageDeaths, }; enum class U8Pref : u8 { From 4cda08abdaa5b72de9be6f30dd750445ee87ec83 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 21 Nov 2023 23:34:34 -0600 Subject: [PATCH 28/45] started addressing storytimer comments nothing significant really --- src/mods/storytimer.cpp | 69 ++++++++++++++++++--------------------- src/systems/menu_defn.cpp | 8 ----- src/systems/pref.cpp | 8 ++--- src/systems/pref.h | 1 - 4 files changed, 33 insertions(+), 53 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 5d0612da..9f25583d 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -20,7 +20,16 @@ enum class TimerOptions { EndOfRun = 3, }; -static u32 s_loadless_story_timer; +static constexpr s32 FULLGAME_TIMER_LOCATION_X = 18 + 24; +static constexpr s32 FULLGAME_TIMER_TEXT_OFFSET = 56; +static constexpr s32 SEGMENT_TIMER_LOCATION_X = 30 + 24; +static constexpr s32 SEGMENT_TIMER_TEXT_OFFSET = 44; +static constexpr s32 IW_TIME_LOCATION_X = 42 + 24; +static constexpr s32 IW_TIME_TEXT_OFFSET = 32; +static constexpr s32 STAGE_FADE_OUT_TIME = 49; +static constexpr u32 WORLD_START_CORRECTION = 2; +static constexpr s32 WORLD_COUNT = 10; +static constexpr s32 STAGES_PER_WORLD = 10; static bool s_entered_goal; struct TimerGroup { u32 segment; // the time taken to complete a world up until tape break on the last stage @@ -31,21 +40,13 @@ struct TimerGroup { u32 non_gameplay; u32 world_start_correction; }; -static TimerGroup s_timer_group[10]; // each world has its own TimerGroup structure +static TimerGroup s_timer_group[WORLD_COUNT]; // each world has its own TimerGroup structure static bool s_can_lower_stage_counter; static bool s_start_stage_fade_out_timer; static u32 s_stage_fade_out_timer; -static s32 s_completed_stages; // the completed stages for the whole run -static s32 s_completed_stages_world[10]; // the completed stages in world k +static s32 s_completed_stages; // the completed stages for the whole run +static s32 s_completed_stages_world[WORLD_COUNT]; // the completed stages in world k static bool s_display_segment_timer; -static constexpr s32 FULLGAME_TIMER_LOCATION_X = 18 + 24; -static constexpr s32 FULLGAME_TIMER_TEXT_OFFSET = 56; -static constexpr s32 SEGMENT_TIMER_LOCATION_X = 30 + 24; -static constexpr s32 SEGMENT_TIMER_TEXT_OFFSET = 44; -static constexpr s32 IW_TIME_LOCATION_X = 42 + 24; -static constexpr s32 IW_TIME_TEXT_OFFSET = 32; -static constexpr s32 STAGE_FADE_OUT_TIME = 49; -static constexpr u32 WORLD_START_CORRECTION = 2; u32 get_completed_stagecount() { return s_completed_stages; } @@ -61,11 +62,10 @@ void tick() { if (mkb::scen_info.mode == 5 || mkb::scen_info.mode == 21) { // 5 is the file select screen, 21 is the name entry screen s_can_lower_stage_counter = false; - s_loadless_story_timer = 0; s_completed_stages = 0; s_start_stage_fade_out_timer = false; s_stage_fade_out_timer = 0; - for (s32 k = 0; k < 10; k++) { + for (s32 k = 0; k < WORLD_COUNT; k++) { s_timer_group[k] = {}; s_completed_stages_world[k] = 0; } @@ -75,7 +75,7 @@ void tick() { // for later use, it's useful to record how many stages we've completed // increment the completed stages by 1 during the init // need to check that the game is not paused to ensure the counter only goes up by 1 - for (s32 k = 0; k < 10; k++) { + for (s32 k = 0; k < WORLD_COUNT; k++) { if (mkb::scen_info.world == k) { if (!paused_now && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { s_completed_stages_world[k] += 1; @@ -150,7 +150,7 @@ void tick() { s_stage_fade_out_timer = 0; } - for (s32 k = 0; k < 10; k++) { + for (s32 k = 0; k < WORLD_COUNT; k++) { if (mkb::scen_info.world == k) { if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { // need to add 1 additional frame to the timer during spin in @@ -168,7 +168,7 @@ void tick() { if (s_completed_stages_world[k] <= 9) { s_timer_group[k].segment = s_timer_group[k].full_world; - } else if (s_completed_stages_world[k] == 10 && + } else if (s_completed_stages_world[k] == STAGES_PER_WORLD && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { // stop world k's segment timer on tape break of the last stage of the world; we // need to correct by 2f since SMD_GAME_GOAL_INIT happens 2f after tape break @@ -205,7 +205,8 @@ void tick() { s_timer_group[k].non_gameplay += 1; } - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % 10 != 0) { + if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && + s_completed_stages % STAGES_PER_WORLD != 0) { // need to add 2 frames to the timer when stage selecting to the 10 ball screen, // but don't correct if on the last stage of a world since the next frame the // timer should increment on is covered by s_world_start_timer_correction @@ -223,15 +224,14 @@ void tick() { // s_timer_group[k].split is just the fullgame time at tape break on the last stage of world k; // to calculate this, just add s_timer_group[j].full_world (j pref_id_to_bool_pref(PrefId id) { return BoolPref::JumpAllowWalljumps; case PrefId::CustomPhysicsDisp: return BoolPref::CustomPhysicsDisp; - case PrefId::StoryTimerWarning: - return BoolPref::StoryTimerWarning; case PrefId::ShowDeathCounter: return BoolPref::ShowDeathCounter; case PrefId::CountFirstStageDeaths: diff --git a/src/systems/pref.h b/src/systems/pref.h index 18a1efe6..59b5ebac 100644 --- a/src/systems/pref.h +++ b/src/systems/pref.h @@ -56,7 +56,6 @@ enum class BoolPref : u8 { JumpChangePhysics, JumpAllowWalljumps, CustomPhysicsDisp, - StoryTimerWarning, ShowDeathCounter, CountFirstStageDeaths, }; From 9170ba3eb6e49da6618ace129adb306ff0593bfc Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Tue, 28 Nov 2023 03:33:22 -0600 Subject: [PATCH 29/45] small changes before bigger changes --- src/mods/storytimer.cpp | 105 +++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 9f25583d..ae203bac 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -34,8 +34,8 @@ static bool s_entered_goal; struct TimerGroup { u32 segment; // the time taken to complete a world up until tape break on the last stage u32 full_world; // the time taken to complete a world until the fade to white on the last stage - u32 split; // the time from the start of the run until tape break of the last stage of the - // world + // u32 split; // the time from the start of the run until tape break of the last stage of + // the world u32 gameplay; u32 non_gameplay; u32 world_start_correction; @@ -56,19 +56,23 @@ void on_goal_entry() { } } +// before starting the run, there are several values we zero +static void reset_timer() { + s_can_lower_stage_counter = false; + s_completed_stages = 0; + s_start_stage_fade_out_timer = false; + s_stage_fade_out_timer = 0; + for (s32 k = 0; k < WORLD_COUNT; k++) { + s_timer_group[k] = {}; + s_completed_stages_world[k] = 0; + } +} + void tick() { - // before starting the run, there are several values we zero on the file select and name entry - // screen (this serves to reset the timer) + // reset the timer on the file select screen (scen_info.mode == 5) and the name entry screen + // (scen_info.mode == 21) if (mkb::scen_info.mode == 5 || mkb::scen_info.mode == 21) { - // 5 is the file select screen, 21 is the name entry screen - s_can_lower_stage_counter = false; - s_completed_stages = 0; - s_start_stage_fade_out_timer = false; - s_stage_fade_out_timer = 0; - for (s32 k = 0; k < WORLD_COUNT; k++) { - s_timer_group[k] = {}; - s_completed_stages_world[k] = 0; - } + reset_timer(); } bool paused_now = *reinterpret_cast(0x805BC474) & 8; @@ -221,6 +225,7 @@ void tick() { } } } + /* // s_timer_group[k].split is just the fullgame time at tape break on the last stage of world k; // to calculate this, just add s_timer_group[j].full_world (j Date: Fri, 22 Dec 2023 18:45:58 -0600 Subject: [PATCH 30/45] backup before fixing bugs -timer and seg timer are consistently offset from each other currently when they shouldn't be --- src/mods/deathcounter.cpp | 15 +++++++ src/mods/storytimer.cpp | 85 +++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 34 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 4087f6d1..2755c5ff 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -53,6 +53,21 @@ void tick() { // increment it by 1 } + // bandaid fix for stardust bug + /* + if (s_can_die && + (mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || + mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || + mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT)) { + // you can die either by retrying after dropping in, falling out, timing over, stage + // selecting after dropping in (but before breaking the tape), or exiting game after + // dropping in (but before breaking the tape) + s_death_count += 1; + s_can_die = false; // once the death counter is incremented, set this to false so we only + // increment it by 1 + } + */ + // first framing should not increase the death counter, and retrying after breaking the tape // should not increase it either to do: however, if you retry after breaking the tape on the // very first frame (so the frame before goal init), it does count as a death when it should not diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index ae203bac..5ed364e3 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -163,13 +163,8 @@ void tick() { // to spin in, more specifically, this prevents the timer from skipping ahead // for a few frames, then pausing for a few frames to even itself out (I don't // understand why that happens) - s_timer_group[k].non_gameplay += 1; + s_timer_group[k].full_world += 1; } - - s_timer_group[k].full_world = s_timer_group[k].gameplay + - s_timer_group[k].non_gameplay + - s_timer_group[k].world_start_correction; - if (s_completed_stages_world[k] <= 9) { s_timer_group[k].segment = s_timer_group[k].full_world; } else if (s_completed_stages_world[k] == STAGES_PER_WORLD && @@ -182,12 +177,12 @@ void tick() { if (is_on_spin_in || is_on_exit_game || is_on_fallout || is_timeover) { // increment the timer during every frame on spin in, exit game, fallout, and // timeover - s_timer_group[k].non_gameplay += 1; + s_timer_group[k].full_world += 1; } if (is_on_gameplay) { // increment the timer every frame during gameplay - s_timer_group[k].gameplay += 1; + s_timer_group[k].full_world += 1; } if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { // increment the timer every frame after game goal init happens; once you press @@ -195,7 +190,7 @@ void tick() { // select to the first completely white frame takes 49 frames). once the timer // hits 49 frames, stop incrementing the timer until the 10 ball screen starts // spinning in - s_timer_group[k].non_gameplay += 1; + s_timer_group[k].full_world += 1; } if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || mkb::g_storymode_stageselect_state == 3 || @@ -206,7 +201,7 @@ void tick() { // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly // variable (up to over 40 frames sometimes!), so for the purpose of a loadless // timer, it makes sense to cut this out from the timer - s_timer_group[k].non_gameplay += 1; + s_timer_group[k].full_world += 1; } if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && @@ -214,15 +209,17 @@ void tick() { // need to add 2 frames to the timer when stage selecting to the 10 ball screen, // but don't correct if on the last stage of a world since the next frame the // timer should increment on is covered by s_world_start_timer_correction - s_timer_group[k].non_gameplay += 2; + s_timer_group[k].full_world += 2; } + /* // this only gets set to 2 when you enter world k; this is needed since otherwise // the timer will not capture the first 2f of the 10 ball spin in when entering // a new world if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { s_timer_group[k].world_start_correction = 2; } + */ } } /* @@ -254,7 +251,7 @@ void disp() { } else if ((s_completed_stages % STAGES_PER_WORLD == 0 && mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) || s_completed_stages % STAGES_PER_WORLD != 0) { - // no longer "between worlds" if you enter the next worlds 10 ball screen, or if you break + // no longer "between worlds" if you enter the next world's 10 ball screen, or if you break // the tape on the last stage of the current world, but retry is_between_worlds = false; } @@ -290,13 +287,25 @@ void disp() { // to calculate this, just add s_timer_group[j].full_world (j 0) { + // don't apply the correction until the world actually starts + full_world[k] = s_timer_group[k].full_world + 1; + segment[k] = s_timer_group[k].segment + 1; + } + } + u32 sum[WORLD_COUNT] = {}; u32 split[WORLD_COUNT] = {}; for (s32 k = 1; k < WORLD_COUNT; k++) { for (s32 j = 0; j < k; j++) { - sum[k] += s_timer_group[j].full_world; + sum[k] += full_world[j]; } - split[k] = sum[k] + s_timer_group[k].segment; + split[k] = sum[k] + segment[k]; } split[0] = s_timer_group[0].segment; u32 loadless_story_timer = split[9]; @@ -309,12 +318,12 @@ void disp() { // move the position of the segment timer depending on if the death counter and fullgame timer // is on - u32 segment_timer_y = 2; + u32 segment_timer_location_y = 2; if (display_story_timer) { - segment_timer_y++; + segment_timer_location_y++; } if (pref::get(pref::BoolPref::ShowDeathCounter)) { - segment_timer_y++; + segment_timer_location_y++; } switch (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions))) { @@ -322,9 +331,8 @@ void disp() { for (s32 k = 0; k < WORLD_COUNT; k++) { if (mkb::scen_info.world == k && !is_run_complete) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y, - SEGMENT_TIMER_TEXT_OFFSET, - "Seg:", s_timer_group[k].segment, 0, false, false, - draw::WHITE); + SEGMENT_TIMER_TEXT_OFFSET, "Seg:", segment[k], 0, false, + false, draw::WHITE); } } break; @@ -332,12 +340,13 @@ void disp() { for (s32 k = 0; k < WORLD_COUNT; k++) { if (is_between_worlds && mkb::scen_info.world == k && k != 9) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y, - SEGMENT_TIMER_TEXT_OFFSET, - "Seg:", s_timer_group[k].segment, 0, false, false, - draw::WHITE); + SEGMENT_TIMER_TEXT_OFFSET, "Seg:", segment[k], 0, false, + false, draw::WHITE); } } break; + case TimerOptions::EndOfRun: + break; case TimerOptions::DontShow: s_display_segment_timer = false; break; @@ -349,28 +358,36 @@ void disp() { is_run_complete) { // haven't attempted the mkb::sprintf suggestion yet timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y, IW_TIME_TEXT_OFFSET, - "W1:", split[0], s_timer_group[0].segment, true, false, draw::WHITE); + "W1:", split[0], segment[0], true, false, draw::WHITE); timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 1, IW_TIME_TEXT_OFFSET, - "W2:", split[1], s_timer_group[1].segment, true, false, draw::WHITE); + "W2:", split[1], segment[1], true, false, draw::WHITE); timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 2, IW_TIME_TEXT_OFFSET, - "W3:", split[2], s_timer_group[2].segment, true, false, draw::WHITE); + "W3:", split[2], segment[2], true, false, draw::WHITE); timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 3, IW_TIME_TEXT_OFFSET, - "W4:", split[3], s_timer_group[3].segment, true, false, draw::WHITE); + "W4:", split[3], segment[3], true, false, draw::WHITE); timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 4, IW_TIME_TEXT_OFFSET, - "W5:", split[4], s_timer_group[4].segment, true, false, draw::WHITE); + "W5:", split[4], segment[4], true, false, draw::WHITE); timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 5, IW_TIME_TEXT_OFFSET, - "W6:", split[5], s_timer_group[5].segment, true, false, draw::WHITE); + "W6:", split[5], segment[5], true, false, draw::WHITE); timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 6, IW_TIME_TEXT_OFFSET, - "W7:", split[6], s_timer_group[6].segment, true, false, draw::WHITE); + "W7:", split[6], segment[6], true, false, draw::WHITE); timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 7, IW_TIME_TEXT_OFFSET, - "W8:", split[7], s_timer_group[7].segment, true, false, draw::WHITE); + "W8:", split[7], segment[7], true, false, draw::WHITE); timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 8, IW_TIME_TEXT_OFFSET, - "W9:", split[8], s_timer_group[8].segment, true, false, draw::WHITE); + "W9:", split[8], segment[8], true, false, draw::WHITE); // use segment timer spacing for w10 since "W10" is 3 characters long, not 2 timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y + 9, - SEGMENT_TIMER_TEXT_OFFSET, "W10:", split[9], s_timer_group[9].segment, - true, false, draw::WHITE); + SEGMENT_TIMER_TEXT_OFFSET, "W10:", split[9], segment[9], true, false, + draw::WHITE); } + + // debugging + + timerdisp::draw_timer(450, 1, IW_TIME_TEXT_OFFSET, "dbg:", full_world[0], 0, false, true, + draw::WHITE); + + timerdisp::draw_timer(450, 2, IW_TIME_TEXT_OFFSET, "dbg:", 60 * mkb::sub_mode, 0, false, true, + draw::WHITE); } } // namespace storytimer \ No newline at end of file From 47d96c1a69c9619a607e7a28b0da2907d4289ecb Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Fri, 22 Dec 2023 19:49:02 -0600 Subject: [PATCH 31/45] removed unnecessary static variables in the TimerGroup struct also fixed the update order bug causing the segment timer to be 1f behind what it should be --- src/mods/storytimer.cpp | 66 ++++++------------- ...storytimer.cpp\357\200\272Zone.Identifier" | 3 + 2 files changed, 23 insertions(+), 46 deletions(-) create mode 100644 "src/mods/storytimer.cpp\357\200\272Zone.Identifier" diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 5ed364e3..d811a687 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -34,11 +34,6 @@ static bool s_entered_goal; struct TimerGroup { u32 segment; // the time taken to complete a world up until tape break on the last stage u32 full_world; // the time taken to complete a world until the fade to white on the last stage - // u32 split; // the time from the start of the run until tape break of the last stage of - // the world - u32 gameplay; - u32 non_gameplay; - u32 world_start_correction; }; static TimerGroup s_timer_group[WORLD_COUNT]; // each world has its own TimerGroup structure static bool s_can_lower_stage_counter; @@ -165,14 +160,6 @@ void tick() { // understand why that happens) s_timer_group[k].full_world += 1; } - if (s_completed_stages_world[k] <= 9) { - s_timer_group[k].segment = s_timer_group[k].full_world; - } else if (s_completed_stages_world[k] == STAGES_PER_WORLD && - mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { - // stop world k's segment timer on tape break of the last stage of the world; we - // need to correct by 2f since SMD_GAME_GOAL_INIT happens 2f after tape break - s_timer_group[k].segment += -2; - } if (is_on_spin_in || is_on_exit_game || is_on_fallout || is_timeover) { // increment the timer during every frame on spin in, exit game, fallout, and @@ -184,7 +171,7 @@ void tick() { // increment the timer every frame during gameplay s_timer_group[k].full_world += 1; } - if (is_postgoal && s_stage_fade_out_timer <= STAGE_FADE_OUT_TIME) { + if (is_postgoal) { // increment the timer every frame after game goal init happens; once you press // stage select, a separate 49 frame timer is started (fade out from stage // select to the first completely white frame takes 49 frames). once the timer @@ -206,35 +193,23 @@ void tick() { if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && s_completed_stages % STAGES_PER_WORLD != 0) { - // need to add 2 frames to the timer when stage selecting to the 10 ball screen, + // need to add 1 frame to the timer when stage selecting to the 10 ball screen, // but don't correct if on the last stage of a world since the next frame the // timer should increment on is covered by s_world_start_timer_correction - s_timer_group[k].full_world += 2; + // NOTE: change back to 2 if I add the stage fade out timer back in + s_timer_group[k].full_world += 1; } - /* - // this only gets set to 2 when you enter world k; this is needed since otherwise - // the timer will not capture the first 2f of the 10 ball spin in when entering - // a new world - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_timer_group[k].world_start_correction = 2; + if (s_completed_stages_world[k] <= 9) { + s_timer_group[k].segment = s_timer_group[k].full_world; + } else if (s_completed_stages_world[k] == STAGES_PER_WORLD && + mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { + // stop world k's segment timer on tape break of the last stage of the world; we + // need to correct by 2f since SMD_GAME_GOAL_INIT happens 2f after tape break + s_timer_group[k].segment += -2; } - */ - } - } - /* - // s_timer_group[k].split is just the fullgame time at tape break on the last stage of world k; - // to calculate this, just add s_timer_group[j].full_world (j Date: Sat, 23 Dec 2023 00:31:42 -0600 Subject: [PATCH 32/45] simplified code for the number of completed stages --- src/mods/storytimer.cpp | 92 ++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 57 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index d811a687..788f30f7 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -26,7 +26,6 @@ static constexpr s32 SEGMENT_TIMER_LOCATION_X = 30 + 24; static constexpr s32 SEGMENT_TIMER_TEXT_OFFSET = 44; static constexpr s32 IW_TIME_LOCATION_X = 42 + 24; static constexpr s32 IW_TIME_TEXT_OFFSET = 32; -static constexpr s32 STAGE_FADE_OUT_TIME = 49; static constexpr u32 WORLD_START_CORRECTION = 2; static constexpr s32 WORLD_COUNT = 10; static constexpr s32 STAGES_PER_WORLD = 10; @@ -34,11 +33,10 @@ static bool s_entered_goal; struct TimerGroup { u32 segment; // the time taken to complete a world up until tape break on the last stage u32 full_world; // the time taken to complete a world until the fade to white on the last stage + // char timer_str[32]; }; static TimerGroup s_timer_group[WORLD_COUNT]; // each world has its own TimerGroup structure static bool s_can_lower_stage_counter; -static bool s_start_stage_fade_out_timer; -static u32 s_stage_fade_out_timer; static s32 s_completed_stages; // the completed stages for the whole run static s32 s_completed_stages_world[WORLD_COUNT]; // the completed stages in world k static bool s_display_segment_timer; @@ -55,8 +53,6 @@ void on_goal_entry() { static void reset_timer() { s_can_lower_stage_counter = false; s_completed_stages = 0; - s_start_stage_fade_out_timer = false; - s_stage_fade_out_timer = 0; for (s32 k = 0; k < WORLD_COUNT; k++) { s_timer_group[k] = {}; s_completed_stages_world[k] = 0; @@ -70,32 +66,13 @@ void tick() { reset_timer(); } + // old code for s_completed_stages bool paused_now = *reinterpret_cast(0x805BC474) & 8; - // for later use, it's useful to record how many stages we've completed - // increment the completed stages by 1 during the init - // need to check that the game is not paused to ensure the counter only goes up by 1 + u32 sum = 0; for (s32 k = 0; k < WORLD_COUNT; k++) { - if (mkb::scen_info.world == k) { - if (!paused_now && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT) { - s_completed_stages_world[k] += 1; - s_can_lower_stage_counter = true; - } - - // if you retry after SMD_GAME_GOAL_INIT but before returning to the stage select - // screen, lower the counter by exactly 1 - if (s_can_lower_stage_counter && mkb::sub_mode == mkb::SMD_GAME_READY_INIT) { - s_completed_stages_world[k] += -1; - s_can_lower_stage_counter = false; - } - - // once you leave a stage, set this to false to ensure the completed stage count is not - // lowered when entering spin in on the next stage - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { - s_can_lower_stage_counter = false; - } - } - s_completed_stages += s_completed_stages_world[k]; + sum += mkb::get_world_unbeaten_stage_count(k); } + s_completed_stages = sum; // for later, it's useful to record what submodes correspond to spin in, gameplay, etc. // splitting up the timer this way also makes it easier in the future if I decide to implement @@ -133,22 +110,6 @@ void tick() { bool is_timeover = (mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN); - // this code is used to halt the timer once the screen becomes completely white when stage - // selecting out of a level - if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && - mkb::g_current_focused_pause_menu_entry == 4 && pad::button_pressed(mkb::PAD_BUTTON_A) && - is_postgoal) { - // stage select is on line 4 of the pause menu (top line is line 0) - s_start_stage_fade_out_timer = true; - } else if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_start_stage_fade_out_timer = false; - } - if (s_start_stage_fade_out_timer) { - s_stage_fade_out_timer += 1; - } else { - s_stage_fade_out_timer = 0; - } - for (s32 k = 0; k < WORLD_COUNT; k++) { if (mkb::scen_info.world == k) { if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { @@ -200,9 +161,10 @@ void tick() { s_timer_group[k].full_world += 1; } - if (s_completed_stages_world[k] <= 9) { + if (mkb::get_world_unbeaten_stage_count(k) < 9 || + (mkb::get_world_unbeaten_stage_count(k) == 9 && !is_postgoal)) { s_timer_group[k].segment = s_timer_group[k].full_world; - } else if (s_completed_stages_world[k] == STAGES_PER_WORLD && + } else if (mkb::get_world_unbeaten_stage_count(k) == 9 && mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { // stop world k's segment timer on tape break of the last stage of the world; we // need to correct by 2f since SMD_GAME_GOAL_INIT happens 2f after tape break @@ -220,19 +182,25 @@ void disp() { } bool is_between_worlds = false; - if ((s_completed_stages % STAGES_PER_WORLD == 0) && s_completed_stages != 0 && - mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { + if ((s_completed_stages % STAGES_PER_WORLD == 9) && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { is_between_worlds = true; } else if ((s_completed_stages % STAGES_PER_WORLD == 0 && - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) || - s_completed_stages % STAGES_PER_WORLD != 0) { + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) /*|| + s_completed_stages % STAGES_PER_WORLD != 0 */) { // no longer "between worlds" if you enter the next world's 10 ball screen, or if you break // the tape on the last stage of the current world, but retry is_between_worlds = false; } - bool is_run_complete = - (mkb::scen_info.world == 9 && s_completed_stages_world[9] == STAGES_PER_WORLD); + bool is_postgoal = + (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN || + mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_INIT || + mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_MAIN || + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN); + + bool is_run_complete = (mkb::scen_info.world == 9 && + ((mkb::get_world_unbeaten_stage_count(9) == 9 && is_postgoal) || + mkb::get_world_unbeaten_stage_count(9) == 10)); // move the position of the fullgame timer if the death counter is on u32 fullgame_timer_location_y = 2; @@ -355,13 +323,23 @@ void disp() { draw::WHITE); } - // debugging - - timerdisp::draw_timer(450, 1, IW_TIME_TEXT_OFFSET, "dbg:", s_timer_group[0].full_world, 0, - false, false, draw::WHITE); + /* + for (s32 k = 0; k < 2; k++) { + mkb::sprintf(s_timer_group[k].timer_str, "W%d: %s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", + k, split[k], segment[k]); + draw::debug_text("%s", s_timer_group[k].timer_str); + } + */ - timerdisp::draw_timer(450, 2, IW_TIME_TEXT_OFFSET, "dbg:", s_timer_group[0].segment, 0, false, + // debugging + /* + timerdisp::draw_timer(450, 1, IW_TIME_TEXT_OFFSET, "dbg:", 60 * s_completed_stages, 0, false, false, draw::WHITE); + + timerdisp::draw_timer(450, 2, IW_TIME_TEXT_OFFSET, + "dbg:", 60 * mkb::get_world_unbeaten_stage_count(1), 0, false, false, + draw::WHITE); + */ } } // namespace storytimer \ No newline at end of file From bf4555a7b552ff6a7f052d5c3ba5e0c521711e10 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sat, 23 Dec 2023 00:35:00 -0600 Subject: [PATCH 33/45] removed the s_completed_stages_world array --- src/mods/storytimer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 788f30f7..c6ad981c 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -37,8 +37,7 @@ struct TimerGroup { }; static TimerGroup s_timer_group[WORLD_COUNT]; // each world has its own TimerGroup structure static bool s_can_lower_stage_counter; -static s32 s_completed_stages; // the completed stages for the whole run -static s32 s_completed_stages_world[WORLD_COUNT]; // the completed stages in world k +static s32 s_completed_stages; // the completed stages for the whole run static bool s_display_segment_timer; u32 get_completed_stagecount() { return s_completed_stages; } @@ -55,7 +54,6 @@ static void reset_timer() { s_completed_stages = 0; for (s32 k = 0; k < WORLD_COUNT; k++) { s_timer_group[k] = {}; - s_completed_stages_world[k] = 0; } } From 91e455804e9092e2e2815ac1f20bec41d376231c Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sat, 23 Dec 2023 00:44:44 -0600 Subject: [PATCH 34/45] =?UTF-8?q?Delete=20storytimer.cpp=EF=80=BAZone.Iden?= =?UTF-8?q?tifier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "src/mods/storytimer.cpp\357\200\272Zone.Identifier" | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 "src/mods/storytimer.cpp\357\200\272Zone.Identifier" diff --git "a/src/mods/storytimer.cpp\357\200\272Zone.Identifier" "b/src/mods/storytimer.cpp\357\200\272Zone.Identifier" deleted file mode 100644 index 43a1a01e..00000000 --- "a/src/mods/storytimer.cpp\357\200\272Zone.Identifier" +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=https://github.com/ From 7b0cb909380d237584abdbc3077585bf6e4557b4 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sat, 23 Dec 2023 01:11:23 -0600 Subject: [PATCH 35/45] removed unused variables --- src/mods/storytimer.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index c6ad981c..567b1e47 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -36,9 +36,7 @@ struct TimerGroup { // char timer_str[32]; }; static TimerGroup s_timer_group[WORLD_COUNT]; // each world has its own TimerGroup structure -static bool s_can_lower_stage_counter; -static s32 s_completed_stages; // the completed stages for the whole run -static bool s_display_segment_timer; +static s32 s_completed_stages; // the completed stages for the whole run u32 get_completed_stagecount() { return s_completed_stages; } @@ -50,7 +48,6 @@ void on_goal_entry() { // before starting the run, there are several values we zero static void reset_timer() { - s_can_lower_stage_counter = false; s_completed_stages = 0; for (s32 k = 0; k < WORLD_COUNT; k++) { s_timer_group[k] = {}; @@ -64,8 +61,8 @@ void tick() { reset_timer(); } - // old code for s_completed_stages bool paused_now = *reinterpret_cast(0x805BC474) & 8; + u32 sum = 0; for (s32 k = 0; k < WORLD_COUNT; k++) { sum += mkb::get_world_unbeaten_stage_count(k); @@ -288,7 +285,6 @@ void disp() { case TimerOptions::EndOfRun: break; case TimerOptions::DontShow: - s_display_segment_timer = false; break; } From fd65cb3fe0f7bf80d7df1e35a1b79225eef3fcbd Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Wed, 27 Dec 2023 23:44:25 -0600 Subject: [PATCH 36/45] rewrote end of run segment timer code using mkb::sprintf --- src/mods/deathcounter.cpp | 5 +- src/mods/storytimer.cpp | 111 ++++++++++++++++++++++++++------------ 2 files changed, 81 insertions(+), 35 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index 2755c5ff..a1c3826b 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -69,8 +69,9 @@ void tick() { */ // first framing should not increase the death counter, and retrying after breaking the tape - // should not increase it either to do: however, if you retry after breaking the tape on the - // very first frame (so the frame before goal init), it does count as a death when it should not + // should not increase it either + // to do: however, if you retry after breaking the tape on the very first frame (so the frame + // before goal init), it does count as a death when it should not if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { s_can_die = false; diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 567b1e47..e72ce914 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -29,6 +29,9 @@ static constexpr s32 IW_TIME_TEXT_OFFSET = 32; static constexpr u32 WORLD_START_CORRECTION = 2; static constexpr s32 WORLD_COUNT = 10; static constexpr s32 STAGES_PER_WORLD = 10; +static constexpr u32 SECOND_FRAMES = 60; +static constexpr u32 MINUTE_FRAMES = SECOND_FRAMES * 60; +static constexpr u32 HOUR_FRAMES = MINUTE_FRAMES * 60; static bool s_entered_goal; struct TimerGroup { u32 segment; // the time taken to complete a world up until tape break on the last stage @@ -288,42 +291,84 @@ void disp() { break; } - // if the segment timer is enabled in any capacity, show all 10 split times + iw times after the - // tape is broken on the last stage - if (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != TimerOptions::DontShow && - is_run_complete) { - // haven't attempted the mkb::sprintf suggestion yet - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y, IW_TIME_TEXT_OFFSET, - "W1:", split[0], segment[0], true, false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 1, IW_TIME_TEXT_OFFSET, - "W2:", split[1], segment[1], true, false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 2, IW_TIME_TEXT_OFFSET, - "W3:", split[2], segment[2], true, false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 3, IW_TIME_TEXT_OFFSET, - "W4:", split[3], segment[3], true, false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 4, IW_TIME_TEXT_OFFSET, - "W5:", split[4], segment[4], true, false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 5, IW_TIME_TEXT_OFFSET, - "W6:", split[5], segment[5], true, false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 6, IW_TIME_TEXT_OFFSET, - "W7:", split[6], segment[6], true, false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 7, IW_TIME_TEXT_OFFSET, - "W8:", split[7], segment[7], true, false, draw::WHITE); - timerdisp::draw_timer(IW_TIME_LOCATION_X, segment_timer_location_y + 8, IW_TIME_TEXT_OFFSET, - "W9:", split[8], segment[8], true, false, draw::WHITE); - // use segment timer spacing for w10 since "W10" is 3 characters long, not 2 - timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y + 9, - SEGMENT_TIMER_TEXT_OFFSET, "W10:", split[9], segment[9], true, false, - draw::WHITE); + u32 split_hours[10] = {}; + u32 split_minutes[10] = {}; + u32 split_seconds[10] = {}; + u32 split_centiseconds[10] = {}; + + u32 segment_hours[10] = {}; + u32 segment_minutes[10] = {}; + u32 segment_seconds[10] = {}; + u32 segment_centiseconds[10] = {}; + + for (s32 k = 0; k < WORLD_COUNT; k++) { + split_hours[k] = split[k] / HOUR_FRAMES; + split_minutes[k] = split[k] % HOUR_FRAMES / MINUTE_FRAMES; + split_seconds[k] = split[k] % MINUTE_FRAMES / SECOND_FRAMES; + split_centiseconds[k] = (split[k] % SECOND_FRAMES) * (100 / 60); + + segment_hours[k] = segment[k] / HOUR_FRAMES; + segment_minutes[k] = segment[k] % HOUR_FRAMES / MINUTE_FRAMES; + segment_seconds[k] = segment[k] % MINUTE_FRAMES / SECOND_FRAMES; + segment_centiseconds[k] = (segment[k] % SECOND_FRAMES) * (100 / 60); } - /* - for (s32 k = 0; k < 2; k++) { - mkb::sprintf(s_timer_group[k].timer_str, "W%d: %s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", - k, split[k], segment[k]); - draw::debug_text("%s", s_timer_group[k].timer_str); + char timer_str[10][32] = {}; + + // if the segment timer is enabled in any capacity, after the tape is broken on the last stage, + // show all 10 split and iw times in the format "Wk: split[k] (segment[k])" + // to do: it is very likely that the current timer formatting text below is redundant given that + // there is similar code in timerdisp.cpp; for later: implement complex's suggestion for this + if (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != TimerOptions::DontShow && + is_run_complete) { + for (s32 k = 0; k < WORLD_COUNT; k++) { + u32 Y[k] = {}; + Y[k] = 24 + (segment_timer_location_y + k) * 16; // vertical position for the line of + // text "Wk: split[k] (segment[k])" + if (split_hours[k] > 0) { + if (segment_hours[k] > 0) { + mkb::sprintf(timer_str[k], "W%d: %d:%02d:%02d.%02d (%d:%02d:%02d.%02d)", k + 1, + split_hours[k], split_minutes[k], split_seconds[k], + split_centiseconds[k], segment_hours[k], segment_minutes[k], + segment_seconds[k], segment_centiseconds[k]); + draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", + timer_str[k]); + } else if (segment_minutes[k] > 0) { + mkb::sprintf(timer_str[k], "W%d: %d:%02d:%02d.%02d (%02d:%02d.%02d)", k + 1, + split_hours[k], split_minutes[k], split_seconds[k], + split_centiseconds[k], segment_minutes[k], segment_seconds[k], + segment_centiseconds[k]); + draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", + timer_str[k]); + } else { + mkb::sprintf(timer_str[k], "W%d: %d:%02d:%02d.%02d (%02d.%02d)", k + 1, + split_hours[k], split_minutes[k], split_seconds[k], + split_centiseconds[k], segment_seconds[k], + segment_centiseconds[k]); + draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", + timer_str[k]); + } + } else if (split_minutes[k] > 0) { + if (segment_minutes[k] > 0) { + mkb::sprintf(timer_str[k], "W%d: %02d:%02d.%02d (%02d:%02d.%02d)", k + 1, + split_minutes[k], split_seconds[k], split_centiseconds[k], + segment_minutes[k], segment_seconds[k], segment_centiseconds[k]); + draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", + timer_str[k]); + } else { + mkb::sprintf(timer_str[k], "W%d: %02d:%02d.%02d (%02d.%02d)", k + 1, + split_minutes[k], split_seconds[k], split_centiseconds[k], + segment_seconds[k], segment_centiseconds[k]); + draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", + timer_str[k]); + } + } else { + mkb::sprintf(timer_str[k], "W%d: %02d.%02d (%02d.%02d)", k + 1, split_seconds[k], + split_centiseconds[k], segment_seconds[k], segment_centiseconds[k]); + draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", timer_str[k]); + } + } } - */ // debugging /* From 6493439405a53722250c3cef3658784f9b57aaf0 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Thu, 28 Dec 2023 00:31:56 -0600 Subject: [PATCH 37/45] fixed some end of run segment formatting issue: the w1 split does not show up --- src/mods/storytimer.cpp | 57 +++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index e72ce914..3b7774d8 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -305,12 +305,12 @@ void disp() { split_hours[k] = split[k] / HOUR_FRAMES; split_minutes[k] = split[k] % HOUR_FRAMES / MINUTE_FRAMES; split_seconds[k] = split[k] % MINUTE_FRAMES / SECOND_FRAMES; - split_centiseconds[k] = (split[k] % SECOND_FRAMES) * (100 / 60); + split_centiseconds[k] = (split[k] % SECOND_FRAMES) * 100 / 60; segment_hours[k] = segment[k] / HOUR_FRAMES; segment_minutes[k] = segment[k] % HOUR_FRAMES / MINUTE_FRAMES; segment_seconds[k] = segment[k] % MINUTE_FRAMES / SECOND_FRAMES; - segment_centiseconds[k] = (segment[k] % SECOND_FRAMES) * (100 / 60); + segment_centiseconds[k] = (segment[k] % SECOND_FRAMES) * 100 / 60; } char timer_str[10][32] = {}; @@ -322,50 +322,35 @@ void disp() { if (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != TimerOptions::DontShow && is_run_complete) { for (s32 k = 0; k < WORLD_COUNT; k++) { - u32 Y[k] = {}; - Y[k] = 24 + (segment_timer_location_y + k) * 16; // vertical position for the line of - // text "Wk: split[k] (segment[k])" + u32 X[k] = {}; // horizontal position for the line of text "Wk: split[k] (segment[k])" + if (k != 9) { + X[k] = IW_TIME_LOCATION_X; + } else { + X[k] = + SEGMENT_TIMER_LOCATION_X; // change the position for world 10 because W10 takes + // up 3 characters instead of 2 like the rest + } + u32 Y[k] = {}; // vertical position for the line of text "Wk: split[k] (segment[k])" + Y[k] = 24 + (segment_timer_location_y + k) * 16; if (split_hours[k] > 0) { if (segment_hours[k] > 0) { - mkb::sprintf(timer_str[k], "W%d: %d:%02d:%02d.%02d (%d:%02d:%02d.%02d)", k + 1, + mkb::sprintf(timer_str[k], "W%d:%d:%02d:%02d.%02d (%d:%02d:%02d.%02d)", k + 1, split_hours[k], split_minutes[k], split_seconds[k], split_centiseconds[k], segment_hours[k], segment_minutes[k], segment_seconds[k], segment_centiseconds[k]); - draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", - timer_str[k]); - } else if (segment_minutes[k] > 0) { - mkb::sprintf(timer_str[k], "W%d: %d:%02d:%02d.%02d (%02d:%02d.%02d)", k + 1, - split_hours[k], split_minutes[k], split_seconds[k], - split_centiseconds[k], segment_minutes[k], segment_seconds[k], - segment_centiseconds[k]); - draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", - timer_str[k]); + draw::debug_text(X[k], Y[k], draw::WHITE, "%s", timer_str[k]); } else { - mkb::sprintf(timer_str[k], "W%d: %d:%02d:%02d.%02d (%02d.%02d)", k + 1, + mkb::sprintf(timer_str[k], "W%d:%d:%02d:%02d.%02d (%02d:%02d.%02d)", k + 1, split_hours[k], split_minutes[k], split_seconds[k], - split_centiseconds[k], segment_seconds[k], + split_centiseconds[k], segment_minutes[k], segment_seconds[k], segment_centiseconds[k]); - draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", - timer_str[k]); - } - } else if (split_minutes[k] > 0) { - if (segment_minutes[k] > 0) { - mkb::sprintf(timer_str[k], "W%d: %02d:%02d.%02d (%02d:%02d.%02d)", k + 1, - split_minutes[k], split_seconds[k], split_centiseconds[k], - segment_minutes[k], segment_seconds[k], segment_centiseconds[k]); - draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", - timer_str[k]); - } else { - mkb::sprintf(timer_str[k], "W%d: %02d:%02d.%02d (%02d.%02d)", k + 1, - split_minutes[k], split_seconds[k], split_centiseconds[k], - segment_seconds[k], segment_centiseconds[k]); - draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", - timer_str[k]); + draw::debug_text(X[k], Y[k], draw::WHITE, "%s", timer_str[k]); } } else { - mkb::sprintf(timer_str[k], "W%d: %02d.%02d (%02d.%02d)", k + 1, split_seconds[k], - split_centiseconds[k], segment_seconds[k], segment_centiseconds[k]); - draw::debug_text(SEGMENT_TIMER_LOCATION_X, Y[k], draw::WHITE, "%s", timer_str[k]); + mkb::sprintf(timer_str[k], "W%d:%02d:%02d.%02d (%02d:%02d.%02d)", k + 1, + split_minutes[k], split_seconds[k], split_centiseconds[k], + segment_minutes[k], segment_seconds[k], segment_centiseconds[k]); + draw::debug_text(X[k], Y[k], draw::WHITE, "%s", timer_str[k]); } } } From 3f13d8be599aeedb049c4dc72838071583f3bfc4 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Thu, 28 Dec 2023 00:44:53 -0600 Subject: [PATCH 38/45] fixed the w1 not showing issue --- src/mods/storytimer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 3b7774d8..015a2cff 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -322,7 +322,7 @@ void disp() { if (TimerOptions(pref::get(pref::U8Pref::SegmentTimerOptions)) != TimerOptions::DontShow && is_run_complete) { for (s32 k = 0; k < WORLD_COUNT; k++) { - u32 X[k] = {}; // horizontal position for the line of text "Wk: split[k] (segment[k])" + u32 X[10] = {}; // horizontal position for the line of text "Wk: split[k] (segment[k])" if (k != 9) { X[k] = IW_TIME_LOCATION_X; } else { From 4e4ab774b43bf8fe8141fb325be63445d988a59b Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Thu, 28 Dec 2023 01:54:36 -0600 Subject: [PATCH 39/45] improved code for stopping the segment timer the segment timer now stops on the goal tape break frame instead of using SMD_GOAL_INIT and subtracting 2 frames manually --- src/mods/storytimer.cpp | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 015a2cff..57954f52 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -10,6 +10,7 @@ #include "utils/draw.h" #include "utils/patch.h" #include "utils/timerdisp.h" +#include "validate.h" namespace storytimer { @@ -36,7 +37,6 @@ static bool s_entered_goal; struct TimerGroup { u32 segment; // the time taken to complete a world up until tape break on the last stage u32 full_world; // the time taken to complete a world until the fade to white on the last stage - // char timer_str[32]; }; static TimerGroup s_timer_group[WORLD_COUNT]; // each world has its own TimerGroup structure static s32 s_completed_stages; // the completed stages for the whole run @@ -45,7 +45,13 @@ u32 get_completed_stagecount() { return s_completed_stages; } void on_goal_entry() { if (!validate::has_entered_goal()) { - // no code yet + // the call to has_entered_goal lets us stop the segment timer on tape break on the last + // stage of a world (as opposed to using SMD_GOAL_INIT and manually subtracting 2 frames) + for (s32 k = 0; k < WORLD_COUNT; k++) { + if (mkb::scen_info.world == k && mkb::get_world_unbeaten_stage_count(k) == 9) { + s_timer_group[k].segment = s_timer_group[k].full_world; + } + } } } @@ -110,6 +116,7 @@ void tick() { for (s32 k = 0; k < WORLD_COUNT; k++) { if (mkb::scen_info.world == k) { + /* if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { // need to add 1 additional frame to the timer during spin in // putting this code before the code below for s_timer_group[k].full_world makes @@ -119,6 +126,7 @@ void tick() { // understand why that happens) s_timer_group[k].full_world += 1; } + */ if (is_on_spin_in || is_on_exit_game || is_on_fallout || is_timeover) { // increment the timer during every frame on spin in, exit game, fallout, and @@ -159,6 +167,17 @@ void tick() { s_timer_group[k].full_world += 1; } + if (mkb::get_world_unbeaten_stage_count(k) < 9 || + (mkb::get_world_unbeaten_stage_count(k) == 9 && + (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || + mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE || + mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || is_on_spin_in))) { + // the case where 9 stages in the world are completed and you are in gameplay is + // handled by the call to validate::has_entered_goal() earlier + s_timer_group[k].segment = s_timer_group[k].full_world; + } + /* if (mkb::get_world_unbeaten_stage_count(k) < 9 || (mkb::get_world_unbeaten_stage_count(k) == 9 && !is_postgoal)) { s_timer_group[k].segment = s_timer_group[k].full_world; @@ -168,6 +187,7 @@ void tick() { // need to correct by 2f since SMD_GAME_GOAL_INIT happens 2f after tape break s_timer_group[k].segment += -2; } + */ } } } @@ -313,7 +333,8 @@ void disp() { segment_centiseconds[k] = (segment[k] % SECOND_FRAMES) * 100 / 60; } - char timer_str[10][32] = {}; + char timer_str[10][32] = {}; // timer_str[k-1] is the formatted text for "Wk: split[k] + // (segment[k])" // if the segment timer is enabled in any capacity, after the tape is broken on the last stage, // show all 10 split and iw times in the format "Wk: split[k] (segment[k])" @@ -357,12 +378,11 @@ void disp() { // debugging /* - timerdisp::draw_timer(450, 1, IW_TIME_TEXT_OFFSET, "dbg:", 60 * s_completed_stages, 0, false, - false, draw::WHITE); + timerdisp::draw_timer(450, 1, IW_TIME_TEXT_OFFSET, "dbg:", 60 * s_timer_group[0].full_world, 0, + false, false, draw::WHITE); - timerdisp::draw_timer(450, 2, IW_TIME_TEXT_OFFSET, - "dbg:", 60 * mkb::get_world_unbeaten_stage_count(1), 0, false, false, - draw::WHITE); + timerdisp::draw_timer(450, 2, IW_TIME_TEXT_OFFSET, "dbg:", s_timer_group[0].segment, 0, false, + false, draw::WHITE); */ } From edb2f4c2e9f6381efde95367004a0aac016e8830 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Thu, 28 Dec 2023 23:24:59 -0600 Subject: [PATCH 40/45] clean up --- src/mods/deathcounter.cpp | 32 +--------- src/mods/deathcounter.h | 1 - src/mods/storytimer.cpp | 130 +++++++++++--------------------------- src/mods/storytimer.h | 1 - src/systems/main.cpp | 4 +- 5 files changed, 40 insertions(+), 128 deletions(-) diff --git a/src/mods/deathcounter.cpp b/src/mods/deathcounter.cpp index a1c3826b..7b968937 100644 --- a/src/mods/deathcounter.cpp +++ b/src/mods/deathcounter.cpp @@ -17,12 +17,6 @@ namespace deathcounter { static bool s_can_die; static u32 s_death_count; -void on_goal_entry() { - if (!validate::has_entered_goal()) { - s_can_die = false; - } -} - void tick() { // set the death count to 0 on the file select screen if (mkb::scen_info.mode == 5) { @@ -38,6 +32,8 @@ void tick() { storytimer::get_completed_stagecount() != 0) { s_can_die = true; } + } else if (validate::has_entered_goal()) { + s_can_die = false; } if (s_can_die && @@ -52,30 +48,6 @@ void tick() { s_can_die = false; // once the death counter is incremented, set this to false so we only // increment it by 1 } - - // bandaid fix for stardust bug - /* - if (s_can_die && - (mkb::sub_mode == mkb::SMD_GAME_READY_INIT || mkb::sub_mode == mkb::SMD_GAME_RINGOUT_INIT || - mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || - mkb::sub_mode == mkb::SMD_GAME_INTR_SEL_INIT)) { - // you can die either by retrying after dropping in, falling out, timing over, stage - // selecting after dropping in (but before breaking the tape), or exiting game after - // dropping in (but before breaking the tape) - s_death_count += 1; - s_can_die = false; // once the death counter is incremented, set this to false so we only - // increment it by 1 - } - */ - - // first framing should not increase the death counter, and retrying after breaking the tape - // should not increase it either - // to do: however, if you retry after breaking the tape on the very first frame (so the frame - // before goal init), it does count as a death when it should not - if (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) { - s_can_die = false; - } } void disp() { diff --git a/src/mods/deathcounter.h b/src/mods/deathcounter.h index e5f653fd..68d11abb 100644 --- a/src/mods/deathcounter.h +++ b/src/mods/deathcounter.h @@ -2,7 +2,6 @@ namespace deathcounter { -void on_goal_entry(); void tick(); void disp(); diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 57954f52..317da40a 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -33,7 +33,6 @@ static constexpr s32 STAGES_PER_WORLD = 10; static constexpr u32 SECOND_FRAMES = 60; static constexpr u32 MINUTE_FRAMES = SECOND_FRAMES * 60; static constexpr u32 HOUR_FRAMES = MINUTE_FRAMES * 60; -static bool s_entered_goal; struct TimerGroup { u32 segment; // the time taken to complete a world up until tape break on the last stage u32 full_world; // the time taken to complete a world until the fade to white on the last stage @@ -43,18 +42,6 @@ static s32 s_completed_stages; // the completed stages for the w u32 get_completed_stagecount() { return s_completed_stages; } -void on_goal_entry() { - if (!validate::has_entered_goal()) { - // the call to has_entered_goal lets us stop the segment timer on tape break on the last - // stage of a world (as opposed to using SMD_GOAL_INIT and manually subtracting 2 frames) - for (s32 k = 0; k < WORLD_COUNT; k++) { - if (mkb::scen_info.world == k && mkb::get_world_unbeaten_stage_count(k) == 9) { - s_timer_group[k].segment = s_timer_group[k].full_world; - } - } - } -} - // before starting the run, there are several values we zero static void reset_timer() { s_completed_stages = 0; @@ -70,8 +57,6 @@ void tick() { reset_timer(); } - bool paused_now = *reinterpret_cast(0x805BC474) & 8; - u32 sum = 0; for (s32 k = 0; k < WORLD_COUNT; k++) { sum += mkb::get_world_unbeaten_stage_count(k); @@ -79,8 +64,6 @@ void tick() { s_completed_stages = sum; // for later, it's useful to record what submodes correspond to spin in, gameplay, etc. - // splitting up the timer this way also makes it easier in the future if I decide to implement - // features such as menuing timeloss // submodes during spin in bool is_on_spin_in = @@ -114,80 +97,41 @@ void tick() { bool is_timeover = (mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_INIT || mkb::sub_mode == mkb::SMD_GAME_TIMEOVER_MAIN); + // stage select states on the 10 ball screen *not* including the transition after the a press + // input. this transition is not included in the timer because even ignoring completely white + // frames, the time spent on mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be + // highly variable (up to over 40 frames sometimes!), so for the purpose of a loadless + // timer, it makes sense to cut this out + bool is_pre_load_in_stage_select = + (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || + mkb::g_storymode_stageselect_state == 3 || + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE); + for (s32 k = 0; k < WORLD_COUNT; k++) { if (mkb::scen_info.world == k) { - /* - if (mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT) { - // need to add 1 additional frame to the timer during spin in - // putting this code before the code below for s_timer_group[k].full_world makes - // the timer tick up more naturally when transitioning from the 10 ball screen - // to spin in, more specifically, this prevents the timer from skipping ahead - // for a few frames, then pausing for a few frames to even itself out (I don't - // understand why that happens) - s_timer_group[k].full_world += 1; - } - */ - - if (is_on_spin_in || is_on_exit_game || is_on_fallout || is_timeover) { - // increment the timer during every frame on spin in, exit game, fallout, and - // timeover - s_timer_group[k].full_world += 1; - } - - if (is_on_gameplay) { - // increment the timer every frame during gameplay - s_timer_group[k].full_world += 1; - } - if (is_postgoal) { - // increment the timer every frame after game goal init happens; once you press - // stage select, a separate 49 frame timer is started (fade out from stage - // select to the first completely white frame takes 49 frames). once the timer - // hits 49 frames, stop incrementing the timer until the 10 ball screen starts - // spinning in - s_timer_group[k].full_world += 1; - } - if (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || - mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE) { - // increment the timer every frame on the story mode stage select screen until - // the a press input; we do not include the transition time after pressing a - // afterwards. even ignoring completely white frames, the time spent on - // mkb::g_storymode_stageselect_state == mkb::STAGE_SELECTED can be highly - // variable (up to over 40 frames sometimes!), so for the purpose of a loadless - // timer, it makes sense to cut this out from the timer + if (is_on_spin_in || is_on_exit_game || is_on_fallout || is_timeover || + is_on_gameplay || is_postgoal || is_pre_load_in_stage_select) { + // increment the timer during every frame on spin in, exit game, fallout, + // timeover, gameplay, and every frame after breaking the tape until (but not + // including) the load back to the 10 ball screen. In addition, increment the timer + // on every frame on the 10 ball screen until the a press input s_timer_group[k].full_world += 1; } - - if (mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN && - s_completed_stages % STAGES_PER_WORLD != 0) { - // need to add 1 frame to the timer when stage selecting to the 10 ball screen, - // but don't correct if on the last stage of a world since the next frame the - // timer should increment on is covered by s_world_start_timer_correction - // NOTE: change back to 2 if I add the stage fade out timer back in + if (s_completed_stages % STAGES_PER_WORLD != 9 && + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN) { + // need to add 1 frame to the timer when stage selecting to the 10 ball screen + // since the first non-completely white frame is not included in + // mkb::STAGE_SELECT_INTRO_SEQUENCE; don't include the last stage of a world + // since that missing frame is handled by the world start correction s_timer_group[k].full_world += 1; } - if (mkb::get_world_unbeaten_stage_count(k) < 9 || (mkb::get_world_unbeaten_stage_count(k) == 9 && - (mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE || - mkb::g_storymode_stageselect_state == 3 || - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_IDLE || - mkb::sub_mode == mkb::SMD_GAME_FIRST_INIT || is_on_spin_in))) { - // the case where 9 stages in the world are completed and you are in gameplay is - // handled by the call to validate::has_entered_goal() earlier - s_timer_group[k].segment = s_timer_group[k].full_world; - } - /* - if (mkb::get_world_unbeaten_stage_count(k) < 9 || - (mkb::get_world_unbeaten_stage_count(k) == 9 && !is_postgoal)) { + (is_pre_load_in_stage_select || is_on_spin_in || !validate::has_entered_goal()))) { + // stop incrementing the segment timer once the tape is broken on the last stage of + // the world s_timer_group[k].segment = s_timer_group[k].full_world; - } else if (mkb::get_world_unbeaten_stage_count(k) == 9 && - mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT && !paused_now) { - // stop world k's segment timer on tape break of the last stage of the world; we - // need to correct by 2f since SMD_GAME_GOAL_INIT happens 2f after tape break - s_timer_group[k].segment += -2; } - */ } } } @@ -199,23 +143,23 @@ void disp() { return; } + bool is_postgoal = + (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN || + mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_INIT || + mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_MAIN || + mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN); + bool is_between_worlds = false; - if ((s_completed_stages % STAGES_PER_WORLD == 9) && mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN) { + if ((s_completed_stages % STAGES_PER_WORLD == 9) && is_postgoal) { is_between_worlds = true; } else if ((s_completed_stages % STAGES_PER_WORLD == 0 && - mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) /*|| - s_completed_stages % STAGES_PER_WORLD != 0 */) { + mkb::g_storymode_stageselect_state == mkb::STAGE_SELECT_INTRO_SEQUENCE) || + s_completed_stages % STAGES_PER_WORLD != 0) { // no longer "between worlds" if you enter the next world's 10 ball screen, or if you break // the tape on the last stage of the current world, but retry is_between_worlds = false; } - bool is_postgoal = - (mkb::sub_mode == mkb::SMD_GAME_GOAL_INIT || mkb::sub_mode == mkb::SMD_GAME_GOAL_MAIN || - mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_INIT || - mkb::sub_mode == mkb::SMD_GAME_GOAL_REPLAY_MAIN || - mkb::sub_mode == mkb::SMD_GAME_SCENARIO_RETURN); - bool is_run_complete = (mkb::scen_info.world == 9 && ((mkb::get_world_unbeaten_stage_count(9) == 9 && is_postgoal) || mkb::get_world_unbeaten_stage_count(9) == 10)); @@ -243,7 +187,6 @@ void disp() { } // at the start of each world, we need to correct the timer by 1 frame - u32 full_world[10] = {}; u32 segment[10] = {}; @@ -258,7 +201,6 @@ void disp() { // split[k] is just the fullgame time at tape break on the last stage of world k; // to calculate this, just add full_world[j] (j Date: Sun, 31 Dec 2023 22:58:17 -0600 Subject: [PATCH 41/45] reverted draw_timer function to only draw one timer --- src/mods/cmseg.cpp | 2 +- src/mods/iw.cpp | 2 +- src/mods/storytimer.cpp | 36 +++++++++++----- src/mods/timer.cpp | 4 +- src/utils/timerdisp.cpp | 92 +++++++++-------------------------------- src/utils/timerdisp.h | 3 +- 6 files changed, 52 insertions(+), 87 deletions(-) diff --git a/src/mods/cmseg.cpp b/src/mods/cmseg.cpp index 36ada7e5..12e3fb5f 100644 --- a/src/mods/cmseg.cpp +++ b/src/mods/cmseg.cpp @@ -365,7 +365,7 @@ void disp() { color = draw::GOLD; else color = draw::WHITE; - timerdisp::draw_timer(380, 0, 44, "SEG:", static_cast(s_seg_time), 0, false, false, draw::WHITE); + timerdisp::draw_timer(380, 0, 44, "SEG:", static_cast(s_seg_time), false, draw::WHITE); } } diff --git a/src/mods/iw.cpp b/src/mods/iw.cpp index 135a85a8..47786957 100644 --- a/src/mods/iw.cpp +++ b/src/mods/iw.cpp @@ -123,6 +123,6 @@ void disp() { mkb::main_game_mode != mkb::STORY_MODE || !main::currently_playing_iw || freecam::should_hide_hud()) return; - timerdisp::draw_timer(392, 0, 32, "IW:", static_cast(s_iw_time), 0, false, false, draw::WHITE); + timerdisp::draw_timer(392, 0, 32, "IW:", static_cast(s_iw_time), false, draw::WHITE); } } // namespace iw diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 317da40a..19332ea0 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -39,6 +39,9 @@ struct TimerGroup { }; static TimerGroup s_timer_group[WORLD_COUNT]; // each world has its own TimerGroup structure static s32 s_completed_stages; // the completed stages for the whole run +static s32 s_time_on_tape_break; // debugging/testing purposes +static s32 s_time_on_intro_sequence; // debugging/testing purposes +static s32 s_time_can_press_a; // debugging/testing purposes u32 get_completed_stagecount() { return s_completed_stages; } @@ -214,8 +217,8 @@ void disp() { if (display_story_timer) { timerdisp::draw_timer(FULLGAME_TIMER_LOCATION_X, fullgame_timer_location_y, - FULLGAME_TIMER_TEXT_OFFSET, "Time:", loadless_story_timer, 0, false, - false, draw::WHITE); + FULLGAME_TIMER_TEXT_OFFSET, "Time:", loadless_story_timer, false, + draw::WHITE); } // move the position of the segment timer depending on if the death counter and fullgame timer @@ -233,8 +236,8 @@ void disp() { for (s32 k = 0; k < WORLD_COUNT; k++) { if (mkb::scen_info.world == k && !is_run_complete) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y, - SEGMENT_TIMER_TEXT_OFFSET, "Seg:", segment[k], 0, false, - false, draw::WHITE); + SEGMENT_TIMER_TEXT_OFFSET, "Seg:", segment[k], false, + draw::WHITE); } } break; @@ -242,8 +245,8 @@ void disp() { for (s32 k = 0; k < WORLD_COUNT; k++) { if (is_between_worlds && mkb::scen_info.world == k && k != 9) { timerdisp::draw_timer(SEGMENT_TIMER_LOCATION_X, segment_timer_location_y, - SEGMENT_TIMER_TEXT_OFFSET, "Seg:", segment[k], 0, false, - false, draw::WHITE); + SEGMENT_TIMER_TEXT_OFFSET, "Seg:", segment[k], false, + draw::WHITE); } } break; @@ -319,12 +322,25 @@ void disp() { } // debugging + /* - timerdisp::draw_timer(450, 1, IW_TIME_TEXT_OFFSET, "dbg:", 60 * s_timer_group[0].full_world, 0, - false, false, draw::WHITE); + if (validate::has_entered_goal()) { + s_time_on_tape_break = loadless_story_timer; + } + if (mkb::g_storymode_stageselect_state == 3) { + s_time_can_press_a = loadless_story_timer; + } + + u32 difference = s_time_can_press_a - s_time_on_tape_break; + + timerdisp::draw_timer(450, 1, SEGMENT_TIMER_TEXT_OFFSET, "dbg:", s_time_on_tape_break, false, + draw::WHITE); + + timerdisp::draw_timer(450, 2, SEGMENT_TIMER_TEXT_OFFSET, "dbg:", s_time_can_press_a, false, + draw::WHITE); - timerdisp::draw_timer(450, 2, IW_TIME_TEXT_OFFSET, "dbg:", s_timer_group[0].segment, 0, false, - false, draw::WHITE); + timerdisp::draw_timer(450, 3, SEGMENT_TIMER_TEXT_OFFSET, "dbg:", difference, false, + draw::WHITE); */ } diff --git a/src/mods/timer.cpp b/src/mods/timer.cpp index 6a6f71c9..593d2eec 100644 --- a/src/mods/timer.cpp +++ b/src/mods/timer.cpp @@ -57,11 +57,11 @@ void disp() { u32 row = 1; if (pref::get(pref::BoolPref::TimerShowRTA) && !freecam::should_hide_hud()) { - timerdisp::draw_timer(380, row++, 44, "RTA:", s_rta_timer, 0, false, true, draw::WHITE); + timerdisp::draw_timer(380, row++, 44, "RTA:", s_rta_timer, true, draw::WHITE); } if (pref::get(pref::BoolPref::TimerShowPause) && !freecam::should_hide_hud()) { - timerdisp::draw_timer(380, row++, 44, "PAU:", s_pause_timer, 0, false, true, draw::WHITE); + timerdisp::draw_timer(380, row++, 44, "PAU:", s_pause_timer, true, draw::WHITE); } switch (mkb::sub_mode) { diff --git a/src/utils/timerdisp.cpp b/src/utils/timerdisp.cpp index 168a72c4..b1522dd9 100644 --- a/src/utils/timerdisp.cpp +++ b/src/utils/timerdisp.cpp @@ -11,85 +11,33 @@ static constexpr u32 HOUR_FRAMES = MINUTE_FRAMES * 60; static constexpr s32 X = 378; static constexpr s32 Y = 24; -void draw_timer(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color){ - bool positive = frames_1 >= 0; - if (!positive) frames_1 = -frames_1; +void draw_timer(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames, + bool show_seconds_only, mkb::GXColor color) { + bool positive = frames >= 0; + if (!positive) frames = -frames; const char* sign = positive ? "" : "-"; - u32 hours_1 = frames_1 / HOUR_FRAMES; - u32 minutes_1 = frames_1 % HOUR_FRAMES / MINUTE_FRAMES; - u32 seconds_1 = frames_1 % MINUTE_FRAMES / SECOND_FRAMES; - u32 centiseconds_1 = (frames_1 % SECOND_FRAMES) * 100 / 60; - - u32 hours_2 = frames_2 / HOUR_FRAMES; - u32 minutes_2 = frames_2 % HOUR_FRAMES / MINUTE_FRAMES; - u32 seconds_2 = frames_2 % MINUTE_FRAMES / SECOND_FRAMES; - u32 centiseconds_2 = (frames_2 % SECOND_FRAMES) * 100 / 60; + u32 hours = frames / HOUR_FRAMES; + u32 minutes = frames % HOUR_FRAMES / MINUTE_FRAMES; + u32 seconds = frames % MINUTE_FRAMES / SECOND_FRAMES; + u32 centiseconds = (frames % SECOND_FRAMES) * 100 / 60; s32 A = pos_x; - s32 a = A + text_offset; + s32 a = A + text_offset; s32 b = Y + (pos_y)*16; - if (show_second_argument == true){ - if (hours_1 > 0) { - if (hours_2 > 0 ) { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, - centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); - } else if (minutes_2 > 0) { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d (%s%02d:%02d.%02d)", sign, hours_1, minutes_1, seconds_1, - centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); - } else { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d (%s%02d.%02d)", sign, hours_1, minutes_1, seconds_1, - centiseconds_1, sign, seconds_2, centiseconds_2); - } - } else if (minutes_1 > 0) { - if (hours_2 > 0) { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%02d:%02d.%02d (%s%d:%02d:%02d.%02d)", sign, minutes_1, seconds_1, - centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); - } else if (minutes_2 > 0) { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%02d:%02d.%02d (%s%02d:%02d.%02d)", sign, minutes_1, seconds_1, - centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); - } else { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%02d:%02d.%02d (%s%02d.%02d)", sign, minutes_1, seconds_1, - centiseconds_1, sign, seconds_2, centiseconds_2); - } - - } else { - if (hours_2 > 0) { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%d.%02d (%s%d:%02d:%02d.%02d)", sign, seconds_1, - centiseconds_1, sign, hours_2, minutes_2, seconds_2, centiseconds_2); - } else if (minutes_2 > 0) { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%d.%02d (%s%d:%02d.%02d)", sign, seconds_1, - centiseconds_1, sign, minutes_2, seconds_2, centiseconds_2); - } else { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%d.%02d (%s%d.%02d)", sign, seconds_1, - centiseconds_1, sign, seconds_2, centiseconds_2); - } - } + if (hours > 0 && !show_seconds_only) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d", sign, hours, minutes, seconds, + centiseconds); + } else if (minutes > 0 && !show_seconds_only) { + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%02d:%02d.%02d", sign, minutes, seconds, centiseconds); } else { - if (hours_1 > 0 && !show_seconds_only) { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%d:%02d:%02d.%02d", sign, hours_1, minutes_1, seconds_1, - centiseconds_1); - } else if (minutes_1 > 0 && !show_seconds_only) { - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%02d:%02d.%02d", sign, minutes_1, seconds_1, - centiseconds_1); - } else { - u32 total_seconds_1 = - seconds_1 + (minutes_1 * MINUTE_FRAMES + hours_1 * HOUR_FRAMES) / SECOND_FRAMES; - draw::debug_text(A, b, color, prefix); - draw::debug_text(a, b, color, "%s%02d.%02d", sign, total_seconds_1, centiseconds_1); - } + u32 total_seconds = + seconds + (minutes * MINUTE_FRAMES + hours * HOUR_FRAMES) / SECOND_FRAMES; + draw::debug_text(A, b, color, prefix); + draw::debug_text(a, b, color, "%s%02d.%02d", sign, total_seconds, centiseconds); } } diff --git a/src/utils/timerdisp.h b/src/utils/timerdisp.h index 1892045a..503a5cfa 100644 --- a/src/utils/timerdisp.h +++ b/src/utils/timerdisp.h @@ -4,7 +4,8 @@ namespace timerdisp { -void draw_timer(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, s32 frames_2, bool show_second_argument, bool show_seconds_only, mkb::GXColor color); +void draw_timer(u32 pos_x, u32 pos_y, u32 text_offset, const char* prefix, s32 frames_1, + bool show_seconds_only, mkb::GXColor color); void draw_subtick_timer(s32 frames, const char* prefix, u32 row, mkb::GXColor color, bool show_minutes, u32 framesave, bool extra_precision); void draw_percentage(s32 fsave, const char* prefix, u32 row, mkb::GXColor color); From 058e0374bcbcde450c3f0f830a0bbde7cdaa03ae Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sun, 31 Dec 2023 23:44:15 -0600 Subject: [PATCH 42/45] debugging stuff --- src/mods/storytimer.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index 19332ea0..d1f3c6ce 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -42,6 +42,7 @@ static s32 s_completed_stages; // the completed stages for the w static s32 s_time_on_tape_break; // debugging/testing purposes static s32 s_time_on_intro_sequence; // debugging/testing purposes static s32 s_time_can_press_a; // debugging/testing purposes +static s32 s_time_on_a_press; // debugging/testing purposes u32 get_completed_stagecount() { return s_completed_stages; } @@ -324,22 +325,34 @@ void disp() { // debugging /* - if (validate::has_entered_goal()) { + if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && + mkb::g_current_focused_pause_menu_entry == 4 && pad::button_pressed(mkb::PAD_BUTTON_A) && + is_postgoal) { + s_time_on_a_press = loadless_story_timer; + } + if (validate::has_entered_goal() && mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { s_time_on_tape_break = loadless_story_timer; } if (mkb::g_storymode_stageselect_state == 3) { s_time_can_press_a = loadless_story_timer; } - u32 difference = s_time_can_press_a - s_time_on_tape_break; + u32 difference_1 = s_time_can_press_a - s_time_on_tape_break; // stardust + u32 difference_2 = s_time_can_press_a - s_time_on_a_press; // regular menuing + + timerdisp::draw_timer(450, 1, SEGMENT_TIMER_TEXT_OFFSET, "fin:", s_time_on_tape_break, false, + draw::WHITE); + + timerdisp::draw_timer(450, 2, SEGMENT_TIMER_TEXT_OFFSET, "can:", s_time_can_press_a, false, + draw::WHITE); - timerdisp::draw_timer(450, 1, SEGMENT_TIMER_TEXT_OFFSET, "dbg:", s_time_on_tape_break, false, + timerdisp::draw_timer(450, 3, SEGMENT_TIMER_TEXT_OFFSET, "sel:", s_time_on_a_press, false, draw::WHITE); - timerdisp::draw_timer(450, 2, SEGMENT_TIMER_TEXT_OFFSET, "dbg:", s_time_can_press_a, false, + timerdisp::draw_timer(450, 4, SEGMENT_TIMER_TEXT_OFFSET, "sta:", difference_1, false, draw::WHITE); - timerdisp::draw_timer(450, 3, SEGMENT_TIMER_TEXT_OFFSET, "dbg:", difference, false, + timerdisp::draw_timer(450, 5, SEGMENT_TIMER_TEXT_OFFSET, "reg:", difference_2, false, draw::WHITE); */ } From 1f4a237fb4faf05bd73c546a7b992dcd67848a46 Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Sun, 31 Dec 2023 23:45:51 -0600 Subject: [PATCH 43/45] removed debugging variables/cleanup --- src/mods/storytimer.cpp | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index d1f3c6ce..c436b261 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -39,10 +39,6 @@ struct TimerGroup { }; static TimerGroup s_timer_group[WORLD_COUNT]; // each world has its own TimerGroup structure static s32 s_completed_stages; // the completed stages for the whole run -static s32 s_time_on_tape_break; // debugging/testing purposes -static s32 s_time_on_intro_sequence; // debugging/testing purposes -static s32 s_time_can_press_a; // debugging/testing purposes -static s32 s_time_on_a_press; // debugging/testing purposes u32 get_completed_stagecount() { return s_completed_stages; } @@ -321,40 +317,6 @@ void disp() { } } } - - // debugging - - /* - if (mkb::pausemenu_type == mkb::PMT_STORY_PLAY && - mkb::g_current_focused_pause_menu_entry == 4 && pad::button_pressed(mkb::PAD_BUTTON_A) && - is_postgoal) { - s_time_on_a_press = loadless_story_timer; - } - if (validate::has_entered_goal() && mkb::sub_mode == mkb::SMD_GAME_PLAY_MAIN) { - s_time_on_tape_break = loadless_story_timer; - } - if (mkb::g_storymode_stageselect_state == 3) { - s_time_can_press_a = loadless_story_timer; - } - - u32 difference_1 = s_time_can_press_a - s_time_on_tape_break; // stardust - u32 difference_2 = s_time_can_press_a - s_time_on_a_press; // regular menuing - - timerdisp::draw_timer(450, 1, SEGMENT_TIMER_TEXT_OFFSET, "fin:", s_time_on_tape_break, false, - draw::WHITE); - - timerdisp::draw_timer(450, 2, SEGMENT_TIMER_TEXT_OFFSET, "can:", s_time_can_press_a, false, - draw::WHITE); - - timerdisp::draw_timer(450, 3, SEGMENT_TIMER_TEXT_OFFSET, "sel:", s_time_on_a_press, false, - draw::WHITE); - - timerdisp::draw_timer(450, 4, SEGMENT_TIMER_TEXT_OFFSET, "sta:", difference_1, false, - draw::WHITE); - - timerdisp::draw_timer(450, 5, SEGMENT_TIMER_TEXT_OFFSET, "reg:", difference_2, false, - draw::WHITE); - */ } } // namespace storytimer \ No newline at end of file From 99685358a0f229c73097e7d9a043cd397a99528b Mon Sep 17 00:00:00 2001 From: rehtrop Date: Mon, 8 Jan 2024 16:05:12 -0600 Subject: [PATCH 44/45] update scripts --- scripts/gen_compile_commands.py | 0 scripts/genfunc.py | 0 scripts/go.sh | 0 scripts/str2hex.py | 0 scripts/subtrees.sh | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/gen_compile_commands.py mode change 100644 => 100755 scripts/genfunc.py mode change 100644 => 100755 scripts/go.sh mode change 100644 => 100755 scripts/str2hex.py mode change 100644 => 100755 scripts/subtrees.sh diff --git a/scripts/gen_compile_commands.py b/scripts/gen_compile_commands.py old mode 100644 new mode 100755 diff --git a/scripts/genfunc.py b/scripts/genfunc.py old mode 100644 new mode 100755 diff --git a/scripts/go.sh b/scripts/go.sh old mode 100644 new mode 100755 diff --git a/scripts/str2hex.py b/scripts/str2hex.py old mode 100644 new mode 100755 diff --git a/scripts/subtrees.sh b/scripts/subtrees.sh old mode 100644 new mode 100755 From 941f8052121071557e4223f9527d5f5a40eb6f8a Mon Sep 17 00:00:00 2001 From: eddy0777 Date: Thu, 25 Jan 2024 00:03:10 -0600 Subject: [PATCH 45/45] minor things -removed unused variables -fixed error where split 1 was off by 1f --- src/mods/storytimer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mods/storytimer.cpp b/src/mods/storytimer.cpp index c436b261..e82a08b8 100644 --- a/src/mods/storytimer.cpp +++ b/src/mods/storytimer.cpp @@ -26,8 +26,6 @@ static constexpr s32 FULLGAME_TIMER_TEXT_OFFSET = 56; static constexpr s32 SEGMENT_TIMER_LOCATION_X = 30 + 24; static constexpr s32 SEGMENT_TIMER_TEXT_OFFSET = 44; static constexpr s32 IW_TIME_LOCATION_X = 42 + 24; -static constexpr s32 IW_TIME_TEXT_OFFSET = 32; -static constexpr u32 WORLD_START_CORRECTION = 2; static constexpr s32 WORLD_COUNT = 10; static constexpr s32 STAGES_PER_WORLD = 10; static constexpr u32 SECOND_FRAMES = 60; @@ -209,7 +207,7 @@ void disp() { } split[k] = sum[k] + segment[k]; } - split[0] = s_timer_group[0].segment; + split[0] = segment[0]; u32 loadless_story_timer = split[9]; if (display_story_timer) {