diff --git a/desktop_version/CMakeLists.txt b/desktop_version/CMakeLists.txt index a02a35f4..c68f9715 100644 --- a/desktop_version/CMakeLists.txt +++ b/desktop_version/CMakeLists.txt @@ -109,6 +109,7 @@ set(VVV_SRC src/XMLUtils.cpp src/main.cpp src/DeferCallbacks.c + src/GlitchrunnerMode.c src/Network.c src/ThirdPartyDeps.c ) diff --git a/desktop_version/src/Entity.cpp b/desktop_version/src/Entity.cpp index c58e90d3..4c301224 100644 --- a/desktop_version/src/Entity.cpp +++ b/desktop_version/src/Entity.cpp @@ -5,6 +5,7 @@ #include "editor.h" #include "Game.h" +#include "GlitchrunnerMode.h" #include "Graphics.h" #include "Map.h" #include "Music.h" @@ -4844,7 +4845,7 @@ void entityclass::collisioncheck(int i, int j, bool scm /*= false*/) } break; case 7: // Person versus horizontal warp line, pre-2.1 - if (game.glitchrunnermode + if (GlitchrunnerMode_less_than_or_equal(Glitchrunner2_0) && game.deathseq == -1 && entities[j].onentity > 0 && entityhlinecollide(i, j)) diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index 1dd31537..004c68c5 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -12,6 +12,7 @@ #include "Entity.h" #include "Enums.h" #include "FileSystemUtils.h" +#include "GlitchrunnerMode.h" #include "Graphics.h" #include "KeyPoll.h" #include "MakeAndPlay.h" @@ -379,7 +380,6 @@ void Game::init(void) fadetolabdelay = 0; over30mode = true; - glitchrunnermode = false; ingame_titlemode = false; #if !defined(NO_CUSTOM_LEVELS) && !defined(NO_EDITOR) @@ -4209,7 +4209,7 @@ void Game::deserializesettings(tinyxml2::XMLElement* dataNode, ScreenSettings* s if (SDL_strcmp(pKey, "glitchrunnermode") == 0) { - glitchrunnermode = help.Int(pText); + GlitchrunnerMode_set(GlitchrunnerMode_string_to_enum(pText)); } if (SDL_strcmp(pKey, "vsync") == 0) @@ -4471,7 +4471,11 @@ void Game::serializesettings(tinyxml2::XMLElement* dataNode, const ScreenSetting xml::update_tag(dataNode, "inputdelay", (int) inputdelay); - xml::update_tag(dataNode, "glitchrunnermode", (int) glitchrunnermode); + xml::update_tag( + dataNode, + "glitchrunnermode", + GlitchrunnerMode_enum_to_string(GlitchrunnerMode_get()) + ); xml::update_tag(dataNode, "vsync", (int) screen_settings->useVsync); @@ -6091,6 +6095,18 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) menuyoff = 0; maxspacing = 15; break; + case Menu::setglitchrunner: + { + int i; + + option("none"); + + for (i = 1; i < GlitchrunnerNumVersions; ++i) + { + option(GlitchrunnerMode_enum_to_string((enum GlitchrunnerMode) i)); + } + break; + } case Menu::advancedoptions: option("unfocus pause"); option("room name background"); diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h index bfe41fb0..e7940cf3 100644 --- a/desktop_version/src/Game.h +++ b/desktop_version/src/Game.h @@ -43,6 +43,7 @@ namespace Menu options, gameplayoptions, speedrunneroptions, + setglitchrunner, advancedoptions, audiooptions, accessibility, @@ -459,7 +460,6 @@ public: bool nocompetitive(void); bool over30mode; - bool glitchrunnermode; // Have fun speedrunners! <3 Misa bool ingame_titlemode; #if !defined(NO_CUSTOM_LEVELS) && !defined(NO_EDITOR) diff --git a/desktop_version/src/GlitchrunnerMode.c b/desktop_version/src/GlitchrunnerMode.c new file mode 100644 index 00000000..e1c99d31 --- /dev/null +++ b/desktop_version/src/GlitchrunnerMode.c @@ -0,0 +1,69 @@ +#include "GlitchrunnerMode.h" + +#include +#include + +#define LOOKUP_TABLE \ + FOREACH_ENUM(GlitchrunnerNone, "") \ + FOREACH_ENUM(Glitchrunner2_0, "2.0") \ + FOREACH_ENUM(Glitchrunner2_2, "2.2") \ + +const char* GlitchrunnerMode_enum_to_string(const enum GlitchrunnerMode mode) +{ + switch (mode) + { +#define FOREACH_ENUM(MODE, STRING) \ + case MODE: \ + return STRING; + + LOOKUP_TABLE + +#undef FOREACH_ENUM + + /* Compiler raises warning about this enum not being handled. */ + case GlitchrunnerNumVersions: + break; + } + + SDL_assert(0 && "Passed non-existent GlitchrunnerMode!"); + return GlitchrunnerMode_enum_to_string(GlitchrunnerNone); +} + +enum GlitchrunnerMode GlitchrunnerMode_string_to_enum(const char* string) +{ +#define FOREACH_ENUM(MODE, STRING) \ + if (SDL_strcmp(STRING, string) == 0) \ + { \ + return MODE; \ + } + + LOOKUP_TABLE + +#undef FOREACH_ENUM + + return GlitchrunnerNone; +} + +#undef LOOKUP_TABLE + +static enum GlitchrunnerMode current_mode = GlitchrunnerNone; + +void GlitchrunnerMode_set(const enum GlitchrunnerMode mode) +{ + current_mode = mode; +} + +enum GlitchrunnerMode GlitchrunnerMode_get(void) +{ + return current_mode; +} + +int GlitchrunnerMode_less_than_or_equal(const enum GlitchrunnerMode mode) +{ + if (current_mode == GlitchrunnerNone) + { + return current_mode == mode; + } + + return current_mode <= mode; +} diff --git a/desktop_version/src/GlitchrunnerMode.h b/desktop_version/src/GlitchrunnerMode.h new file mode 100644 index 00000000..ac082a95 --- /dev/null +++ b/desktop_version/src/GlitchrunnerMode.h @@ -0,0 +1,35 @@ +#ifndef GLITCHRUNNERMODE_H +#define GLITCHRUNNERMODE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Have fun speedrunners! <3 Misa */ + +/* When a version is added, update the lookup table in GlitchrunnerMode.c */ + +enum GlitchrunnerMode +{ + GlitchrunnerNone, + Glitchrunner2_0, + Glitchrunner2_2, /* 2.1 is same as 2.2 */ + GlitchrunnerNumVersions +}; + +const char* GlitchrunnerMode_enum_to_string(enum GlitchrunnerMode mode); + +enum GlitchrunnerMode GlitchrunnerMode_string_to_enum(const char* string); + +void GlitchrunnerMode_set(enum GlitchrunnerMode mode); + +enum GlitchrunnerMode GlitchrunnerMode_get(void); + +int GlitchrunnerMode_less_than_or_equal(enum GlitchrunnerMode mode); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* GLITCHRUNNERMODE_H */ diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp index abe6d521..7eefbd9b 100644 --- a/desktop_version/src/Input.cpp +++ b/desktop_version/src/Input.cpp @@ -6,6 +6,7 @@ #include "Enums.h" #include "FileSystemUtils.h" #include "Game.h" +#include "GlitchrunnerMode.h" #include "Graphics.h" #include "KeyPoll.h" #include "MakeAndPlay.h" @@ -661,8 +662,9 @@ static void menuactionpress(void) case 0: // Glitchrunner mode music.playef(11); - game.glitchrunnermode = !game.glitchrunnermode; - game.savestatsandsettings_menu(); + game.createmenu(Menu::setglitchrunner); + game.currentmenuoption = GlitchrunnerMode_get(); + map.nexttowercolour(); break; case 1: /* Input delay */ @@ -690,6 +692,13 @@ static void menuactionpress(void) break; } break; + case Menu::setglitchrunner: + GlitchrunnerMode_set((enum GlitchrunnerMode) game.currentmenuoption); + music.playef(11); + game.returnmenu(); + game.savestatsandsettings_menu(); + map.nexttowercolour(); + break; case Menu::advancedoptions: switch (game.currentmenuoption) { @@ -1919,7 +1928,11 @@ void gameinput(void) } else { - if(game.glitchrunnermode || !game.glitchrunkludge) game.state++; + if (GlitchrunnerMode_less_than_or_equal(Glitchrunner2_0) + || !game.glitchrunkludge) + { + game.state++; + } game.jumpheld = true; game.glitchrunkludge=true; //Bug fix! You should only be able to do this ONCE. @@ -2249,10 +2262,12 @@ void gameinput(void) } } -static void mapmenuactionpress(void); +static void mapmenuactionpress(bool version2_2); void mapinput(void) { + const bool version2_2 = GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2); + //TODO Mouse Input! //game.mx = (mouseX / 2); //game.my = (mouseY / 2); @@ -2263,7 +2278,7 @@ void mapinput(void) game.press_map = false; game.press_interact = false; - if (game.glitchrunnermode && graphics.fademode == 1 && graphics.menuoffset == 0) + if (version2_2 && graphics.fademode == 1 && graphics.menuoffset == 0) { // Deliberate re-addition of the glitchy gamestate-based fadeout! @@ -2299,7 +2314,7 @@ void mapinput(void) } } - if (game.fadetomenu && !game.glitchrunnermode) + if (game.fadetomenu && !version2_2) { if (game.fadetomenudelay > 0) { @@ -2313,7 +2328,7 @@ void mapinput(void) } } - if (game.fadetolab && !game.glitchrunnermode) + if (game.fadetolab && !version2_2) { if (game.fadetolabdelay > 0) { @@ -2327,7 +2342,7 @@ void mapinput(void) } if(graphics.menuoffset==0 - && ((!game.glitchrunnermode && !game.fadetomenu && game.fadetomenudelay <= 0 && !game.fadetolab && game.fadetolabdelay <= 0) + && ((!version2_2 && !game.fadetomenu && game.fadetomenudelay <= 0 && !game.fadetolab && game.fadetolabdelay <= 0) || graphics.fademode == 0)) { if (key.isDown(KEYBOARD_LEFT) || key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_a) || key.isDown(KEYBOARD_w)|| key.controllerWantsLeft(true)) @@ -2418,7 +2433,7 @@ void mapinput(void) if (game.press_action) { - mapmenuactionpress(); + mapmenuactionpress(version2_2); } if (game.menupage < 0) game.menupage = 3; @@ -2435,7 +2450,7 @@ void mapinput(void) } } -static void mapmenuactionpress(void) +static void mapmenuactionpress(const bool version2_2) { switch (game.menupage) { @@ -2507,7 +2522,7 @@ static void mapmenuactionpress(void) graphics.fademode = 2; music.fadeout(); map.nexttowercolour(); - if (!game.glitchrunnermode) + if (!version2_2) { game.fadetomenu = true; game.fadetomenudelay = 16; @@ -2524,7 +2539,7 @@ static void mapmenuactionpress(void) game.swnmode = false; graphics.fademode = 2; music.fadeout(); - if (!game.glitchrunnermode) + if (!version2_2) { game.fadetolab = true; game.fadetolabdelay = 16; diff --git a/desktop_version/src/KeyPoll.cpp b/desktop_version/src/KeyPoll.cpp index 4fee8a73..e6916776 100644 --- a/desktop_version/src/KeyPoll.cpp +++ b/desktop_version/src/KeyPoll.cpp @@ -7,6 +7,7 @@ #include "Exit.h" #include "Game.h" +#include "GlitchrunnerMode.h" #include "Graphics.h" #include "Music.h" @@ -72,7 +73,7 @@ void KeyPoll::toggleFullscreen(void) } keymap.clear(); /* we lost the input due to a new window. */ - if (game.glitchrunnermode) + if (GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2)) { game.press_left = false; game.press_right = false; diff --git a/desktop_version/src/Logic.cpp b/desktop_version/src/Logic.cpp index 4b492e66..4b1fe3cb 100644 --- a/desktop_version/src/Logic.cpp +++ b/desktop_version/src/Logic.cpp @@ -3,6 +3,7 @@ #include "Enums.h" #include "FileSystemUtils.h" #include "Game.h" +#include "GlitchrunnerMode.h" #include "Graphics.h" #include "Map.h" #include "Music.h" @@ -975,7 +976,7 @@ void gamelogic(void) //Using warplines? if (obj.customwarpmode) { - if (!game.glitchrunnermode) { + if (!GlitchrunnerMode_less_than_or_equal(Glitchrunner2_0)) { //Rewritten system for mobile update: basically, the new logic is to //check if the player is leaving the map, and if so do a special check against //warp lines for collision diff --git a/desktop_version/src/Map.cpp b/desktop_version/src/Map.cpp index bb97c252..406bee9b 100644 --- a/desktop_version/src/Map.cpp +++ b/desktop_version/src/Map.cpp @@ -4,6 +4,7 @@ #include "editor.h" #include "Entity.h" #include "Game.h" +#include "GlitchrunnerMode.h" #include "Graphics.h" #include "MakeAndPlay.h" #include "Music.h" @@ -815,7 +816,7 @@ void mapclass::resetplayer(const bool player_died) { obj.entities[i].invis = false; } - if (!game.glitchrunnermode) + if (!GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2)) { obj.entities[i].size = 0; obj.entities[i].cx = 6; @@ -2056,7 +2057,7 @@ void mapclass::twoframedelayfix(void) // and when the script gets loaded script.run() has already ran for that frame, too. // A bit kludge-y, but it's the least we can do without changing the frame ordering. - if (game.glitchrunnermode + if (GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2) || !custommode || game.deathseq != -1) return; diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp index 865e0271..32ae7e46 100644 --- a/desktop_version/src/Render.cpp +++ b/desktop_version/src/Render.cpp @@ -4,6 +4,7 @@ #include "editor.h" #include "Entity.h" #include "FileSystemUtils.h" +#include "GlitchrunnerMode.h" #include "Graphics.h" #include "GraphicsUtil.h" #include "KeyPoll.h" @@ -105,6 +106,37 @@ static void volumesliderrender(void) graphics.Print(-1, 85, buffer, tr, tg, tb, true); } +static void inline drawglitchrunnertext(void) +{ + int tempr = tr; + int tempg = tg; + int tempb = tb; + + /* Screen width 40 chars, 4 per char */ + char buffer[160 + 1]; + + const char* mode_string; + + const enum GlitchrunnerMode mode = GlitchrunnerMode_get(); + + if (mode == GlitchrunnerNone) + { + tempr /= 2; + tempg /= 2; + tempb /= 2; + + mode_string = "OFF"; + } + else + { + mode_string = GlitchrunnerMode_enum_to_string(mode); + } + + SDL_snprintf(buffer, sizeof(buffer), "Glitchrunner mode is %s", mode_string); + + graphics.Print(-1, 95, buffer, tempr, tempg, tempb, true); +} + static void menurender(void) { int temp = 50; @@ -571,14 +603,7 @@ static void menurender(void) graphics.bigprint(-1, 30, "Glitchrunner Mode", tr, tg, tb, true); graphics.Print(-1, 65, "Re-enable glitches that existed", tr, tg, tb, true); graphics.Print(-1, 75, "in previous versions of the game.", tr, tg, tb, true); - if (game.glitchrunnermode) - { - graphics.Print(-1, 95, "Glitchrunner mode is ON", tr, tg, tb, true); - } - else - { - graphics.Print(-1, 95, "Glitchrunner mode is OFF", tr / 2, tg / 2, tb / 2, true); - } + drawglitchrunnertext(); break; case 1: graphics.bigprint(-1, 30, "Input Delay", tr, tg, tb, true); @@ -625,6 +650,12 @@ static void menurender(void) break; } break; + case Menu::setglitchrunner: + graphics.bigprint(-1, 30, "Glitchrunner Mode", tr, tg, tb, true); + graphics.Print(-1, 65, "Select a new glitchrunner", tr, tg, tb, true); + graphics.Print(-1, 75, "version below.", tr, tg, tb, true); + drawglitchrunnertext(); + break; case Menu::advancedoptions: switch (game.currentmenuoption) { @@ -2666,7 +2697,7 @@ void maprender(void) // We need to draw the black screen above the menu in order to disguise it // being jankily brought down in glitchrunner mode when exiting to the title // Otherwise, there's no reason to obscure the menu - if (game.glitchrunnermode || graphics.fademode == 3 || graphics.fademode == 5) + if (GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2) || graphics.fademode == 3 || graphics.fademode == 5) { graphics.drawfade(); } diff --git a/desktop_version/src/Script.cpp b/desktop_version/src/Script.cpp index f8cfd797..eae56902 100644 --- a/desktop_version/src/Script.cpp +++ b/desktop_version/src/Script.cpp @@ -7,6 +7,7 @@ #include "Entity.h" #include "Enums.h" #include "Exit.h" +#include "GlitchrunnerMode.h" #include "Graphics.h" #include "KeyPoll.h" #include "Map.h" @@ -3394,13 +3395,15 @@ void scriptclass::teleport(void) void scriptclass::hardreset(void) { + const bool version2_2 = GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2); + //Game: game.hascontrol = true; game.gravitycontrol = 0; game.teleport = false; game.companion = 0; game.roomchange = false; - if (!game.glitchrunnermode) + if (!version2_2) { // Ironically, resetting more variables makes the janky fadeout system in glitchrunnermode even more glitchy game.roomx = 0; @@ -3441,7 +3444,7 @@ void scriptclass::hardreset(void) game.savetime = "00:00"; game.savearea = "nowhere"; game.savetrinkets = 0; - if (!game.glitchrunnermode) + if (!version2_2) { // Ironically, resetting more variables makes the janky fadeout system in glitchrunnermode even more glitchy game.saverx = 0; @@ -3487,7 +3490,7 @@ void scriptclass::hardreset(void) game.statedelay = 0; game.hascontrol = true; - if (!game.glitchrunnermode) + if (!GlitchrunnerMode_less_than_or_equal(Glitchrunner2_0)) { // Keep the "- Press ACTION to advance text -" prompt around, // apparently the speedrunners call it the "text storage" glitch @@ -3528,7 +3531,7 @@ void scriptclass::hardreset(void) map.resetnames(); map.custommode=false; map.custommodeforreal=false; - if (!game.glitchrunnermode) + if (!version2_2) { // Ironically, resetting more variables makes the janky fadeout system even more glitchy map.towermode=false;