-
Notifications
You must be signed in to change notification settings - Fork 5
Loadless timer, death counter, R menuing #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
640539f
851b6b5
c8ffb38
272978f
e3d3588
c1d22ec
36976d8
5d21d43
a65bec6
1f46cba
ab6a94b
4928a9e
ffd3399
e2dbfbd
6bd6181
a89263f
ea3e36d
959b589
5083c46
81243aa
de48a3b
f6128ec
df58f00
e7b4544
204c470
5812ff3
7b0240e
3784de5
59c22c1
1960881
61aa9bd
20de4e8
fb20cf1
6bc2ada
69dc8d2
a2364c1
2b41734
3100fe9
6733433
0bade0f
7f00f7b
af53183
3caac61
3e266b4
d647e4a
1334284
6862698
e2da8eb
23df108
fa27681
b644714
ed5aaaa
1a80d44
46c8d17
6dd2f5d
737c3e3
fe291ae
58810af
91b7be9
9ad68fd
8611496
2705b5c
10e1d1a
f1f8fb9
1b1248c
127d33d
5bd853c
25877af
c904063
93f4b5e
6b9e0c0
58c87ff
45c7a94
bd92011
5486527
92a054d
8de98f4
30cea10
a9a2d58
ab4c84a
cfcfdb8
0d6ea35
4087f0f
7e9cb06
736f329
39db605
d8b0b19
d130de8
fe9bdd0
aca9527
26dc9d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| #include "deathcounter.h" | ||
|
|
||
| #include "mkb/mkb.h" | ||
|
|
||
| #include "storyreset.h" | ||
| #include "systems/goal.h" | ||
| #include "systems/pref.h" | ||
| #include "systems/savest.h" | ||
| #include "systems/textinfo.h" | ||
| #include "utils/draw.h" | ||
| #include "utils/macro_utils.h" | ||
| #include "utils/mode.h" | ||
|
|
||
| namespace deathcounter { | ||
|
|
||
| constexpr u16 WORLD_COUNT = mode::WORLD_COUNT; | ||
|
|
||
| static u32 s_world_death_count[WORLD_COUNT] = {}; | ||
| static savest::Action s_previous_frame_action = savest::Action::None; | ||
| // Flag to determine when we should/shouldn't increment the death counter | ||
| static bool s_can_incr_death_counter = false; | ||
|
|
||
| using Slot = textinfo::Slot; | ||
| using Format = timerdisp::TimeFormat; | ||
|
|
||
| u32 get_total_death_count() { | ||
| u32 total = 0; | ||
| for (u16 k = 0; k < WORLD_COUNT; k++) { | ||
| total += s_world_death_count[k]; | ||
| } | ||
| return total; | ||
| } | ||
|
|
||
| u32 get_world_death_count(u16 world_idx) { | ||
| u16 clamped_idx = MIN(world_idx, WORLD_COUNT - 1); // clamp for safety | ||
| return s_world_death_count[clamped_idx]; | ||
| } | ||
|
|
||
| void increment_world_death_counter() { | ||
| // Check the pref for count first stage deaths and if we're on the first stage | ||
| if (!pref::get(pref::Pref::CountFirstStageDeaths) && | ||
| mode::get_storymode_total_clear_count() == 0) { | ||
| return; | ||
| } | ||
| s_world_death_count[mkb::scen_info.world] += 1; // death counter for the current world | ||
| s_can_incr_death_counter = false; // so we only increment once per death | ||
| } | ||
|
|
||
| void reset_flag() { | ||
| s_can_incr_death_counter = false; | ||
| } | ||
|
|
||
| void reset_death_counters() { | ||
| for (u16 k = 0; k < WORLD_COUNT; k++) { | ||
| s_world_death_count[k] = 0; | ||
| } | ||
| reset_flag(); | ||
| } | ||
|
|
||
| bool loaded_state() { | ||
| return savest::get_last_action() == savest::Action::Load && | ||
| s_previous_frame_action == savest::Action::None; | ||
| } | ||
|
|
||
| // When we're done holding the savestate button/when gameplay resumes | ||
| void update_flag_on_state_release() { | ||
| if (goal::is_gameplay_exact() && savest::get_last_action() == savest::Action::None) { | ||
| // As soon as we're done holding the load state button (or just any time we're controlling | ||
| // the monkey on the stage), we're allowed to die | ||
| s_can_incr_death_counter = true; | ||
| } | ||
| } | ||
|
|
||
| bool should_count_as_normal_death() { | ||
| bool retried_without_clearing = | ||
| mode::is_spin_in_init(mkb::sub_mode) && s_can_incr_death_counter; | ||
| bool left_stage_without_clearing = | ||
| mode::is_stage_exit_submode(mkb::sub_mode) && s_can_incr_death_counter; | ||
| // Need to also check the flag for death init submodes in case we fall out and let the animation | ||
| // play out (ie we enter 2 "death init" submodes before resuming gameplay) | ||
| bool died = mode::is_death_init(mkb::sub_mode) && s_can_incr_death_counter; | ||
| return retried_without_clearing || left_stage_without_clearing || died; | ||
| } | ||
|
|
||
| bool should_count_as_savestate_death() { | ||
| return loaded_state() && s_can_incr_death_counter; | ||
| } | ||
|
|
||
| void count_deaths() { | ||
| if (goal::is_postgoal_exact()) { | ||
| s_can_incr_death_counter = false; | ||
| } | ||
|
|
||
| if (should_count_as_normal_death() || should_count_as_savestate_death()) { | ||
| increment_world_death_counter(); | ||
| } | ||
| } | ||
|
|
||
| void tick() { | ||
| if (storyreset::should_reset_run()) { | ||
| reset_death_counters(); | ||
| } | ||
|
|
||
| // Whenever entering a new stage, reset our flag | ||
| if (mode::is_spin_in_first_init(mkb::sub_mode)) { | ||
| reset_flag(); | ||
| } | ||
|
|
||
| update_flag_on_state_release(); | ||
| count_deaths(); | ||
|
|
||
| // Only after we're done doing death checks for this frame do we update s_previous_frame_action | ||
| s_previous_frame_action = savest::get_last_action(); | ||
| } | ||
|
|
||
| bool should_display_death_counter() { | ||
| u8 pref = pref::get(pref::Pref::DeathCounterDisplayOptions); | ||
|
|
||
| using DeathCounterOptions = storyreset::StoryDisplayOptions; | ||
|
|
||
| switch (DeathCounterOptions(pref)) { | ||
| case DeathCounterOptions::AlwaysShow: | ||
| return true; | ||
| case DeathCounterOptions::BetweenWorlds: | ||
| return goal::is_between_worlds(); | ||
| case DeathCounterOptions::EndOfRun: | ||
| return goal::is_run_complete(); | ||
| case DeathCounterOptions::DontShow: | ||
| return false; | ||
| default: | ||
| // Unreachable | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| bool should_not_display_counter_at_all() { | ||
| if (!mode::is_main_game_mode_story(mkb::main_game_mode)) { | ||
| // If we're in the menus outside of a story mode run due to an accidental exit game, we | ||
| // still want to be able to display the counter if we haven't reset it yet | ||
| return !storyreset::is_run_active(); | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| void disp() { | ||
| if (should_not_display_counter_at_all()) { | ||
| return; | ||
| } | ||
|
|
||
| if (should_display_death_counter()) { | ||
| // Technically not a timer, but we can still use this function without specifying any | ||
| // special formatting | ||
| textinfo::draw_timer(Slot::Left, draw::WHITE, "Deaths:", get_total_death_count(), | ||
| Format::Unformatted); | ||
| } | ||
| } | ||
|
|
||
| } // namespace deathcounter | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #pragma once | ||
|
|
||
| #include "mkb/mkb.h" | ||
|
|
||
| namespace deathcounter { | ||
|
|
||
| u32 get_total_death_count(); | ||
| u32 get_world_death_count(u16 world_idx); | ||
|
Comment on lines
+7
to
+8
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove if only used for debug prints
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These get used by the story breakdown screen since death counts for each world + total death count get displayed there |
||
| bool should_display_death_counter(); | ||
|
|
||
| void tick(); | ||
| void disp(); | ||
|
|
||
| } // namespace deathcounter | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,14 @@ | |
|
|
||
| namespace gotostory { | ||
|
|
||
| enum class State { | ||
| Default, | ||
| LoadMenuReq, | ||
| LoadStoryReq, | ||
| }; | ||
|
|
||
| void tick(); | ||
| void load_storymode(); | ||
| State get_gotostory_state(); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any way you can use mkb modes/submodes instead of gotostory state? |
||
|
|
||
| } // namespace gotostory | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these are only used for debug prints? Should be removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now these are used in
storytimer.cppto draw the breakdown screen (since I updated the breakdown screen to also include death count per world). Something I was thinking about doing was to completely remove thedeathcounterdependency fromstorytimer, since they really should be independent things. (storytimeralso currently needs to know ifdeathcounteris displaying the counter, but that dependency can also be removed after updating prac mod's display system).So right now, the include chain looks like the right hand side of the image. But, I could make a new file called
storybreakdownor something that's just dedicated to drawing the breakdown screen, and thenstorytimeranddeathcountercould just be independent of each other (and the include chain would look like the left hand side of the image)