From f23e99820f0e396a51fa2e1b92a442997c5f6fae Mon Sep 17 00:00:00 2001 From: Misa Date: Mon, 13 Feb 2023 17:12:45 -0800 Subject: [PATCH 1/8] Refactor `entityclass::entityhlinecollide` The code quality has been improved in several ways: - Variables are `const`-qualified where possible. - Storing pointers to the objects referenced so `entities` doesn't need to keep being indexed, and the objects can then be referred to with better, longer names like `person` and `line`. - Early returns are used so the most important code doesn't keep being pushed to the right. - The comment from `entityclass::collisioncheck` is moved here, because it should be in this function and not at the callsite of the function. The existing comment in the function is made redundant with the more descriptive variable names, and is removed. - The comment has also been improved to be more concise and clear. --- desktop_version/src/Entity.cpp | 38 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/desktop_version/src/Entity.cpp b/desktop_version/src/Entity.cpp index f70246d725..f2f21e4a2b 100644 --- a/desktop_version/src/Entity.cpp +++ b/desktop_version/src/Entity.cpp @@ -4242,31 +4242,35 @@ static int yline( int a, int b ) return 1; } -bool entityclass::entityhlinecollide( int t, int l ) +bool entityclass::entityhlinecollide(const int person_idx, const int line_idx) { - if (!INBOUNDS_VEC(t, entities) || !INBOUNDS_VEC(l, entities)) + if (!INBOUNDS_VEC(person_idx, entities) || !INBOUNDS_VEC(line_idx, entities)) { vlog_error("entityhlinecollide() out-of-bounds!"); return false; } - //Returns true is entity t collided with the horizontal line l. - if(entities[t].xp + entities[t].cx+entities[t].w>=entities[l].xp) + const entclass* person = &entities[person_idx]; + const entclass* line = &entities[line_idx]; + + const bool in_vicinity = + person->xp + person->cx + person->w >= line->xp && + person->xp + person->cx <= line->xp + line->w; + if (!in_vicinity) { - if(entities[t].xp + entities[t].cx<=entities[l].xp+entities[l].w) - { - int linetemp = 0; + return false; + } - linetemp += yline(entities[t].yp, entities[l].yp); - linetemp += yline(entities[t].yp + entities[t].h, entities[l].yp); - linetemp += yline(entities[t].oldyp, entities[l].yp); - linetemp += yline(entities[t].oldyp + entities[t].h, entities[l].yp); + /* Here we compare the person's old position versus their new one. + * All points are either above or below the line. Else, it's a collision. */ + int linetemp = 0; - if (linetemp > -4 && linetemp < 4) return true; - return false; - } - } - return false; + linetemp += yline(person->yp, line->yp); + linetemp += yline(person->yp + person->h, line->yp); + linetemp += yline(person->oldyp, line->yp); + linetemp += yline(person->oldyp + person->h, line->yp); + + return linetemp > -4 && linetemp < 4; } bool entityclass::entityvlinecollide( int t, int l ) @@ -4850,8 +4854,6 @@ void entityclass::collisioncheck(int i, int j, bool scm /*= false*/) case 4: //Person vs horizontal line! if(game.deathseq==-1) { - //Here we compare the person's old position versus his new one versus the line. - //All points either be above or below it. Otherwise, there was a collision this frame. if (entities[j].onentity > 0) { if (entityhlinecollide(i, j)) From 0edf0016d969800e29a82d41a779dd86e9c91758 Mon Sep 17 00:00:00 2001 From: Misa Date: Tue, 7 Mar 2023 23:05:43 -0800 Subject: [PATCH 2/8] `const&`-ify `getcolorfromname` and `getcrewmanfromname` This brings these functions into conforming code style and is a small performance optimization. --- desktop_version/src/Script.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/desktop_version/src/Script.cpp b/desktop_version/src/Script.cpp index a58b1735a1..d82067797b 100644 --- a/desktop_version/src/Script.cpp +++ b/desktop_version/src/Script.cpp @@ -131,7 +131,7 @@ void scriptclass::tokenize( const std::string& t ) } } -static int getcolorfromname(std::string name) +static int getcolorfromname(const std::string& name) { if (name == "player") return CYAN; else if (name == "cyan") return CYAN; @@ -149,7 +149,7 @@ static int getcolorfromname(std::string name) return color; // Last effort to give a valid color, maybe they just input the color? } -static int getcrewmanfromname(std::string name) +static int getcrewmanfromname(const std::string& name) { if (name == "player") return obj.getplayer(); // Return the player int color = getcolorfromname(name); // Maybe they passed in a crewmate name, or an id? From 265d4f9dc48aa803cae351651dfb44e71e664e88 Mon Sep 17 00:00:00 2001 From: Misa Date: Fri, 30 Aug 2024 11:23:55 -0700 Subject: [PATCH 3/8] Refactor: Unindent horizontal line code This removes unnecessary indentation in the code responsible for acting on a horizontal gravity line collision. The "meat" of the code is now no longer pushed to the right, as it should be. --- desktop_version/src/Entity.cpp | 42 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/desktop_version/src/Entity.cpp b/desktop_version/src/Entity.cpp index f2f21e4a2b..f82dcc1431 100644 --- a/desktop_version/src/Entity.cpp +++ b/desktop_version/src/Entity.cpp @@ -4852,30 +4852,32 @@ void entityclass::collisioncheck(int i, int j, bool scm /*= false*/) } break; case 4: //Person vs horizontal line! - if(game.deathseq==-1) + { + const bool collision = + game.deathseq == -1 + && entities[j].onentity > 0 + && entityhlinecollide(i, j); + if (!collision) { - if (entities[j].onentity > 0) - { - if (entityhlinecollide(i, j)) - { - music.playef(Sound_GRAVITYLINE); - game.gravitycontrol = (game.gravitycontrol + 1) % 2; - game.totalflips++; - if (game.gravitycontrol == 0) - { - if (entities[i].vy < 1) entities[i].vy = 1; - } - else - { - if (entities[i].vy > -1) entities[i].vy = -1; - } + break; + } - entities[j].state = entities[j].onentity; - entities[j].life = 6; - } - } + music.playef(Sound_GRAVITYLINE); + game.gravitycontrol = (game.gravitycontrol + 1) % 2; + game.totalflips++; + if (game.gravitycontrol == 0) + { + if (entities[i].vy < 1) entities[i].vy = 1; } + else + { + if (entities[i].vy > -1) entities[i].vy = -1; + } + + entities[j].state = entities[j].onentity; + entities[j].life = 6; break; + } case 5: //Person vs vertical gravity/warp line! if(game.deathseq==-1) { From 3e0b7e5345194721666fadd83177b877e059e0fc Mon Sep 17 00:00:00 2001 From: Misa Date: Fri, 30 Aug 2024 11:27:57 -0700 Subject: [PATCH 4/8] Add glitchless mode UI This only adds glitchless mode as a menu option in the speedrunner options menu, and saving and loading it as a settings boolean. It is not yet functional. Glitchless mode and glitchrunner mode are mutually incompatible. --- desktop_version/lang/ar/strings.xml | 8 +++++ desktop_version/lang/ca/strings.xml | 8 +++++ desktop_version/lang/cy/strings.xml | 8 +++++ desktop_version/lang/de/strings.xml | 8 +++++ desktop_version/lang/en/strings.xml | 8 +++++ desktop_version/lang/eo/strings.xml | 8 +++++ desktop_version/lang/es/strings.xml | 8 +++++ desktop_version/lang/es_419/strings.xml | 8 +++++ desktop_version/lang/es_AR/strings.xml | 8 +++++ desktop_version/lang/fr/strings.xml | 8 +++++ desktop_version/lang/ga/strings.xml | 8 +++++ desktop_version/lang/it/strings.xml | 8 +++++ desktop_version/lang/ja/strings.xml | 8 +++++ desktop_version/lang/ko/strings.xml | 8 +++++ desktop_version/lang/nl/strings.xml | 8 +++++ desktop_version/lang/pl/strings.xml | 8 +++++ desktop_version/lang/pt_BR/strings.xml | 8 +++++ desktop_version/lang/pt_PT/strings.xml | 8 +++++ desktop_version/lang/ru/strings.xml | 8 +++++ desktop_version/lang/szl/strings.xml | 8 +++++ desktop_version/lang/tr/strings.xml | 8 +++++ desktop_version/lang/uk/strings.xml | 8 +++++ desktop_version/lang/zh/strings.xml | 8 +++++ desktop_version/lang/zh_TW/strings.xml | 8 +++++ desktop_version/src/Game.cpp | 19 ++++++++++- desktop_version/src/Game.h | 1 + desktop_version/src/Input.cpp | 28 +++++++++++++--- desktop_version/src/Render.cpp | 43 ++++++++++++++++++++++--- 28 files changed, 274 insertions(+), 9 deletions(-) diff --git a/desktop_version/lang/ar/strings.xml b/desktop_version/lang/ar/strings.xml index dc4ab172a4..d415c59d65 100644 --- a/desktop_version/lang/ar/strings.xml +++ b/desktop_version/lang/ar/strings.xml @@ -249,6 +249,14 @@ + + + + + + + + diff --git a/desktop_version/lang/ca/strings.xml b/desktop_version/lang/ca/strings.xml index 9067a50d8f..a81210338b 100644 --- a/desktop_version/lang/ca/strings.xml +++ b/desktop_version/lang/ca/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/cy/strings.xml b/desktop_version/lang/cy/strings.xml index 75233e0a01..b293efe0e1 100644 --- a/desktop_version/lang/cy/strings.xml +++ b/desktop_version/lang/cy/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/de/strings.xml b/desktop_version/lang/de/strings.xml index 8bc440f81a..057f9178eb 100644 --- a/desktop_version/lang/de/strings.xml +++ b/desktop_version/lang/de/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/en/strings.xml b/desktop_version/lang/en/strings.xml index 86a4217f37..b15abd005a 100644 --- a/desktop_version/lang/en/strings.xml +++ b/desktop_version/lang/en/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/eo/strings.xml b/desktop_version/lang/eo/strings.xml index 6c08504366..77e2884863 100644 --- a/desktop_version/lang/eo/strings.xml +++ b/desktop_version/lang/eo/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/es/strings.xml b/desktop_version/lang/es/strings.xml index 68c8a2468d..812efa152c 100644 --- a/desktop_version/lang/es/strings.xml +++ b/desktop_version/lang/es/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/es_419/strings.xml b/desktop_version/lang/es_419/strings.xml index 827a3b97f9..3d2e6585f0 100644 --- a/desktop_version/lang/es_419/strings.xml +++ b/desktop_version/lang/es_419/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/es_AR/strings.xml b/desktop_version/lang/es_AR/strings.xml index e2cdc45706..90ecaad166 100644 --- a/desktop_version/lang/es_AR/strings.xml +++ b/desktop_version/lang/es_AR/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/fr/strings.xml b/desktop_version/lang/fr/strings.xml index 411cc564be..908d2a01fd 100644 --- a/desktop_version/lang/fr/strings.xml +++ b/desktop_version/lang/fr/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/ga/strings.xml b/desktop_version/lang/ga/strings.xml index cbdf99877c..4f278b3465 100644 --- a/desktop_version/lang/ga/strings.xml +++ b/desktop_version/lang/ga/strings.xml @@ -245,6 +245,14 @@ Déan cóip chúltaca, ar eagla na heagla." explanation="translation maintenance + + + + + + + + diff --git a/desktop_version/lang/it/strings.xml b/desktop_version/lang/it/strings.xml index f4798b2b6a..42226339d7 100644 --- a/desktop_version/lang/it/strings.xml +++ b/desktop_version/lang/it/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/ja/strings.xml b/desktop_version/lang/ja/strings.xml index f7fe0042f1..43f206d30e 100644 --- a/desktop_version/lang/ja/strings.xml +++ b/desktop_version/lang/ja/strings.xml @@ -258,6 +258,14 @@ Escキーを押すと表示を終了する。" explanation="" max="38*6" max_loc + + + + + + + + diff --git a/desktop_version/lang/ko/strings.xml b/desktop_version/lang/ko/strings.xml index e7b69f1f94..f33b999efa 100755 --- a/desktop_version/lang/ko/strings.xml +++ b/desktop_version/lang/ko/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/nl/strings.xml b/desktop_version/lang/nl/strings.xml index 6d1aeebc24..af335ea782 100644 --- a/desktop_version/lang/nl/strings.xml +++ b/desktop_version/lang/nl/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/pl/strings.xml b/desktop_version/lang/pl/strings.xml index 059bd1edd8..ed1fcf8d82 100644 --- a/desktop_version/lang/pl/strings.xml +++ b/desktop_version/lang/pl/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/pt_BR/strings.xml b/desktop_version/lang/pt_BR/strings.xml index 0d084ab8a1..346fa40e5a 100644 --- a/desktop_version/lang/pt_BR/strings.xml +++ b/desktop_version/lang/pt_BR/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/pt_PT/strings.xml b/desktop_version/lang/pt_PT/strings.xml index 3d24a84f57..5cc4fac82e 100644 --- a/desktop_version/lang/pt_PT/strings.xml +++ b/desktop_version/lang/pt_PT/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/ru/strings.xml b/desktop_version/lang/ru/strings.xml index 04c6476b5e..b2cebd4af8 100644 --- a/desktop_version/lang/ru/strings.xml +++ b/desktop_version/lang/ru/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/szl/strings.xml b/desktop_version/lang/szl/strings.xml index 3eadda2581..eb41bb9e94 100644 --- a/desktop_version/lang/szl/strings.xml +++ b/desktop_version/lang/szl/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/tr/strings.xml b/desktop_version/lang/tr/strings.xml index c7cfdf82b7..14c269b605 100644 --- a/desktop_version/lang/tr/strings.xml +++ b/desktop_version/lang/tr/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/uk/strings.xml b/desktop_version/lang/uk/strings.xml index dbfc81a9c6..2b4f8424ca 100644 --- a/desktop_version/lang/uk/strings.xml +++ b/desktop_version/lang/uk/strings.xml @@ -244,6 +244,14 @@ + + + + + + + + diff --git a/desktop_version/lang/zh/strings.xml b/desktop_version/lang/zh/strings.xml index d437c5ba4c..73e1c34788 100644 --- a/desktop_version/lang/zh/strings.xml +++ b/desktop_version/lang/zh/strings.xml @@ -250,6 +250,14 @@ + + + + + + + + diff --git a/desktop_version/lang/zh_TW/strings.xml b/desktop_version/lang/zh_TW/strings.xml index 157c0cbaaf..2ab10df716 100644 --- a/desktop_version/lang/zh_TW/strings.xml +++ b/desktop_version/lang/zh_TW/strings.xml @@ -250,6 +250,14 @@ + + + + + + + + diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index 1d7bad140c..fad16998d2 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -154,6 +154,7 @@ void Game::init(void) musicmutebutton = 0; glitchrunkludge = false; + glitchlessmode = false; gamestate = TITLEMODE; prevgamestate = TITLEMODE; hascontrol = true; @@ -4826,6 +4827,11 @@ void Game::deserializesettings(tinyxml2::XMLElement* dataNode, struct ScreenSett GlitchrunnerMode_set(GlitchrunnerMode_string_to_enum(pText)); } + if (SDL_strcmp(pKey, "glitchlessmode") == 0) + { + glitchlessmode = help.Int(pText); + } + if (SDL_strcmp(pKey, "showingametimer") == 0) { showingametimer = help.Int(pText); @@ -4939,6 +4945,14 @@ void Game::deserializesettings(tinyxml2::XMLElement* dataNode, struct ScreenSett } setdefaultcontrollerbuttons(); + + if (GlitchrunnerMode_get() != GlitchrunnerNone && glitchlessmode) + { + /* Glitchrunner and glitchless mode are incompatible. + * If the file was manually edited to enable both, disable both. */ + GlitchrunnerMode_set(GlitchrunnerNone); + glitchlessmode = false; + } } bool Game::savestats(bool sync /*= true*/) @@ -5115,6 +5129,8 @@ void Game::serializesettings(tinyxml2::XMLElement* dataNode, const struct Screen GlitchrunnerMode_enum_to_string(GlitchrunnerMode_get()) ); + xml::update_tag(dataNode, "glitchlessmode", (int) glitchlessmode); + xml::update_tag(dataNode, "showingametimer", (int) showingametimer); xml::update_tag(dataNode, "vsync", (int) screen_settings->useVsync); @@ -6826,7 +6842,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) maxspacing = 15; break; case Menu::speedrunneroptions: - option(loc::gettext("glitchrunner mode")); + option(loc::gettext("glitchrunner mode"), !glitchlessmode); + option(loc::gettext("glitchless mode"), GlitchrunnerMode_get() == GlitchrunnerNone); option(loc::gettext("input delay")); option(loc::gettext("interact button")); option(loc::gettext("fake load screen")); diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h index 362a956ced..fdac0c0d34 100644 --- a/desktop_version/src/Game.h +++ b/desktop_version/src/Game.h @@ -330,6 +330,7 @@ class Game int state, statedelay; bool glitchrunkludge; + bool glitchlessmode; enum GameGamestate gamestate; enum GameGamestate prevgamestate; //only used sometimes diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp index 468c265aac..968d8833ef 100644 --- a/desktop_version/src/Input.cpp +++ b/desktop_version/src/Input.cpp @@ -787,36 +787,56 @@ static void menuactionpress(void) { case 0: // Glitchrunner mode + if (game.glitchlessmode) + { + music.playef(Sound_CRY); + break; + } + music.playef(Sound_VIRIDIAN); game.createmenu(Menu::setglitchrunner); game.currentmenuoption = GlitchrunnerMode_get(); map.nexttowercolour(); break; case 1: + /* Glitchless mode */ + if (GlitchrunnerMode_get() != GlitchrunnerNone) + { + music.playef(2); + break; + } + + music.playef(11); + game.glitchlessmode = !game.glitchlessmode; + + /* Recreate menu to update glitchrunner mode */ + game.createmenu(game.currentmenuname, true); + break; + case 2: /* Input delay */ music.playef(Sound_VIRIDIAN); game.inputdelay = !game.inputdelay; game.savestatsandsettings_menu(); break; - case 2: + case 3: /* Interact button toggle */ music.playef(Sound_VIRIDIAN); game.separate_interact = !game.separate_interact; game.savestatsandsettings_menu(); break; - case 3: + case 4: // toggle fake load screen game.skipfakeload = !game.skipfakeload; game.savestatsandsettings_menu(); music.playef(Sound_VIRIDIAN); break; - case 4: + case 5: // toggle in game timer game.showingametimer = !game.showingametimer; game.savestatsandsettings_menu(); music.playef(Sound_VIRIDIAN); break; - case 5: + case 6: // english sprites loc::english_sprites = !loc::english_sprites; if (!loc::english_sprites) diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp index 20efc8ffd0..a42352d647 100644 --- a/desktop_version/src/Render.cpp +++ b/desktop_version/src/Render.cpp @@ -1022,10 +1022,38 @@ static void menurender(void) { font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("Glitchrunner Mode"), tr, tg, tb); int next_y = font::print_wrap(PR_CEN, -1, 65, loc::gettext("Re-enable glitches that existed in previous versions of the game."), tr, tg, tb); + + if (game.glitchlessmode) + { + font::print_wrap(PR_CEN, -1, next_y, loc::gettext("Glitchrunner mode is incompatible with glitchless mode."), tr, tg, tb); + break; + } + drawglitchrunnertext(next_y); break; } case 1: + { + font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("Glitchless Mode"), tr, tg, tb); + const int next_y = font::print_wrap(PR_CEN, -1, 65, loc::gettext("Disable glitches that might otherwise be useful for speedruns."), tr, tg, tb); + + if (GlitchrunnerMode_get() != GlitchrunnerNone) + { + font::print_wrap(PR_CEN, -1, next_y, loc::gettext("Glitchless mode is incompatible with glitchrunner mode."), tr, tg, tb); + break; + } + + if (game.glitchlessmode) + { + font::print_wrap(PR_CEN, -1, next_y, loc::gettext("Glitchless mode is ON"), tr, tg, tb); + } + else + { + font::print_wrap(PR_CEN, -1, next_y, loc::gettext("Glitchless mode is OFF"), tr / 2, tg / 2, tb / 2); + } + break; + } + case 2: { font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("Input Delay"), tr, tg, tb); int next_y = font::print_wrap(PR_CEN, -1, 65, loc::gettext("Re-enable the 1-frame input delay from previous versions of the game."), tr, tg, tb); @@ -1039,7 +1067,7 @@ static void menurender(void) } break; } - case 2: + case 3: { char buffer[SCREEN_WIDTH_CHARS + 1]; const char* button; @@ -1060,7 +1088,7 @@ static void menurender(void) font::print_wrap(PR_CEN, -1, next_y, buffer, tr, tg, tb); break; } - case 3: + case 4: { font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("Fake Load Screen"), tr, tg, tb); int next_y = font::print_wrap(PR_CEN, -1, 65, loc::gettext("Disable the fake loading screen which appears on game launch."), tr, tg, tb); @@ -1070,7 +1098,7 @@ static void menurender(void) font::print_wrap(PR_CEN, -1, next_y, loc::gettext("Fake loading screen is ON"), tr, tg, tb); break; } - case 4: + case 5: { font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("In-Game Timer"), tr, tg, tb); int next_y = font::print_wrap(PR_CEN, -1, 65, loc::gettext("Toggle the in-game timer outside of time trials."), tr, tg, tb); @@ -1084,7 +1112,7 @@ static void menurender(void) } break; } - case 5: + case 6: { font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("English Sprites"), tr, tg, tb); int next_y = font::print_wrap(PR_CEN, -1, 65, loc::gettext("Show the original English word enemies regardless of your language setting."), tr, tg, tb); @@ -2265,6 +2293,12 @@ static void mode_indicator_text(const int alpha) y += spacing; } + if (game.glitchlessmode) + { + font::print(flags, x, y, loc::gettext("Glitchless mode enabled"), r, g, b); + y += spacing; + } + if (graphics.flipmode) { const char* english = "Flip Mode enabled"; @@ -2356,6 +2390,7 @@ void gamerender(void) ); bool any_mode_active = map.invincibility || GlitchrunnerMode_get() != GlitchrunnerNone + || game.glitchlessmode || graphics.flipmode || game.slowdown < 30; bool draw_mode_indicator_text = mode_indicator_alpha > 100 && any_mode_active; From b8ab77c7014c6af95701bf634526380ca809d740 Mon Sep 17 00:00:00 2001 From: Misa Date: Fri, 30 Aug 2024 11:31:30 -0700 Subject: [PATCH 5/8] Glitchless: Disable R key This disables pressing R to instantly die on the spot in glitchless mode. However, it is still available in custom levels. The R key was intended to get players out of softlocks in custom levels, but it was left enabled in the main game by mistake. This turned out to enable a variety of various glitches, most notably telejumping. So it was left enabled. But now glitchless mode disables it, to prevent pressing it by accident for speedrunning goals that prohibit pressing R. --- desktop_version/src/Input.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp index 968d8833ef..fce36a0df6 100644 --- a/desktop_version/src/Input.cpp +++ b/desktop_version/src/Input.cpp @@ -3009,7 +3009,10 @@ void gameinput(void) game.menupage = 30; // Pause screen } - if (game.deathseq == -1 && (key.isDown(SDLK_r) || key.isDown(game.controllerButton_restart)) && !game.nodeathmode)// && map.custommode) //Have fun glitchrunners! + if (game.deathseq == -1 && + (key.isDown(SDLK_r) || key.isDown(game.controllerButton_restart)) + && !game.nodeathmode + && (map.custommode || !game.glitchlessmode)) /* Have fun glitchrunners! */ { game.deathseq = 30; } From 3f222d3f742fe344a1084bcf5c3aad0e7e11e7b8 Mon Sep 17 00:00:00 2001 From: Misa Date: Fri, 30 Aug 2024 11:35:02 -0700 Subject: [PATCH 6/8] Glitchless: Fix warp token death warps The warp token death warp glitch is simple. It takes advantage of the fact that, in the main game, warp tokens (barring some exceptions) only change the room but do not change the player's position. So if the player dies while touching a warp token, the room will change but they will stay at the same position of their respawn point, which is used in speedrunning. To fix this, if the player dies, make sure that the warp tokens in the room don't warp them. Otherwise, this would still be possible to do even without pressing R. --- desktop_version/src/Map.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/desktop_version/src/Map.cpp b/desktop_version/src/Map.cpp index 747ebc383d..8670f6032b 100644 --- a/desktop_version/src/Map.cpp +++ b/desktop_version/src/Map.cpp @@ -854,6 +854,20 @@ void mapclass::resetplayer(const bool player_died) game.scmprogress = game.roomx - 40; } } + + if (game.glitchlessmode) + { + /* Fix warp token death warps: + * Reset the state of all warp tokens to 0. */ + for (size_t i = 0; i < obj.entities.size(); i++) + { + entclass* entity = &obj.entities[i]; + if (entity->type == 11) + { + entity->state = 0; + } + } + } } void mapclass::warpto(int rx, int ry , int t, int tx, int ty) From 01d256b4081afc8780314c02e33f5e94d01fa987 Mon Sep 17 00:00:00 2001 From: Misa Date: Fri, 30 Aug 2024 11:47:41 -0700 Subject: [PATCH 7/8] Glitchless: Fix line clipping The reason that line clipping works is because when the gravity line unflips the player, they are still eligible to flip (with onground/onroof) so by doing it frame-perfectly they can flip again. To fix this, just zero out their onground/onroof. This glitch mainly applies to horizontal gravity lines but it is also possible, but less severe (in most cases), with vertical gravity lines, so this fixes it for vertical lines too. --- desktop_version/src/Entity.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/desktop_version/src/Entity.cpp b/desktop_version/src/Entity.cpp index f82dcc1431..846d9aa3db 100644 --- a/desktop_version/src/Entity.cpp +++ b/desktop_version/src/Entity.cpp @@ -2783,6 +2783,14 @@ bool entityclass::updateentities( int i ) { if (INBOUNDS_VEC(temp, entities) && entities[temp].vy > -3) entities[temp].vy = -3; } + + if (game.glitchlessmode && INBOUNDS_VEC(temp, entities)) + { + /* Fix line clipping: Invalidate flipping eligibility so + * a second flip is impossible. */ + entities[temp].onground = 0; + entities[temp].onroof = 0; + } } else if (entities[i].state == 2) { @@ -4876,6 +4884,14 @@ void entityclass::collisioncheck(int i, int j, bool scm /*= false*/) entities[j].state = entities[j].onentity; entities[j].life = 6; + + if (game.glitchlessmode) + { + /* Fix line clipping: Invalidate flipping eligibility so + * a second flip is impossible. */ + entities[i].onground = 0; + entities[i].onroof = 0; + } break; } case 5: //Person vs vertical gravity/warp line! From 639f0e5229cfd9eb5448d014238da984fb932990 Mon Sep 17 00:00:00 2001 From: Misa Date: Fri, 30 Aug 2024 11:51:43 -0700 Subject: [PATCH 8/8] Glitchless: Fix changetile sprite glitch (TEMP) TODO: use color_valid for other commands? --- desktop_version/src/Entity.cpp | 16 ++++++++++++++++ desktop_version/src/Script.cpp | 24 +++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/desktop_version/src/Entity.cpp b/desktop_version/src/Entity.cpp index 846d9aa3db..c7ab52fd1b 100644 --- a/desktop_version/src/Entity.cpp +++ b/desktop_version/src/Entity.cpp @@ -3953,6 +3953,10 @@ int entityclass::getscm(void) } } + if (game.glitchlessmode) + { + return -1; + } return 0; } @@ -3970,6 +3974,10 @@ int entityclass::getlineat( int t ) } } + if (game.glitchlessmode) + { + return -1; + } return 0; } @@ -3989,6 +3997,10 @@ int entityclass::getcrewman( int t, int fallback /*= 0*/ ) } } + if (game.glitchlessmode) + { + return -1; + } return fallback; } @@ -4013,6 +4025,10 @@ int entityclass::getcustomcrewman( int t ) } } + if (game.glitchlessmode) + { + return -1; + } return 0; } diff --git a/desktop_version/src/Script.cpp b/desktop_version/src/Script.cpp index d82067797b..8c93566bc1 100644 --- a/desktop_version/src/Script.cpp +++ b/desktop_version/src/Script.cpp @@ -157,6 +157,28 @@ static int getcrewmanfromname(const std::string& name) return obj.getcrewman(color); } +static bool color_valid(const int index, const std::string& name) +{ + if (!INBOUNDS_VEC(index, obj.entities)) + { + return false; + } + + if (!game.glitchlessmode) + { + return true; + } + + const int color = getcolorfromname(name); + const bool using_aem = color == -1; + if (using_aem) + { + return true; + } + + return obj.entities[index].colour == color; +} + /* Also used in gamestate 1001. */ void foundtrinket_textbox1(textboxclass* THIS); @@ -1022,7 +1044,7 @@ void scriptclass::run(void) int crewmate = getcrewmanfromname(words[1]); if (crewmate != -1) i = crewmate; // Ensure AEM is kept - if (INBOUNDS_VEC(i, obj.entities)) + if (color_valid(i, words[1])) { obj.entities[i].tile = ss_toi(words[2]); }