2020-07-19 21:03:16 +02:00
|
|
|
#include <tinyxml2.h>
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-07-19 21:43:29 +02:00
|
|
|
#include "Credits.h"
|
2021-02-20 08:19:09 +01:00
|
|
|
#include "CustomLevels.h"
|
2021-02-21 00:40:11 +01:00
|
|
|
#include "Editor.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "Entity.h"
|
|
|
|
#include "Enums.h"
|
2020-07-19 21:43:29 +02:00
|
|
|
#include "FileSystemUtils.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "Game.h"
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
#include "GlitchrunnerMode.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "Graphics.h"
|
|
|
|
#include "KeyPoll.h"
|
2020-07-19 21:43:29 +02:00
|
|
|
#include "MakeAndPlay.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "Map.h"
|
|
|
|
#include "Music.h"
|
2020-07-19 21:43:29 +02:00
|
|
|
#include "Script.h"
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
#include "UtilityClass.h"
|
2021-02-24 00:21:29 +01:00
|
|
|
#include "Vlogging.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
|
2021-01-10 18:14:37 +01:00
|
|
|
static void updatebuttonmappings(int bind)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-02 23:06:56 +02:00
|
|
|
for (
|
|
|
|
SDL_GameControllerButton i = SDL_CONTROLLER_BUTTON_A;
|
|
|
|
i < SDL_CONTROLLER_BUTTON_DPAD_UP;
|
|
|
|
i = (SDL_GameControllerButton) (i + 1)
|
|
|
|
) {
|
|
|
|
if (key.isDown(i))
|
|
|
|
{
|
|
|
|
bool dupe = false;
|
2021-04-19 08:23:44 +02:00
|
|
|
switch (bind)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
2021-04-19 08:23:44 +02:00
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
size_t j;
|
|
|
|
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_flip[j])
|
|
|
|
{
|
|
|
|
dupe = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!dupe)
|
|
|
|
{
|
|
|
|
game.controllerButton_flip.push_back(i);
|
|
|
|
music.playef(11);
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_map.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_map[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_map.erase(game.controllerButton_map.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_esc.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_esc[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_esc.erase(game.controllerButton_esc.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_restart.size(); j += 1)
|
2020-08-09 00:41:59 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_restart[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_restart.erase(game.controllerButton_restart.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_interact.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_interact[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_interact.erase(game.controllerButton_interact.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-04-02 23:06:56 +02:00
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
case 2:
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
2021-04-19 08:23:44 +02:00
|
|
|
size_t j;
|
|
|
|
for (j = 0; j < game.controllerButton_map.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_map[j])
|
|
|
|
{
|
|
|
|
dupe = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!dupe)
|
|
|
|
{
|
|
|
|
game.controllerButton_map.push_back(i);
|
|
|
|
music.playef(11);
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_flip[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_flip.erase(game.controllerButton_flip.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_esc.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_esc[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_esc.erase(game.controllerButton_esc.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_restart.size(); j += 1)
|
2020-08-09 00:41:59 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_restart[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_restart.erase(game.controllerButton_restart.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_interact.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_interact[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_interact.erase(game.controllerButton_interact.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-04-02 23:06:56 +02:00
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
case 3:
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
2021-04-19 08:23:44 +02:00
|
|
|
size_t j;
|
|
|
|
for (j = 0; j < game.controllerButton_esc.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_esc[j])
|
|
|
|
{
|
|
|
|
dupe = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!dupe)
|
|
|
|
{
|
|
|
|
game.controllerButton_esc.push_back(i);
|
|
|
|
music.playef(11);
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_flip[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_flip.erase(game.controllerButton_flip.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_map.size(); j += 1)
|
2020-04-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_map[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_map.erase(game.controllerButton_map.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_restart.size(); j += 1)
|
2020-08-09 00:41:59 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_restart[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_restart.erase(game.controllerButton_restart.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_interact.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_interact[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_interact.erase(game.controllerButton_interact.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-08-09 00:41:59 +02:00
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
case 4:
|
2020-08-09 00:41:59 +02:00
|
|
|
{
|
2021-04-19 08:23:44 +02:00
|
|
|
size_t j;
|
|
|
|
for (j = 0; j < game.controllerButton_restart.size(); j += 1)
|
2020-08-09 00:41:59 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_restart[j])
|
|
|
|
{
|
|
|
|
dupe = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!dupe)
|
|
|
|
{
|
|
|
|
game.controllerButton_restart.push_back(i);
|
|
|
|
music.playef(11);
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_flip[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_flip.erase(game.controllerButton_flip.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (j = 0; j < game.controllerButton_map.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_map[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_map.erase(game.controllerButton_map.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (j = 0; j < game.controllerButton_esc.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_esc[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_esc.erase(game.controllerButton_esc.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (j = 0; j < game.controllerButton_interact.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_interact[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_interact.erase(game.controllerButton_interact.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 5:
|
|
|
|
{
|
|
|
|
size_t j;
|
|
|
|
for (j = 0; j < game.controllerButton_interact.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_interact[j])
|
|
|
|
{
|
|
|
|
dupe = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!dupe)
|
|
|
|
{
|
|
|
|
game.controllerButton_interact.push_back(i);
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
|
2020-08-09 00:41:59 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_flip[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_flip.erase(game.controllerButton_flip.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_map.size(); j += 1)
|
2020-08-09 00:41:59 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_map[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_map.erase(game.controllerButton_map.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_esc.size(); j += 1)
|
2020-08-09 00:41:59 +02:00
|
|
|
{
|
|
|
|
if (i == game.controllerButton_esc[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_esc.erase(game.controllerButton_esc.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
2021-04-19 08:23:44 +02:00
|
|
|
for (j = 0; j < game.controllerButton_restart.size(); j += 1)
|
|
|
|
{
|
|
|
|
if (i == game.controllerButton_restart[j])
|
|
|
|
{
|
|
|
|
game.controllerButton_restart.erase(game.controllerButton_restart.begin() + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-04-02 23:06:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-03-06 23:46:41 +01:00
|
|
|
static void toggleflipmode(void)
|
|
|
|
{
|
|
|
|
graphics.setflipmode = !graphics.setflipmode;
|
2021-03-06 22:59:13 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2021-03-06 23:46:41 +01:00
|
|
|
if (graphics.setflipmode)
|
|
|
|
{
|
|
|
|
music.playef(18);
|
|
|
|
game.screenshake = 10;
|
|
|
|
game.flashlight = 5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-26 04:11:27 +01:00
|
|
|
static bool fadetomode = false;
|
|
|
|
static int fadetomodedelay = 0;
|
2021-03-20 07:34:41 +01:00
|
|
|
static int gotomode = 0;
|
2021-03-26 04:11:27 +01:00
|
|
|
|
2021-03-26 04:10:36 +01:00
|
|
|
static void startmode(const int mode)
|
|
|
|
{
|
2021-03-20 07:34:41 +01:00
|
|
|
gotomode = mode;
|
2021-03-26 04:10:36 +01:00
|
|
|
graphics.fademode = 2; /* fading out */
|
2021-03-26 04:11:27 +01:00
|
|
|
fadetomode = true;
|
2021-08-06 00:05:14 +02:00
|
|
|
fadetomodedelay = 19;
|
2021-03-26 04:10:36 +01:00
|
|
|
}
|
|
|
|
|
2021-12-18 08:35:08 +01:00
|
|
|
static void handlefadetomode(void)
|
|
|
|
{
|
|
|
|
if (fadetomodedelay > 0)
|
|
|
|
{
|
|
|
|
--fadetomodedelay;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fadetomode = false;
|
|
|
|
script.startgamemode(gotomode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-12 02:43:17 +02:00
|
|
|
static int* user_changing_volume = NULL;
|
|
|
|
static int previous_volume = 0;
|
|
|
|
|
|
|
|
static void initvolumeslider(const int menuoption)
|
|
|
|
{
|
|
|
|
switch (menuoption)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
game.slidermode = SLIDER_MUSICVOLUME;
|
|
|
|
user_changing_volume = &music.user_music_volume;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
game.slidermode = SLIDER_SOUNDVOLUME;
|
|
|
|
user_changing_volume = &music.user_sound_volume;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SDL_assert(0 && "Unhandled volume slider option!");
|
|
|
|
game.slidermode = SLIDER_NONE;
|
|
|
|
user_changing_volume = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
previous_volume = *user_changing_volume;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void deinitvolumeslider(void)
|
|
|
|
{
|
|
|
|
user_changing_volume = NULL;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
game.slidermode = SLIDER_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void slidermodeinput(void)
|
|
|
|
{
|
|
|
|
if (user_changing_volume == NULL)
|
|
|
|
{
|
|
|
|
SDL_assert(0 && "user_changing_volume is NULL!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.press_left)
|
|
|
|
{
|
|
|
|
*user_changing_volume -= USER_VOLUME_STEP;
|
|
|
|
}
|
|
|
|
else if (game.press_right)
|
|
|
|
{
|
|
|
|
*user_changing_volume += USER_VOLUME_STEP;
|
|
|
|
}
|
|
|
|
*user_changing_volume = clamp(*user_changing_volume, 0, USER_VOLUME_MAX);
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
static void menuactionpress(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-17 00:19:17 +02:00
|
|
|
switch (game.currentmenuname)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::mainmenu:
|
2020-04-15 19:14:42 +02:00
|
|
|
#if defined(MAKEANDPLAY)
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#define MPOFFSET -1
|
|
|
|
#else
|
|
|
|
#define MPOFFSET 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(NO_CUSTOM_LEVELS)
|
|
|
|
#define NOCUSTOMSOFFSET -1
|
|
|
|
#else
|
|
|
|
#define NOCUSTOMSOFFSET 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define OFFSET (MPOFFSET+NOCUSTOMSOFFSET)
|
|
|
|
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
#if !defined(MAKEANDPLAY)
|
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//Play
|
2020-04-26 22:41:35 +02:00
|
|
|
if (!game.save_exists() && !game.anything_unlocked())
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-15 19:14:42 +02:00
|
|
|
//No saves exist, just start a new game
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(0);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-15 19:14:42 +02:00
|
|
|
//Bring you to the normal playmenu
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::play);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#endif
|
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2020-04-16 05:10:11 +02:00
|
|
|
case OFFSET+1:
|
2020-04-15 19:14:42 +02:00
|
|
|
//Bring you to the normal playmenu
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::playerworlds);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#endif
|
2020-04-16 05:10:11 +02:00
|
|
|
case OFFSET+2:
|
2020-04-15 19:14:42 +02:00
|
|
|
//Options
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::options);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#if !defined(MAKEANDPLAY)
|
2021-04-09 12:09:12 +02:00
|
|
|
case OFFSET+3:
|
2021-04-09 17:53:55 +02:00
|
|
|
//Credits
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::credits);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#else
|
|
|
|
#undef MPOFFSET
|
|
|
|
#define MPOFFSET -2
|
|
|
|
#endif
|
2021-04-09 12:09:12 +02:00
|
|
|
case OFFSET+4:
|
2021-02-22 09:28:43 +01:00
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::youwannaquit);
|
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#undef OFFSET
|
|
|
|
#undef NOCUSTOMSOFFSET
|
|
|
|
#undef MPOFFSET
|
2020-04-16 05:10:11 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2020-04-02 23:06:56 +02:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::levellist:
|
2021-08-12 04:48:40 +02:00
|
|
|
{
|
2021-02-21 00:40:11 +01:00
|
|
|
const bool nextlastoptions = cl.ListOfMetaData.size() > 8;
|
2020-04-15 19:14:42 +02:00
|
|
|
if(game.currentmenuoption==(int)game.menuoptions.size()-1){
|
|
|
|
//go back to menu
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2021-08-12 04:48:40 +02:00
|
|
|
}else if(nextlastoptions && game.currentmenuoption==(int)game.menuoptions.size()-2){
|
2020-04-17 08:05:49 +02:00
|
|
|
//previous page
|
|
|
|
music.playef(11);
|
|
|
|
if(game.levelpage==0){
|
2021-02-21 00:40:11 +01:00
|
|
|
game.levelpage=(cl.ListOfMetaData.size()-1)/8;
|
2020-04-17 08:05:49 +02:00
|
|
|
}else{
|
|
|
|
game.levelpage--;
|
|
|
|
}
|
|
|
|
game.createmenu(Menu::levellist, true);
|
|
|
|
game.currentmenuoption=game.menuoptions.size()-2;
|
|
|
|
map.nexttowercolour();
|
2021-08-12 04:48:40 +02:00
|
|
|
}else if(nextlastoptions && game.currentmenuoption==(int)game.menuoptions.size()-3){
|
2020-04-15 19:14:42 +02:00
|
|
|
//next page
|
|
|
|
music.playef(11);
|
2021-02-21 00:40:11 +01:00
|
|
|
if((size_t) ((game.levelpage*8)+8) >= cl.ListOfMetaData.size()){
|
2020-04-15 19:14:42 +02:00
|
|
|
game.levelpage=0;
|
|
|
|
}else{
|
|
|
|
game.levelpage++;
|
|
|
|
}
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::levellist, true);
|
2020-04-17 08:05:49 +02:00
|
|
|
game.currentmenuoption=game.menuoptions.size()-3;
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}else{
|
|
|
|
//Ok, launch the level!
|
|
|
|
//PLAY CUSTOM LEVEL HOOK
|
|
|
|
music.playef(11);
|
|
|
|
game.playcustomlevel=(game.levelpage*8)+game.currentmenuoption;
|
2021-02-21 00:40:11 +01:00
|
|
|
game.customleveltitle=cl.ListOfMetaData[game.playcustomlevel].title;
|
|
|
|
game.customlevelfilename=cl.ListOfMetaData[game.playcustomlevel].filename;
|
2020-04-02 23:06:56 +02:00
|
|
|
|
2021-02-21 00:40:11 +01:00
|
|
|
std::string name = "saves/" + cl.ListOfMetaData[game.playcustomlevel].filename.substr(7) + ".vvv";
|
2020-06-04 02:39:21 +02:00
|
|
|
tinyxml2::XMLDocument doc;
|
|
|
|
if (!FILESYSTEM_loadTiXml2Document(name.c_str(), doc)){
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(22);
|
2020-04-15 19:14:42 +02:00
|
|
|
}else{
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::quickloadlevel);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2021-08-12 04:48:40 +02:00
|
|
|
}
|
2020-04-02 23:06:56 +02:00
|
|
|
#endif
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::quickloadlevel:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
|
|
|
{
|
|
|
|
case 0: //continue save
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(23);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(22);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-08-12 05:26:58 +02:00
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::deletequicklevel);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
2020-04-17 21:10:07 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2020-04-02 23:06:56 +02:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2021-08-12 05:26:58 +02:00
|
|
|
case Menu::deletequicklevel:
|
|
|
|
switch (game.currentmenuoption)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
music.playef(11);
|
|
|
|
game.returnmenu();
|
|
|
|
break;
|
|
|
|
case 1:
|
2021-02-21 00:40:11 +01:00
|
|
|
game.customdeletequick(cl.ListOfMetaData[game.playcustomlevel].filename);
|
2021-08-12 05:26:58 +02:00
|
|
|
game.returntomenu(Menu::levellist);
|
|
|
|
game.flashlight = 5;
|
|
|
|
game.screenshake = 15;
|
|
|
|
music.playef(23);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::playerworlds:
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#if defined(NO_EDITOR)
|
|
|
|
#define OFFSET -1
|
|
|
|
#else
|
|
|
|
#define OFFSET 0
|
|
|
|
#endif
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
|
|
|
{
|
|
|
|
case 0:
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
|
|
|
game.levelpage=0;
|
2021-02-21 00:40:11 +01:00
|
|
|
cl.getDirectoryData();
|
2020-04-15 19:14:42 +02:00
|
|
|
game.loadcustomlevelstats(); //Should only load a file if it's needed
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::levellist);
|
2021-08-07 07:26:48 +02:00
|
|
|
if (FILESYSTEM_levelDirHasError())
|
|
|
|
{
|
|
|
|
game.createmenu(Menu::warninglevellist);
|
|
|
|
}
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#if !defined(NO_EDITOR)
|
2020-04-16 05:10:11 +02:00
|
|
|
case 1:
|
2020-04-15 19:14:42 +02:00
|
|
|
//LEVEL EDITOR HOOK
|
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(20);
|
2020-04-15 19:14:42 +02:00
|
|
|
ed.filename="";
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#endif
|
2020-04-16 05:10:11 +02:00
|
|
|
case OFFSET+2:
|
2020-04-18 03:50:10 +02:00
|
|
|
//"OPENFOLDERHOOK"
|
2020-04-18 17:06:06 +02:00
|
|
|
if (FILESYSTEM_openDirectoryEnabled()
|
|
|
|
&& FILESYSTEM_openDirectory(FILESYSTEM_getUserLevelDirectory()))
|
2020-04-18 03:50:10 +02:00
|
|
|
{
|
|
|
|
music.playef(11);
|
|
|
|
SDL_MinimizeWindow(graphics.screenbuffer->m_window);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
music.playef(2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case OFFSET+3:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
De-duplicate copy-pasted input/render code in menus
This removes duplicate code that came about as a result of various
possible permutations of menu options, depending on being M&P, having no
custom level support, having no editor support, and having MMMMMM.
The menus with such permutations are the following:
- main menu
- "start game" is gone in MAKEANDPLAY
- "player levels" is gone in NO_CUSTOM_LEVELS
- "view credits" is gone in MAKEANDPLAY
- "game options"
- "unlock play data" is gone in MAKEANDPLAY
- "soundtrack" is gone if you don't have an mmmmmm.vvv file
- "player levels"
- "level editor" is gone in NO_EDITOR
I achieve this de-duplication by clever use of calculating offsets,
which I feel is the best way to de-duplicate the code with the least
amount of work, if a little brittle.
The other options are to (1) put function pointers on each MenuOption
object, which is pretty verbose and would inflate Game::createmenu() by
a lot, (2) switch all game.currentmenuoption checks to instead check for
the text of the currently-selected menu option, which is very
error-prone because if you make a typo it won't be caught at
compile-time, (3) add a unique ID to each MenuOption object that
represents a text but will error at compile-time if you make a typo,
however this just duplicates all the menu option text, which is more
code than was duplicated previously.
So I just went with this one.
2020-04-16 02:59:03 +02:00
|
|
|
#undef OFFSET
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2020-04-02 23:06:56 +02:00
|
|
|
#endif
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::errornostart:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::mainmenu);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::graphicoptions:
|
2021-04-23 01:18:06 +02:00
|
|
|
if (graphics.screenbuffer == NULL)
|
|
|
|
{
|
|
|
|
SDL_assert(0 && "Screenbuffer is NULL!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
|
|
|
{
|
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
|
|
|
graphics.screenbuffer->toggleFullScreen();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
|
|
|
graphics.screenbuffer->toggleStretchMode();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-06-30 22:30:59 +02:00
|
|
|
// resize to nearest multiple
|
|
|
|
if (graphics.screenbuffer->isWindowed)
|
|
|
|
{
|
|
|
|
music.playef(11);
|
|
|
|
graphics.screenbuffer->ResizeToNearestMultiple();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-06-30 22:30:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
music.playef(2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
|
|
|
graphics.screenbuffer->toggleLinearFilter();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-06-30 22:30:59 +02:00
|
|
|
case 4:
|
2020-04-15 19:14:42 +02:00
|
|
|
//change smoothing
|
|
|
|
music.playef(11);
|
|
|
|
graphics.screenbuffer->badSignalEffect= !graphics.screenbuffer->badSignalEffect;
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-06-30 22:30:59 +02:00
|
|
|
case 5:
|
2021-09-15 05:23:22 +02:00
|
|
|
/* FIXME: Upgrade to SDL 2.0.18 and remove this ifdef when it releases! */
|
|
|
|
#if SDL_VERSION_ATLEAST(2, 0, 17)
|
2020-05-04 22:19:47 +02:00
|
|
|
//toggle vsync
|
|
|
|
music.playef(11);
|
2021-09-15 05:23:22 +02:00
|
|
|
graphics.screenbuffer->toggleVSync();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-07-08 20:38:55 +02:00
|
|
|
#endif
|
2020-07-08 20:43:04 +02:00
|
|
|
break;
|
2020-04-16 05:10:11 +02:00
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2021-04-11 22:52:35 +02:00
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::youwannaquit:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//bye!
|
|
|
|
music.playef(2);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(100);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2021-02-22 09:28:43 +01:00
|
|
|
map.nexttowercolour();
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::setinvincibility:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
map.invincibility = !map.invincibility;
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2020-04-17 01:02:01 +02:00
|
|
|
case Menu::setslowdown:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
game.slowdown = 30;
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-15 19:14:42 +02:00
|
|
|
game.slowdown = 24;
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-04-15 19:14:42 +02:00
|
|
|
game.slowdown = 18;
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2020-04-15 19:14:42 +02:00
|
|
|
game.slowdown = 12;
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2021-04-09 17:53:55 +02:00
|
|
|
case Menu::speedrunneroptions:
|
|
|
|
switch (game.currentmenuoption)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
// Glitchrunner mode
|
|
|
|
music.playef(11);
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
game.createmenu(Menu::setglitchrunner);
|
|
|
|
game.currentmenuoption = GlitchrunnerMode_get();
|
|
|
|
map.nexttowercolour();
|
2021-04-09 17:53:55 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
/* Input delay */
|
|
|
|
music.playef(11);
|
|
|
|
game.inputdelay = !game.inputdelay;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
break;
|
|
|
|
case 2:
|
2021-04-19 08:23:44 +02:00
|
|
|
/* Interact button toggle */
|
|
|
|
music.playef(11);
|
|
|
|
game.separate_interact = !game.separate_interact;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
break;
|
|
|
|
case 3:
|
2021-04-09 17:53:55 +02:00
|
|
|
// toggle fake load screen
|
|
|
|
game.skipfakeload = !game.skipfakeload;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
music.playef(11);
|
|
|
|
break;
|
2021-08-05 23:31:20 +02:00
|
|
|
case 4:
|
|
|
|
// toggle in game timer
|
|
|
|
game.showingametimer = !game.showingametimer;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
music.playef(11);
|
|
|
|
break;
|
2021-04-09 17:53:55 +02:00
|
|
|
default:
|
|
|
|
//back
|
|
|
|
music.playef(11);
|
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
case Menu::setglitchrunner:
|
|
|
|
GlitchrunnerMode_set((enum GlitchrunnerMode) game.currentmenuoption);
|
|
|
|
music.playef(11);
|
|
|
|
game.returnmenu();
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2020-06-30 22:06:19 +02:00
|
|
|
case Menu::advancedoptions:
|
|
|
|
switch (game.currentmenuoption)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
// toggle unfocus pause
|
|
|
|
game.disablepause = !game.disablepause;
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-06-30 22:06:19 +02:00
|
|
|
music.playef(11);
|
|
|
|
break;
|
2021-04-17 07:00:33 +02:00
|
|
|
case 1:
|
2021-08-05 21:20:05 +02:00
|
|
|
/* toggle unfocus music pause */
|
|
|
|
game.disableaudiopause = !game.disableaudiopause;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
music.playef(11);
|
|
|
|
break;
|
|
|
|
case 2:
|
2020-06-30 22:06:19 +02:00
|
|
|
// toggle translucent roomname BG
|
|
|
|
graphics.translucentroomname = !graphics.translucentroomname;
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-06-30 22:06:19 +02:00
|
|
|
music.playef(11);
|
|
|
|
break;
|
2021-04-02 00:39:56 +02:00
|
|
|
default:
|
2020-06-30 22:06:19 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::accessibility:
|
2021-04-09 17:53:55 +02:00
|
|
|
{
|
|
|
|
int accessibilityoffset = 0;
|
2021-04-09 12:09:12 +02:00
|
|
|
#if !defined(MAKEANDPLAY)
|
2021-04-09 17:53:55 +02:00
|
|
|
accessibilityoffset = 1;
|
|
|
|
if (game.currentmenuoption == 0) {
|
|
|
|
//unlock play options
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::unlockmenu);
|
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
2021-04-09 12:09:12 +02:00
|
|
|
#endif
|
2021-04-09 17:53:55 +02:00
|
|
|
if (game.currentmenuoption == accessibilityoffset + 0) {
|
|
|
|
//invincibility
|
2021-05-04 03:22:59 +02:00
|
|
|
if (!game.ingame_titlemode || !game.incompetitive())
|
2021-04-09 17:53:55 +02:00
|
|
|
{
|
|
|
|
if (!map.invincibility)
|
|
|
|
{
|
|
|
|
game.createmenu(Menu::setinvincibility);
|
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
map.invincibility = !map.invincibility;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
}
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
music.playef(2);
|
|
|
|
map.invincibility = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == accessibilityoffset + 1) {
|
|
|
|
//change game speed
|
2021-05-04 03:22:59 +02:00
|
|
|
if (!game.ingame_titlemode || !game.incompetitive())
|
2021-04-09 17:53:55 +02:00
|
|
|
{
|
|
|
|
game.createmenu(Menu::setslowdown);
|
|
|
|
map.nexttowercolour();
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
music.playef(2);
|
|
|
|
game.slowdown = 30;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == accessibilityoffset + 2) {
|
|
|
|
//disable animated backgrounds
|
|
|
|
game.colourblindmode = !game.colourblindmode;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
graphics.towerbg.tdrawback = true;
|
|
|
|
graphics.titlebg.tdrawback = true;
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == accessibilityoffset + 3) {
|
|
|
|
//disable screeneffects
|
|
|
|
game.noflashingmode = !game.noflashingmode;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
if (!game.noflashingmode)
|
|
|
|
{
|
|
|
|
music.playef(18);
|
|
|
|
game.screenshake = 10;
|
|
|
|
game.flashlight = 5;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == accessibilityoffset + 4) {
|
|
|
|
//disable text outline
|
|
|
|
graphics.notextoutline = !graphics.notextoutline;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == accessibilityoffset + 5) {
|
|
|
|
//back
|
|
|
|
music.playef(11);
|
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Menu::gameplayoptions:
|
|
|
|
{
|
|
|
|
int gameplayoptionsoffset = 0;
|
2021-04-09 12:09:12 +02:00
|
|
|
#if !defined(MAKEANDPLAY)
|
2021-04-09 17:53:55 +02:00
|
|
|
if (game.ingame_titlemode && game.unlock[18])
|
2021-04-09 12:09:12 +02:00
|
|
|
#endif
|
2021-04-09 17:53:55 +02:00
|
|
|
{
|
|
|
|
gameplayoptionsoffset = 1;
|
|
|
|
if (game.currentmenuoption == 0) {
|
|
|
|
toggleflipmode();
|
|
|
|
// Fix wrong area music in Tower (Positive Force vs. ecroF evitisoP)
|
|
|
|
if (map.custommode)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
int area = map.area(game.roomx, game.roomy);
|
|
|
|
if (area == 3 || area == 11)
|
|
|
|
{
|
|
|
|
if (graphics.setflipmode)
|
|
|
|
{
|
|
|
|
music.play(9); // ecroF evitisoP
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
music.play(2); // Positive Force
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.currentmenuoption == gameplayoptionsoffset + 0)
|
|
|
|
{
|
|
|
|
//Toggle 30+ FPS
|
|
|
|
music.playef(11);
|
|
|
|
game.over30mode = !game.over30mode;
|
|
|
|
game.savestatsandsettings_menu();
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == gameplayoptionsoffset + 1)
|
|
|
|
{
|
|
|
|
//Speedrunner options
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::speedrunneroptions);
|
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == gameplayoptionsoffset + 2)
|
|
|
|
{
|
|
|
|
//Advanced options
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::advancedoptions);
|
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == gameplayoptionsoffset + 3)
|
|
|
|
{
|
|
|
|
//Clear Data
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::cleardatamenu);
|
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
2021-08-12 05:54:02 +02:00
|
|
|
else if (game.currentmenuoption == gameplayoptionsoffset + 4)
|
|
|
|
{
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::clearcustomdatamenu);
|
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == gameplayoptionsoffset + 5) {
|
2021-04-09 17:53:55 +02:00
|
|
|
//return to previous menu
|
|
|
|
music.playef(11);
|
2021-04-11 22:52:35 +02:00
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
2021-04-09 17:53:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::options:
|
2021-04-09 17:53:55 +02:00
|
|
|
switch (game.currentmenuoption)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
//gameplay options
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::gameplayoptions);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
//graphic options
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::graphicoptions);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
case 2:
|
2021-04-12 00:18:35 +02:00
|
|
|
/* Audio options */
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::audiooptions);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
case 3:
|
2021-04-09 17:53:55 +02:00
|
|
|
//gamepad options
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::controller);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2021-04-12 00:18:35 +02:00
|
|
|
case 4:
|
2021-04-09 17:53:55 +02:00
|
|
|
//accessibility options
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::accessibility);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2021-04-12 00:18:35 +02:00
|
|
|
default:
|
|
|
|
/* Return */
|
|
|
|
music.playef(11);
|
|
|
|
if (game.ingame_titlemode)
|
|
|
|
{
|
|
|
|
game.returntoingame();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
break;
|
2021-04-09 17:53:55 +02:00
|
|
|
}
|
2021-04-12 00:18:35 +02:00
|
|
|
break;
|
|
|
|
case Menu::audiooptions:
|
|
|
|
switch (game.currentmenuoption)
|
2021-04-09 17:53:55 +02:00
|
|
|
{
|
2021-04-12 00:18:35 +02:00
|
|
|
case 0:
|
|
|
|
case 1:
|
2021-04-12 02:43:17 +02:00
|
|
|
music.playef(11);
|
|
|
|
if (game.slidermode == SLIDER_NONE)
|
|
|
|
{
|
|
|
|
initvolumeslider(game.currentmenuoption);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
deinitvolumeslider();
|
|
|
|
}
|
2021-04-12 00:18:35 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (!music.mmmmmm)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Toggle MMMMMM */
|
2021-04-09 17:53:55 +02:00
|
|
|
music.usingmmmmmm = !music.usingmmmmmm;
|
|
|
|
music.playef(11);
|
|
|
|
if (music.currentsong > -1)
|
|
|
|
{
|
|
|
|
music.play(music.currentsong);
|
|
|
|
}
|
|
|
|
game.savestatsandsettings_menu();
|
2021-04-12 00:18:35 +02:00
|
|
|
break;
|
2021-04-09 17:53:55 +02:00
|
|
|
}
|
|
|
|
|
2021-04-12 00:18:35 +02:00
|
|
|
if (game.currentmenuoption == 2 + (int) music.mmmmmm)
|
2021-04-09 17:53:55 +02:00
|
|
|
{
|
2021-04-12 00:18:35 +02:00
|
|
|
/* Return */
|
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
2021-06-13 00:33:44 +02:00
|
|
|
music.playef(11);
|
2021-04-09 17:53:55 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::unlockmenutrials:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
case 0: //unlock 1
|
2020-04-15 19:14:42 +02:00
|
|
|
game.unlock[9] = true;
|
|
|
|
game.unlocknotify[9] = true;
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenutrials, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2021-09-07 03:56:39 +02:00
|
|
|
case 1: //unlock 2
|
2020-04-15 19:14:42 +02:00
|
|
|
game.unlock[10] = true;
|
|
|
|
game.unlocknotify[10] = true;
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenutrials, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2021-09-07 03:56:39 +02:00
|
|
|
case 2: //unlock 3
|
2020-04-15 19:14:42 +02:00
|
|
|
game.unlock[11] = true;
|
|
|
|
game.unlocknotify[11] = true;
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenutrials, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2021-09-07 03:56:39 +02:00
|
|
|
case 3: //unlock 4
|
2020-04-15 19:14:42 +02:00
|
|
|
game.unlock[12] = true;
|
|
|
|
game.unlocknotify[12] = true;
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenutrials, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2021-09-07 03:56:39 +02:00
|
|
|
case 4: //unlock 5
|
2020-04-15 19:14:42 +02:00
|
|
|
game.unlock[13] = true;
|
|
|
|
game.unlocknotify[13] = true;
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenutrials, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2021-09-07 03:56:39 +02:00
|
|
|
case 5: //unlock 6
|
2020-04-15 19:14:42 +02:00
|
|
|
game.unlock[14] = true;
|
|
|
|
game.unlocknotify[14] = true;
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenutrials, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2021-09-07 03:56:39 +02:00
|
|
|
case 6: //back
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::unlockmenu:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//unlock time trials separately...
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::unlockmenutrials);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-15 19:14:42 +02:00
|
|
|
//unlock intermissions
|
|
|
|
music.playef(11);
|
|
|
|
game.unlock[16] = true;
|
|
|
|
game.unlocknotify[16] = true;
|
|
|
|
game.unlock[6] = true;
|
|
|
|
game.unlock[7] = true;
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenu, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-04-15 19:14:42 +02:00
|
|
|
//unlock no death mode
|
|
|
|
music.playef(11);
|
|
|
|
game.unlock[17] = true;
|
|
|
|
game.unlocknotify[17] = true;
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenu, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2020-04-15 19:14:42 +02:00
|
|
|
//unlock flip mode
|
|
|
|
music.playef(11);
|
|
|
|
game.unlock[18] = true;
|
|
|
|
game.unlocknotify[18] = true;
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenu, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2020-04-15 19:14:42 +02:00
|
|
|
//unlock jukebox
|
|
|
|
music.playef(11);
|
|
|
|
game.stat_trinkets = 20;
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenu, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 5:
|
2020-04-15 19:14:42 +02:00
|
|
|
//unlock secret lab
|
|
|
|
music.playef(11);
|
|
|
|
game.unlock[8] = true;
|
|
|
|
game.unlocknotify[8] = true;
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::unlockmenu, true);
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::credits:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//next page
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits2, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-17 08:37:49 +02:00
|
|
|
case 1:
|
|
|
|
//last page
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::credits6, true);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2020-04-16 05:10:11 +02:00
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::credits2:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//next page
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits25, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-17 08:37:49 +02:00
|
|
|
//previous page
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::credits, true);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
case 2:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::credits25:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//next page
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits3, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-17 08:37:49 +02:00
|
|
|
case 1:
|
|
|
|
//previous page
|
|
|
|
music.playef(11);
|
|
|
|
game.createmenu(Menu::credits2, true);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2020-04-16 05:10:11 +02:00
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::credits3:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//next page
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index += 9;
|
|
|
|
|
Turn (super)patrons/githubfriends into arrays & move them to new file
So, originally, I wanted to keep them on Game, but it turns out that if
I initialize it in Game.cpp, the compiler will complain that other files
won't know what's actually inside the array. To do that, I'd have to
initialize it in Game.h. But I don't want to initialize it in Game.h
because that'd mean recompiling a lot of unnecessary files whenever
someone gets added to the credits.
So, I moved all the patrons, superpatrons, and GitHub contributors to a
new file, Credits.h, which only contains the list (and the credits max
position calculation). That way, whenever someone gets added, only the
minimal amount of files need to be recompiled.
2020-07-03 12:13:15 +02:00
|
|
|
if (game.current_credits_list_index >= (int)SDL_arraysize(Credits::superpatrons))
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
// No more super patrons. Move to the next credits section
|
|
|
|
game.current_credits_list_index = 0;
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits4, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// There are more super patrons. Refresh the menu with the next ones
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits3, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
|
2020-04-17 08:37:49 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
//previous page
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index -= 9;
|
|
|
|
|
|
|
|
if (game.current_credits_list_index < 0)
|
|
|
|
{
|
|
|
|
//No more super patrons. Move to the previous credits section
|
|
|
|
game.current_credits_list_index = 0;
|
|
|
|
game.createmenu(Menu::credits25, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//There are more super patrons. Refresh the menu with the next ones
|
|
|
|
game.createmenu(Menu::credits3, true);
|
|
|
|
}
|
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index = 0;
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::credits4:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//next page
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index += 14;
|
|
|
|
|
Turn (super)patrons/githubfriends into arrays & move them to new file
So, originally, I wanted to keep them on Game, but it turns out that if
I initialize it in Game.cpp, the compiler will complain that other files
won't know what's actually inside the array. To do that, I'd have to
initialize it in Game.h. But I don't want to initialize it in Game.h
because that'd mean recompiling a lot of unnecessary files whenever
someone gets added to the credits.
So, I moved all the patrons, superpatrons, and GitHub contributors to a
new file, Credits.h, which only contains the list (and the credits max
position calculation). That way, whenever someone gets added, only the
minimal amount of files need to be recompiled.
2020-07-03 12:13:15 +02:00
|
|
|
if (game.current_credits_list_index >= (int)SDL_arraysize(Credits::patrons))
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
// No more patrons. Move to the next credits section
|
|
|
|
game.current_credits_list_index = 0;
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits5, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// There are more patrons. Refresh the menu with the next ones
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits4, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
|
2020-04-17 08:37:49 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
//previous page
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index -= 14;
|
|
|
|
|
|
|
|
if (game.current_credits_list_index < 0)
|
|
|
|
{
|
|
|
|
//No more patrons. Move to the previous credits section
|
Turn (super)patrons/githubfriends into arrays & move them to new file
So, originally, I wanted to keep them on Game, but it turns out that if
I initialize it in Game.cpp, the compiler will complain that other files
won't know what's actually inside the array. To do that, I'd have to
initialize it in Game.h. But I don't want to initialize it in Game.h
because that'd mean recompiling a lot of unnecessary files whenever
someone gets added to the credits.
So, I moved all the patrons, superpatrons, and GitHub contributors to a
new file, Credits.h, which only contains the list (and the credits max
position calculation). That way, whenever someone gets added, only the
minimal amount of files need to be recompiled.
2020-07-03 12:13:15 +02:00
|
|
|
game.current_credits_list_index = SDL_arraysize(Credits::superpatrons) - 1 - (SDL_arraysize(Credits::superpatrons)-1)%9;
|
2020-04-17 08:37:49 +02:00
|
|
|
game.createmenu(Menu::credits3, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//There are more patrons. Refresh the menu with the next ones
|
|
|
|
game.createmenu(Menu::credits4, true);
|
|
|
|
}
|
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index = 0;
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::credits5:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//next page
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index += 9;
|
|
|
|
|
Turn (super)patrons/githubfriends into arrays & move them to new file
So, originally, I wanted to keep them on Game, but it turns out that if
I initialize it in Game.cpp, the compiler will complain that other files
won't know what's actually inside the array. To do that, I'd have to
initialize it in Game.h. But I don't want to initialize it in Game.h
because that'd mean recompiling a lot of unnecessary files whenever
someone gets added to the credits.
So, I moved all the patrons, superpatrons, and GitHub contributors to a
new file, Credits.h, which only contains the list (and the credits max
position calculation). That way, whenever someone gets added, only the
minimal amount of files need to be recompiled.
2020-07-03 12:13:15 +02:00
|
|
|
if (game.current_credits_list_index >= (int)SDL_arraysize(Credits::githubfriends))
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
// No more GitHub contributors. Move to the next credits section
|
|
|
|
game.current_credits_list_index = 0;
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits6, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// There are more GitHub contributors. Refresh the menu with the next ones
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits5, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
|
2020-04-17 08:37:49 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
//previous page
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index -= 9;
|
|
|
|
|
|
|
|
if (game.current_credits_list_index < 0)
|
|
|
|
{
|
|
|
|
//No more GitHub contributors. Move to the previous credits section
|
Turn (super)patrons/githubfriends into arrays & move them to new file
So, originally, I wanted to keep them on Game, but it turns out that if
I initialize it in Game.cpp, the compiler will complain that other files
won't know what's actually inside the array. To do that, I'd have to
initialize it in Game.h. But I don't want to initialize it in Game.h
because that'd mean recompiling a lot of unnecessary files whenever
someone gets added to the credits.
So, I moved all the patrons, superpatrons, and GitHub contributors to a
new file, Credits.h, which only contains the list (and the credits max
position calculation). That way, whenever someone gets added, only the
minimal amount of files need to be recompiled.
2020-07-03 12:13:15 +02:00
|
|
|
game.current_credits_list_index = SDL_arraysize(Credits::patrons) - 1 - (SDL_arraysize(Credits::patrons)-1)%14;
|
2020-04-17 08:37:49 +02:00
|
|
|
game.createmenu(Menu::credits4, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//There are more GitHub contributors. Refresh the menu with the next ones
|
|
|
|
game.createmenu(Menu::credits5, true);
|
|
|
|
}
|
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
|
|
|
game.current_credits_list_index = 0;
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::credits6:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//first page
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::credits, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-17 08:37:49 +02:00
|
|
|
case 1:
|
|
|
|
//previous page
|
|
|
|
music.playef(11);
|
Turn (super)patrons/githubfriends into arrays & move them to new file
So, originally, I wanted to keep them on Game, but it turns out that if
I initialize it in Game.cpp, the compiler will complain that other files
won't know what's actually inside the array. To do that, I'd have to
initialize it in Game.h. But I don't want to initialize it in Game.h
because that'd mean recompiling a lot of unnecessary files whenever
someone gets added to the credits.
So, I moved all the patrons, superpatrons, and GitHub contributors to a
new file, Credits.h, which only contains the list (and the credits max
position calculation). That way, whenever someone gets added, only the
minimal amount of files need to be recompiled.
2020-07-03 12:13:15 +02:00
|
|
|
game.current_credits_list_index = SDL_arraysize(Credits::githubfriends) - 1 - (SDL_arraysize(Credits::githubfriends)-1)%9;
|
2020-04-17 08:37:49 +02:00
|
|
|
game.createmenu(Menu::credits5, true);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2020-04-16 05:10:11 +02:00
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::play:
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 04:38:42 +02:00
|
|
|
//Do we have the Secret Lab option?
|
2020-04-26 22:09:56 +02:00
|
|
|
int sloffset = game.unlock[8] ? 0 : -1;
|
|
|
|
//Do we have a telesave or quicksave?
|
2020-04-26 22:41:35 +02:00
|
|
|
int ngoffset = game.save_exists() ? 0 : -1;
|
2020-04-15 19:14:42 +02:00
|
|
|
if (game.currentmenuoption == 0)
|
|
|
|
{
|
|
|
|
//continue
|
|
|
|
//right, this depends on what saves you've got
|
2020-04-26 22:41:35 +02:00
|
|
|
if (!game.save_exists())
|
2020-04-26 22:09:56 +02:00
|
|
|
{
|
|
|
|
//You have no saves but have something unlocked, or you couldn't have gotten here
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(0);
|
2020-04-26 22:09:56 +02:00
|
|
|
}
|
|
|
|
else if (game.telesummary == "")
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
//You at least have a quicksave, or you couldn't have gotten here
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(2);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.quicksummary == "")
|
|
|
|
{
|
|
|
|
//You at least have a telesave, or you couldn't have gotten here
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(1);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//go to a menu!
|
|
|
|
music.playef(11);
|
|
|
|
game.loadsummary(); //Prepare save slots to display
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::continuemenu);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
}
|
2020-04-16 04:38:42 +02:00
|
|
|
else if (game.currentmenuoption == 1 && game.unlock[8])
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
Move Secret Lab nocompetitive check to Super Gravitron
It turns out, despite the game attempting to prevent you from using
invincibility or slowdown in the Super Gravitron by simply preventing
you from entering the Secret Lab from the menu, it's still possible to
enter the Super Gravitron with it anyways. Just have invincibility or
slowdown (or both!) enabled, enter the game normally, and talk to
Victoria when you have 20 trinkets, to start the epilogue cutscene.
Yeah, that's a pretty big gaping hole right there...
It's also possible to do a trick that speedrunners use called
telejumping to the Secret Lab to bypass the invincibility/slowdown
check, too.
So rather than single-case patch both of these, I'm going to fix it as
generally as possible, by moving the invincibility/slowdown check to the
gamestate that starts the Super Gravitron, gamestate 9. If you have
invincibility/slowdown enabled, you immediately get sent back to the
Secret Lab. However, this check is ignored in custom levels, because
custom levels may want to use the Super Gravitron and let players have
invincibility/slowdown while doing so (and there are in fact custom
levels out in the wild that use the Super Gravitron; it was like one of
the first things done when people discovered internal scripting).
No message pops up when the game sends you back to the Secret Lab, but
no message popped up when the Secret Lab menu option was disabled
previously in the first place, so I haven't made anything WORSE, per se.
A nice effect of this is that you can have invincibility/slowdown
enabled and still be able to go to the Secret Lab from the menu. This is
useful if you just want to check your trophies and leave, without having
to go out of your way to disable invincibility/slowdown just to go
inside.
2021-05-04 03:57:13 +02:00
|
|
|
music.playef(11);
|
|
|
|
startmode(11);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-26 22:09:56 +02:00
|
|
|
else if (game.currentmenuoption == sloffset+2)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
//play modes
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::playmodes);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
2020-04-26 22:41:35 +02:00
|
|
|
else if (game.currentmenuoption == sloffset+3 && game.save_exists())
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
//newgame
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::newgamewarning);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
2020-04-26 22:09:56 +02:00
|
|
|
else if (game.currentmenuoption == sloffset+ngoffset+4)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::newgamewarning:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//yep
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(0);
|
2020-04-15 19:14:42 +02:00
|
|
|
game.deletequick();
|
|
|
|
game.deletetele();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::controller:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-11-13 02:16:18 +01:00
|
|
|
key.sensitivity++;
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
2020-11-13 02:16:18 +01:00
|
|
|
if(key.sensitivity > 4)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-11-13 02:16:18 +01:00
|
|
|
key.sensitivity = 0;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
Refactor Game::savestats() to not use a default argument
In order to be able to fix the bug #556, I'm planning on adding
ScreenSettings* to the settings.vvv write function. However, that
entails adding another argument to Game::savesettings(), which is going
to be really messy given the default argument of Game::savestats().
That, combined with the fact that the code comment at the site of the
implementation of Game::savestats() being wrong (!!!), leads me to
believe that using default function arguments here isn't worth it.
Instead, what I've done is made it so callers are explicit about whether
or not they're calling savestats(), savesettings(), or both at the same
time. If they are calling both at the same time, then they will be using
a new function named savestatsandsettings().
In short, these are the interface changes:
* bool Game::savestats(bool) has been removed
* bool Game::savestatsandsettings() has been added
* void Game::savestats_menu() has been renamed to
void Game::savestatsandsettings_menu()
* All previous callers of bool Game::savestats() are now using bool
Game::savestatsandsettings()
* The one caller of bool Game::savestats(bool) is now using bool
Game::savestats()
2020-12-22 01:03:19 +01:00
|
|
|
game.savestatsandsettings_menu();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
|
2021-04-19 08:23:44 +02:00
|
|
|
case 6:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2021-03-05 09:54:25 +01:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::cleardatamenu:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-15 19:14:42 +02:00
|
|
|
//yep
|
|
|
|
music.playef(23);
|
|
|
|
game.deletequick();
|
|
|
|
game.deletetele();
|
|
|
|
game.deletestats();
|
Move all settings to settings.vvv
The game previously did this dumb thing where it lumped in all its
settings with its file that tracked your records and unlocks,
`unlock.vvv`. It wasn't really an issue, until 2.3 came along and added
a few settings, suddenly making a problem where 2.3 settings would be
reset by chance if you decided to touch 2.2.
The solution to this is to move all settings to a new file,
`settings.vvv`. However, for compatibility with 2.2, settings will still
be written to `unlock.vvv`.
The game will prioritize reading from `settings.vvv` instead of
`unlock.vvv`, so if there's a setting that's missing from `unlock.vvv`,
no worries there. But if `settings.vvv` is missing, then it'll read
settings from `unlock.vvv`. As well, if `unlock.vvv` is missing, then
`settings.vvv` will be read from instead (I explicitly tested for this,
and found that I had to write special code to handle this case,
otherwise the game would overwrite the existing `settings.vvv` before
reading from it; kids, make sure to always test your code!).
Closes #373 fully.
2020-11-04 08:11:21 +01:00
|
|
|
game.deletesettings();
|
2020-04-15 19:14:42 +02:00
|
|
|
game.flashlight = 5;
|
|
|
|
game.screenshake = 15;
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
Don't go back to main menu when deleting main game save data
Going back to the main menu allowed for glitchiness to occur if you
deleted your save data while in in-game options. This meant you could
then load back in to the game, and then quit to the menu, then open the
options and then jump back in-game, exploring the state of the game
after hardreset() had been called on it. Which is: pretty glitchy.
For example, this meant having your room coordinates be 0,0 (which is
different from 100,100, which is the actual 0,0, thanks for the
100-indexing Terry), which caused some of the room transitions to be
disabled because room transitions were disabled if the
game.door_up/down/left/right variables were -2 or less, and they were
computed based on room coordinates, which meant some of them went
negative if you were 0,0 and not 100,100. At least this was the case
until I removed those variables for, at best, doing nothing, and at
worst, being actively harmful.
Anyways, so deleting your save data now just takes you back to the
previous menu, much like deleting custom level data does. I don't know
why deleting save data put you back on the main menu in the first place.
It's not like the options menu needed to be reloaded or anything. I
checked and this was the behavior in 2.0 as well, so it was probably
added for a dumb reason.
I considered prohibiting data deletion if you were ingame_titlemode, but
as of the moment it seems to be okay (if albeit weird, e.g. returning to
menu while in Secret Lab doesn't place your cursor on the "play"
button), and I can always add such a prohibition later if it was really
causing problems. Can't think of anything bad off of the top of my head,
though.
Btw thanks to Elomavi for discovering that you could do this glitch.
2021-12-18 08:01:47 +01:00
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2021-08-12 05:54:02 +02:00
|
|
|
case Menu::clearcustomdatamenu:
|
|
|
|
switch (game.currentmenuoption)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
music.playef(11);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
game.deletecustomlevelstats();
|
|
|
|
FILESYSTEM_deleteLevelSaves();
|
|
|
|
music.playef(23);
|
|
|
|
game.flashlight = 5;
|
|
|
|
game.screenshake = 15;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2020-04-17 00:19:17 +02:00
|
|
|
case Menu::playmodes:
|
2021-05-04 03:29:23 +02:00
|
|
|
if (game.currentmenuoption == 0 && !game.nocompetitive()) //go to the time trial menu
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::timetrials);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 1 && game.unlock[16])
|
|
|
|
{
|
|
|
|
//intermission mode menu
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::intermissionmenu);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
2021-05-04 03:29:23 +02:00
|
|
|
else if (game.currentmenuoption == 2 && game.unlock[17] && !game.nocompetitive()) //start a game in no death mode
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
music.playef(11);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::startnodeathmode);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 3 && game.unlock[18]) //enable/disable flip mode
|
|
|
|
{
|
2021-03-06 23:46:41 +01:00
|
|
|
toggleflipmode();
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 4)
|
|
|
|
{
|
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Can't do yet! play sad sound
|
|
|
|
music.playef(2);
|
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::startnodeathmode:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0: //start no death mode, disabling cutscenes
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(10);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(9);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::continuemenu:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(1);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(2);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::intermissionmenu:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
|
|
|
music.play(6);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::playint1);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-15 19:14:42 +02:00
|
|
|
music.playef(11);
|
|
|
|
music.play(6);
|
2020-04-16 06:53:36 +02:00
|
|
|
game.createmenu(Menu::playint2);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::playint1:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(12);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(13);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(14);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(15);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::playint2:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(16);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(17);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(18);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(19);
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::gameover2:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
|
|
|
music.play(6);
|
2020-04-27 21:27:12 +02:00
|
|
|
game.returntomenu(Menu::playmodes);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::unlocktimetrials:
|
|
|
|
case Menu::unlocktimetrial:
|
|
|
|
case Menu::unlocknodeathmode:
|
|
|
|
case Menu::unlockintermission:
|
|
|
|
case Menu::unlockflipmode:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 04:26:49 +02:00
|
|
|
game.createmenu(Menu::play, true);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::timetrials:
|
2020-04-15 19:14:42 +02:00
|
|
|
if (game.currentmenuoption == 0 && game.unlock[9]) //space station 1
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(3);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 1 && game.unlock[10]) //lab
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(4);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 2 && game.unlock[11]) //tower
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(5);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 3 && game.unlock[12]) //station 2
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(6);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 4 && game.unlock[13]) //warp
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(7);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 5 && game.unlock[14]) //final
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(8);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.currentmenuoption == 6) //go to the time trial menu
|
|
|
|
{
|
|
|
|
//back
|
|
|
|
music.playef(11);
|
2020-04-17 05:05:01 +02:00
|
|
|
game.returnmenu();
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Can't do yet! play sad sound
|
|
|
|
music.playef(2);
|
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::timetrialcomplete3:
|
2020-04-16 05:10:11 +02:00
|
|
|
switch (game.currentmenuoption)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2020-04-16 05:10:11 +02:00
|
|
|
case 0:
|
2020-04-15 19:14:42 +02:00
|
|
|
//back
|
|
|
|
music.playef(11);
|
|
|
|
music.play(6);
|
2020-06-26 01:22:58 +02:00
|
|
|
game.returntomenu(Menu::timetrials);
|
2020-04-15 19:14:42 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-15 19:14:42 +02:00
|
|
|
//duplicate the above based on given time trial level!
|
|
|
|
if (game.timetriallevel == 0) //space station 1
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(3);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.timetriallevel == 1) //lab
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(4);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.timetriallevel == 2) //tower
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(5);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.timetriallevel == 3) //station 2
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(6);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.timetriallevel == 4) //warp
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(7);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
else if (game.timetriallevel == 5) //final
|
|
|
|
{
|
2020-05-19 03:03:18 +02:00
|
|
|
music.playef(11);
|
2021-03-26 04:10:36 +01:00
|
|
|
startmode(8);
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-16 05:10:11 +02:00
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
|
|
|
case Menu::gamecompletecontinue:
|
|
|
|
case Menu::nodeathmodecomplete2:
|
2020-04-16 05:10:11 +02:00
|
|
|
music.play(6);
|
|
|
|
music.playef(11);
|
2020-04-17 06:25:30 +02:00
|
|
|
game.returnmenu();
|
2020-04-16 05:10:11 +02:00
|
|
|
map.nexttowercolour();
|
2020-04-17 00:19:17 +02:00
|
|
|
break;
|
2020-11-22 03:10:26 +01:00
|
|
|
case Menu::errorsavingsettings:
|
|
|
|
if (game.currentmenuoption == 1)
|
|
|
|
{
|
|
|
|
game.silence_settings_error = true;
|
|
|
|
}
|
|
|
|
music.playef(11);
|
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2021-08-07 05:57:34 +02:00
|
|
|
case Menu::errorloadinglevel:
|
2021-08-07 07:26:48 +02:00
|
|
|
case Menu::warninglevellist:
|
2021-08-07 05:57:34 +02:00
|
|
|
music.playef(11);
|
|
|
|
game.returnmenu();
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2020-04-17 00:19:17 +02:00
|
|
|
default:
|
|
|
|
break;
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
}
|
2020-02-12 05:45:58 +01:00
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void titleinput(void)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
//game.mx = (mouseX / 4);
|
|
|
|
//game.my = (mouseY / 4);
|
2020-02-12 05:45:58 +01:00
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
game.press_left = false;
|
|
|
|
game.press_right = false;
|
|
|
|
game.press_action = false;
|
|
|
|
game.press_map = false;
|
2021-04-19 08:23:44 +02:00
|
|
|
game.press_interact = false;
|
2020-02-12 05:45:58 +01:00
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
if (graphics.flipmode)
|
|
|
|
{
|
|
|
|
if (key.isDown(KEYBOARD_LEFT) || key.isDown(KEYBOARD_DOWN) || key.isDown(KEYBOARD_a) || key.isDown(KEYBOARD_s) || key.controllerWantsRight(true)) game.press_left = true;
|
|
|
|
if (key.isDown(KEYBOARD_RIGHT) || key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_d) || key.isDown(KEYBOARD_w) || key.controllerWantsLeft(true)) game.press_right = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (key.isDown(KEYBOARD_LEFT) || key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_a) || key.isDown(KEYBOARD_w) || key.controllerWantsLeft(true))
|
|
|
|
{
|
|
|
|
game.press_left = true;
|
|
|
|
}
|
|
|
|
if (key.isDown(KEYBOARD_RIGHT) || key.isDown(KEYBOARD_DOWN) || key.isDown(KEYBOARD_d) || key.isDown(KEYBOARD_s) || key.controllerWantsRight(true))
|
|
|
|
{
|
|
|
|
game.press_right = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip)) game.press_action = true;
|
|
|
|
//|| key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_DOWN)) game.press_action = true; //on menus, up and down don't work as action
|
|
|
|
if (key.isDown(KEYBOARD_ENTER)) game.press_map = true;
|
2020-02-12 05:45:58 +01:00
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
//In the menu system, all keypresses are single taps rather than holds. Therefore this test has to be done for all presses
|
2021-02-22 09:28:43 +01:00
|
|
|
if (!game.press_action && !game.press_left && !game.press_right && !key.isDown(27) && !key.isDown(game.controllerButton_esc)) game.jumpheld = false;
|
2020-04-15 19:14:42 +02:00
|
|
|
if (!game.press_map) game.mapheld = false;
|
2020-02-12 05:45:58 +01:00
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
if (!game.jumpheld && graphics.fademode==0)
|
|
|
|
{
|
2021-02-22 09:28:43 +01:00
|
|
|
if (game.press_action || game.press_left || game.press_right || game.press_map || key.isDown(27) || key.isDown(game.controllerButton_esc))
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
game.jumpheld = true;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-02-22 09:28:43 +01:00
|
|
|
if (game.menustart
|
|
|
|
&& game.menucountdown <= 0
|
|
|
|
&& (key.isDown(27) || key.isDown(game.controllerButton_esc)))
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
|
|
|
music.playef(11);
|
2021-02-22 09:28:43 +01:00
|
|
|
if (game.currentmenuname == Menu::mainmenu)
|
2020-06-23 02:29:30 +02:00
|
|
|
{
|
2021-02-22 09:28:43 +01:00
|
|
|
game.createmenu(Menu::youwannaquit);
|
2021-03-26 04:26:45 +01:00
|
|
|
map.nexttowercolour();
|
2020-06-23 02:29:30 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-12 02:43:17 +02:00
|
|
|
if (game.slidermode != SLIDER_NONE)
|
|
|
|
{
|
|
|
|
switch (game.slidermode)
|
|
|
|
{
|
|
|
|
/* Cancel volume change. */
|
|
|
|
case SLIDER_MUSICVOLUME:
|
|
|
|
case SLIDER_SOUNDVOLUME:
|
|
|
|
if (user_changing_volume == NULL)
|
|
|
|
{
|
|
|
|
SDL_assert(0 && "user_changing_volume is NULL!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*user_changing_volume = previous_volume;
|
|
|
|
deinitvolumeslider();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SDL_assert(0 && "Unhandled slider mode!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (game.ingame_titlemode
|
2021-04-11 22:52:35 +02:00
|
|
|
&& game.currentmenuname == Menu::options)
|
2021-02-22 09:28:43 +01:00
|
|
|
{
|
Add graphic options and game options to editor settings
This is a small quality-of-life tweak that makes it so if you're in the
middle of editing a level, you don't have to save the level, exit to the
menu, change whatever setting you wanted, re-enter the editor, and type
in the level name, just to change one setting. This is the same as
adding Graphic Options and Game Options to the in-game pause menu,
except for the editor, too.
To do this, I'm reusing Game::returntopausemenu() (because all of its
callers are the same callers for returning to editor settings) and
renamed it to returntoingame(), then added a variable named
ingame_editormode to Game. When we're in the options menus but still in
the editor, BOTH ingame_titlemode and ingame_editormode will be true.
2021-03-19 03:52:30 +01:00
|
|
|
game.returntoingame();
|
2021-02-22 09:28:43 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.returnmenu();
|
2021-03-19 05:12:55 +01:00
|
|
|
map.nexttowercolour();
|
2021-02-22 09:28:43 +01:00
|
|
|
}
|
2020-06-23 02:29:30 +02:00
|
|
|
}
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2020-04-02 23:06:56 +02:00
|
|
|
|
2020-04-15 19:14:42 +02:00
|
|
|
if(game.menustart)
|
|
|
|
{
|
2021-04-12 02:43:17 +02:00
|
|
|
if (game.slidermode == SLIDER_NONE)
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2021-04-12 02:43:17 +02:00
|
|
|
if (game.press_left)
|
|
|
|
{
|
|
|
|
game.currentmenuoption--;
|
|
|
|
}
|
|
|
|
else if (game.press_right)
|
|
|
|
{
|
|
|
|
game.currentmenuoption++;
|
|
|
|
}
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
2021-04-12 02:43:17 +02:00
|
|
|
else
|
2020-04-15 19:14:42 +02:00
|
|
|
{
|
2021-04-12 02:43:17 +02:00
|
|
|
slidermodeinput();
|
2020-04-15 19:14:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.currentmenuoption < 0) game.currentmenuoption = game.menuoptions.size()-1;
|
|
|
|
if (game.currentmenuoption >= (int) game.menuoptions.size() ) game.currentmenuoption = 0;
|
|
|
|
|
|
|
|
if (game.press_action)
|
|
|
|
{
|
|
|
|
if (!game.menustart)
|
|
|
|
{
|
|
|
|
game.menustart = true;
|
|
|
|
music.play(6);
|
|
|
|
music.playef(18);
|
|
|
|
game.screenshake = 10;
|
|
|
|
game.flashlight = 5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
menuactionpress();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-16 06:53:36 +02:00
|
|
|
if ( game.currentmenuname == Menu::controller &&
|
2020-01-01 21:29:24 +01:00
|
|
|
game.currentmenuoption > 0 &&
|
2021-04-19 08:23:44 +02:00
|
|
|
game.currentmenuoption < 6 &&
|
2020-01-01 21:29:24 +01:00
|
|
|
key.controllerButtonDown() )
|
|
|
|
{
|
2020-04-01 23:52:45 +02:00
|
|
|
updatebuttonmappings(game.currentmenuoption);
|
2021-06-11 21:56:07 +02:00
|
|
|
music.playef(11);
|
2021-06-11 21:54:36 +02:00
|
|
|
game.savestatsandsettings_menu();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-03-26 04:11:27 +01:00
|
|
|
if (fadetomode)
|
|
|
|
{
|
2021-12-18 08:35:08 +01:00
|
|
|
handlefadetomode();
|
2021-03-26 04:11:27 +01:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void gameinput(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//TODO mouse input
|
|
|
|
//game.mx = (mouseX / 2);
|
|
|
|
//game.my = (mouseY / 2);
|
|
|
|
|
|
|
|
if(!script.running)
|
|
|
|
{
|
|
|
|
game.press_left = false;
|
|
|
|
game.press_right = false;
|
|
|
|
game.press_action = false;
|
2021-04-19 08:23:44 +02:00
|
|
|
game.press_interact = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 02:59:08 +02:00
|
|
|
if (key.isDown(KEYBOARD_LEFT) || key.isDown(KEYBOARD_a) || key.controllerWantsLeft(false))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 02:59:08 +02:00
|
|
|
game.press_left = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 02:59:08 +02:00
|
|
|
if (key.isDown(KEYBOARD_RIGHT) || key.isDown(KEYBOARD_d) || key.controllerWantsRight(false))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 02:59:08 +02:00
|
|
|
game.press_right = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 02:59:08 +02:00
|
|
|
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v)
|
|
|
|
|| key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_DOWN) || key.isDown(KEYBOARD_w) || key.isDown(KEYBOARD_s)|| key.isDown(game.controllerButton_flip))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 02:59:08 +02:00
|
|
|
game.press_action = true;
|
2021-04-19 08:23:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (key.isDown(KEYBOARD_e) || key.isDown(game.controllerButton_interact))
|
|
|
|
{
|
|
|
|
game.press_interact = true;
|
|
|
|
}
|
2020-09-06 13:49:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
game.press_map = false;
|
|
|
|
if (key.isDown(KEYBOARD_ENTER) || key.isDown(SDLK_KP_ENTER) || key.isDown(game.controllerButton_map) )
|
|
|
|
{
|
|
|
|
game.press_map = true;
|
2020-04-03 02:59:08 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (game.advancetext)
|
|
|
|
{
|
|
|
|
if (game.pausescript)
|
|
|
|
{
|
|
|
|
game.press_action = false;
|
|
|
|
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v)
|
|
|
|
|| key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_DOWN) || key.isDown(KEYBOARD_w) || key.isDown(KEYBOARD_s) || key.isDown(game.controllerButton_flip)) game.press_action = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.press_action && !game.jumpheld)
|
|
|
|
{
|
|
|
|
if (game.pausescript)
|
|
|
|
{
|
|
|
|
game.pausescript = false;
|
|
|
|
game.hascontrol = true;
|
|
|
|
game.jumpheld = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
if (GlitchrunnerMode_less_than_or_equal(Glitchrunner2_0)
|
|
|
|
|| !game.glitchrunkludge)
|
|
|
|
{
|
|
|
|
game.state++;
|
|
|
|
}
|
2020-04-02 23:06:56 +02:00
|
|
|
game.jumpheld = true;
|
|
|
|
game.glitchrunkludge=true;
|
|
|
|
//Bug fix! You should only be able to do this ONCE.
|
2020-06-25 23:34:22 +02:00
|
|
|
//...Unless you're in glitchrunner mode
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix bringing up map menu during gamemode(teleporter)
When gamemode(teleporter) gets run in a script, it brings up a read-only
version of the teleporter screen, intended only for displaying rooms on
the minimap.
However, ever since 2.3 allowed bringing up the map screen during
cutscenes (in order to prevent softlocks), bringing up the map screen
during this mode would (1) do an unnecessary animation of suddenly
switching back to the game and bringing up the menu screen again (even
though the menu screen has already been brought up), and (2) would let
you close the menu entirely and go back to GAMEMODE, thus
unintentionally closing the teleporter screen and kind of ruining the
cutscene.
To fix this, when you bring up the map screen, it will instead instantly
transition to the map screen. And when you bring it down, it will also
instantly transition back to the teleporter screen.
But that's not all. The previous behavior was actually kind of a nice
failsafe, in that if you somehow got stuck in a state where a script ran
gamemode(teleporter), but stopped running before it could take you out
of that mode by running gamemode(game), then you could return to
GAMEMODE yourself by bringing up the map screen and then bringing it
back down. So I've made sure to keep that failsafe behavior, only as
long as there isn't a script running.
2020-12-29 00:36:32 +01:00
|
|
|
if (!game.press_map
|
|
|
|
//Extra conditionals as a kludge fix so if you open the quit menu during
|
|
|
|
//the script command gamemode(teleporter) and close it with Esc, it won't
|
|
|
|
//immediately open again
|
|
|
|
//We really need a better input system soon...
|
|
|
|
&& !key.isDown(27)
|
|
|
|
&& !key.isDown(game.controllerButton_esc))
|
|
|
|
{
|
|
|
|
game.mapheld = false;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-04-19 08:23:44 +02:00
|
|
|
if (!game.press_interact)
|
|
|
|
{
|
|
|
|
game.interactheld = false;
|
|
|
|
}
|
|
|
|
|
2020-04-01 23:52:45 +02:00
|
|
|
if (game.intimetrial && graphics.fademode == 1 && game.quickrestartkludge)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//restart the time trial
|
|
|
|
game.quickrestartkludge = false;
|
2020-03-31 21:38:52 +02:00
|
|
|
script.startgamemode(game.timetriallevel + 3);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.deathseq = -1;
|
|
|
|
game.completestop = false;
|
Fix being able to start flipped in time trials
This fixes a regression where you're able to start flipped by restarting
and then holding ACTION.
This happens because when the game resets all variables, it turns
hascontrol back on (because of hardreset()). However, this is handled in
the input function, and it's handled before player input is handled, so
the player is able to get 1 frame of being able to flip after a time
trial resets.
Why didn't this happen in 2.2? Because resetplayer() in 2.2 would set
lifeseq to 10, as if the player had died. However, this is inconsistent,
because loading in to the game for the first time would not result in a
lifeseq of 10. So, in 2.2, restarting the time trial would remove that 1
frame of being able to flip because of lifeseq, while 2.3 doesn't set
lifeseq because the player hasn't died.
I could have fixed this by setting lifeseq in the time trial restart
code, but I decided to just set hascontrol to false instead.
Fixes #770.
2021-06-12 23:02:08 +02:00
|
|
|
game.hascontrol = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//Returning to editor mode must always be possible
|
2021-02-21 00:40:11 +01:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS) && !defined(NO_EDITOR)
|
2021-04-19 08:23:44 +02:00
|
|
|
if (map.custommode && !map.custommodeforreal)
|
|
|
|
{
|
|
|
|
if ((game.press_map || key.isDown(27)) && !game.mapheld)
|
|
|
|
{
|
2021-06-18 08:25:27 +02:00
|
|
|
if (!game.separate_interact
|
|
|
|
&& game.press_map
|
|
|
|
&& (INBOUNDS_VEC(game.activeactivity, obj.blocks)
|
|
|
|
|| (game.activetele && game.readytotele > 20)))
|
|
|
|
{
|
|
|
|
/* Pass, let code block below handle it */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.returntoeditor();
|
|
|
|
game.mapheld = true;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-02-10 01:53:01 +01:00
|
|
|
#endif
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//Entity type 0 is player controled
|
2020-09-06 13:28:09 +02:00
|
|
|
bool has_control = false;
|
|
|
|
bool enter_pressed = game.press_map && !game.mapheld;
|
|
|
|
bool enter_already_processed = false;
|
2020-09-23 11:31:06 +02:00
|
|
|
bool any_onground = false;
|
|
|
|
bool any_onroof = false;
|
2021-04-19 08:23:44 +02:00
|
|
|
bool interact_pressed;
|
|
|
|
if (game.separate_interact)
|
|
|
|
{
|
|
|
|
interact_pressed = game.press_interact && !game.interactheld;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
interact_pressed = enter_pressed;
|
|
|
|
}
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t ie = 0; ie < obj.entities.size(); ++ie)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (obj.entities[ie].rule == 0)
|
|
|
|
{
|
|
|
|
if (game.hascontrol && game.deathseq == -1 && game.lifeseq <= 5)
|
|
|
|
{
|
2020-09-06 13:28:09 +02:00
|
|
|
has_control = true;
|
2021-04-19 08:23:44 +02:00
|
|
|
if (interact_pressed)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-04-19 08:23:44 +02:00
|
|
|
game.interactheld = true;
|
|
|
|
if (!game.separate_interact)
|
|
|
|
{
|
|
|
|
game.mapheld = true;
|
|
|
|
}
|
2021-03-05 19:18:46 +01:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-04-19 08:23:44 +02:00
|
|
|
if (interact_pressed && !script.running)
|
2021-03-05 19:18:46 +01:00
|
|
|
{
|
2020-01-01 21:29:24 +01:00
|
|
|
if (game.activetele && game.readytotele > 20 && !game.intimetrial)
|
|
|
|
{
|
2020-09-06 13:28:09 +02:00
|
|
|
enter_already_processed = true;
|
2021-01-02 03:38:55 +01:00
|
|
|
if(int(SDL_fabsf(obj.entities[ie].vx))<=1 && int(obj.entities[ie].vy)==0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//wait! space station 2 debug thingy
|
|
|
|
if (game.teleportscript != "")
|
|
|
|
{
|
|
|
|
|
|
|
|
//trace(game.recordstring);
|
|
|
|
//We're teleporting! Yey!
|
|
|
|
game.activetele = false;
|
|
|
|
game.hascontrol = false;
|
2020-04-03 02:59:08 +02:00
|
|
|
music.fadeout();
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
int player = obj.getplayer();
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
2020-06-13 05:36:08 +02:00
|
|
|
{
|
|
|
|
obj.entities[player].colour = 102;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
int teleporter = obj.getteleporter();
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
if (INBOUNDS_VEC(teleporter, obj.entities))
|
2020-06-13 04:31:08 +02:00
|
|
|
{
|
|
|
|
obj.entities[teleporter].tile = 6;
|
|
|
|
obj.entities[teleporter].colour = 102;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
//which teleporter script do we use? it depends on the companion!
|
|
|
|
game.state = 4000;
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.companion == 0)
|
|
|
|
{
|
|
|
|
//Alright, normal teleporting
|
2021-09-02 21:21:46 +02:00
|
|
|
game.mapmenuchange(TELEPORTERMODE, true);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
game.useteleporter = true;
|
2020-03-31 02:16:02 +02:00
|
|
|
game.initteleportermode();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//We're teleporting! Yey!
|
|
|
|
game.activetele = false;
|
|
|
|
game.hascontrol = false;
|
2020-04-03 02:59:08 +02:00
|
|
|
music.fadeout();
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
int player = obj.getplayer();
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
2020-06-13 05:36:08 +02:00
|
|
|
{
|
|
|
|
obj.entities[player].colour = 102;
|
|
|
|
}
|
2020-04-02 00:32:21 +02:00
|
|
|
int companion = obj.getcompanion();
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
if(INBOUNDS_VEC(companion, obj.entities)) obj.entities[companion].colour = 102;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
int teleporter = obj.getteleporter();
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
if (INBOUNDS_VEC(teleporter, obj.entities))
|
2020-06-13 04:31:08 +02:00
|
|
|
{
|
|
|
|
obj.entities[teleporter].tile = 6;
|
|
|
|
obj.entities[teleporter].colour = 102;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
//which teleporter script do we use? it depends on the companion!
|
|
|
|
game.state = 3000;
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
else if (INBOUNDS_VEC(game.activeactivity, obj.blocks))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-06 13:28:09 +02:00
|
|
|
enter_already_processed = true;
|
2021-01-02 03:38:55 +01:00
|
|
|
if((int(SDL_fabsf(obj.entities[ie].vx))<=1) && (int(obj.entities[ie].vy) == 0) )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
script.load(obj.blocks[game.activeactivity].script);
|
Fix entity and block indices after destroying them
This patch restores some 2.2 behavior, fixing a regression caused by the
refactor of properly using std::vectors.
In 2.2, the game allocated 200 items in obj.entities, but used a system
where each entity had an `active` attribute to signify if the entity
actually existed or not. When dealing with entities, you would have to
check this `active` flag, or else you'd be dealing with an entity that
didn't actually exist. (By the way, what I'm saying applies to blocks
and obj.blocks as well, except for some small differing details like the
game allocating 500 block slots versus obj.entities's 200.)
As a consequence, the game had to use a separate tracking variable,
obj.nentity, because obj.entities.size() would just report 200, instead
of the actual amount of entities. Needless to say, having to check for
`active` and use `obj.nentity` is a bit error-prone, and it's messier
than simply using the std::vector the way it was intended. Also, this
resulted in a hard limit of 200 entities, which custom level makers ran
into surprisingly quite often.
2.3 comes along, and removes the whole system. Now, std::vectors are
properly being used, and obj.entities.size() reports the actual number
of entities in the vector; you no longer have to check for `active` when
dealing with entities of any sort.
But there was one previous behavior of 2.2 that this system kind of
forgets about - namely, the ability to have holes in between entities.
You see, when an entity got disabled in 2.2 (which just meant turning
its `active` off), the indices of all other entities stayed the same;
the indice of the entity that got disabled stays there as a hole in the
array. But when an entity gets removed in 2.3 (previous to this patch),
the indices of every entity afterwards in the array get shifted down by
one. std::vector isn't really meant to be able to contain holes.
Do the indices of entities and blocks matter? Yes; they determine the
order in which entities and blocks get evaluated (the highest indice
gets evaluated first), and I had to fix some block evaluation order
stuff in previous PRs.
And in the case of entities, they matter hugely when using the
recently-discovered Arbitrary Entity Manipulation glitch (where crewmate
script commands are used on arbitrary entities by setting the `i`
attribute of `scriptclass` and passing invalid crewmate identifiers to
the commands). If you use Arbitrary Entity Manipulation after destroying
some entities, there is a chance that your script won't work between 2.2
and 2.3.
The indices also still determine the rendering order of entities
(highest indice gets drawn first, which means lowest indice gets drawn
in front of other entities). As an example: let's say we have the player
at 0, a gravity line at 1, and a checkpoint at 2; then we destroy the
gravity line and create a crewmate (let's do Violet).
If we're able to have holes, then after removing the gravity line, none
of the other indices shift. Then Violet will be created at indice 1, and
will be drawn in front of the checkpoint.
But if we can't have holes, then removing the gravity line results in
the indice of the checkpoint shifting down to indice 1. Then Violet is
created at indice 2, and gets drawn behind the checkpoint! This is a
clear illustration of changing the behavior that existed in 2.2.
However, I also don't want to go back to the `active` system of having
to check an attribute before operating on an entity. So... what do we
do to restore the holes?
Well, we don't need to have an `active` attribute, or modify any
existing code that operates on entities. Instead, we can just set the
attributes of the entities so that they naturally get ignored by
everything that comes into contact with it. For entities, we set their
invis to true, and their size, type, and rule to -1 (the game never uses
a size, type, or rule of -1 anywhere); for blocks, we set their type to
-1, and their width and height to 0.
obj.entities.size() will no longer necessarily equal the amount of
entities in the room; rather, it will be the amount of entity SLOTS that
have been allocated. But nothing that uses obj.entities.size() needs to
actually know the amount of entities; it's mostly used for iterating
over every entity in the vector.
Excess entity slots get cleaned up upon every call of
mapclass::gotoroom(), which will now deallocate entity slots starting
from the end until it hits a player, at which point it will switch to
disabling entity slots instead of removing them entirely.
The entclass::clear() and blockclass::clear() functions have been
restored because we need to call their initialization functions when
reusing a block/entity slot; it's possible to create an entity with an
invalid type number (it creates a glitchy Viridian), and without calling
the initialization function again, it would simply not create anything.
After this patch is applied, entity and block indices will be restored
to how they behaved in 2.2.
2020-12-27 07:11:34 +01:00
|
|
|
obj.disableblock(game.activeactivity);
|
2020-04-04 01:28:50 +02:00
|
|
|
game.activeactivity = -1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-22 21:44:20 +02:00
|
|
|
if(game.press_left)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-22 21:44:20 +02:00
|
|
|
obj.entities[ie].ax = -3;
|
|
|
|
obj.entities[ie].dir = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-09-22 21:44:20 +02:00
|
|
|
else if (game.press_right)
|
|
|
|
{
|
|
|
|
obj.entities[ie].ax = 3;
|
|
|
|
obj.entities[ie].dir = 1;
|
|
|
|
}
|
|
|
|
}
|
2020-09-23 11:31:06 +02:00
|
|
|
|
2021-08-31 19:51:40 +02:00
|
|
|
if (obj.entities[ie].onground > 0)
|
|
|
|
{
|
|
|
|
any_onground = true;
|
|
|
|
}
|
|
|
|
else if (obj.entities[ie].onroof > 0)
|
|
|
|
{
|
|
|
|
any_onroof = true;
|
2020-09-23 11:31:06 +02:00
|
|
|
}
|
2020-09-22 21:44:20 +02:00
|
|
|
}
|
2020-09-23 11:29:02 +02:00
|
|
|
}
|
2020-09-22 21:44:20 +02:00
|
|
|
|
2020-09-23 11:29:02 +02:00
|
|
|
if (game.press_left)
|
|
|
|
{
|
|
|
|
game.tapleft++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (game.tapleft <= 4 && game.tapleft > 0)
|
2020-09-22 21:44:20 +02:00
|
|
|
{
|
2020-09-23 11:29:02 +02:00
|
|
|
for (size_t ie = 0; ie < obj.entities.size(); ++ie)
|
2020-09-22 21:44:20 +02:00
|
|
|
{
|
2020-09-23 11:29:02 +02:00
|
|
|
if (obj.entities[ie].rule == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-23 11:29:02 +02:00
|
|
|
if (obj.entities[ie].vx < 0.0f)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-23 11:29:02 +02:00
|
|
|
obj.entities[ie].vx = 0.0f;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-09-22 21:44:20 +02:00
|
|
|
}
|
|
|
|
}
|
2020-09-23 11:29:02 +02:00
|
|
|
game.tapleft = 0;
|
|
|
|
}
|
|
|
|
if (game.press_right)
|
|
|
|
{
|
|
|
|
game.tapright++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (game.tapright <= 4 && game.tapright > 0)
|
2020-09-22 21:44:20 +02:00
|
|
|
{
|
2020-09-23 11:29:02 +02:00
|
|
|
for (size_t ie = 0; ie < obj.entities.size(); ++ie)
|
2020-09-22 21:44:20 +02:00
|
|
|
{
|
2020-09-23 11:29:02 +02:00
|
|
|
if (obj.entities[ie].rule == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-23 11:29:02 +02:00
|
|
|
if (obj.entities[ie].vx > 0.0f)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-09-23 11:29:02 +02:00
|
|
|
obj.entities[ie].vx = 0.0f;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-09-22 21:24:23 +02:00
|
|
|
}
|
|
|
|
}
|
2020-09-23 11:29:02 +02:00
|
|
|
game.tapright = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-02 20:50:00 +02:00
|
|
|
if (has_control)
|
2020-09-23 11:29:02 +02:00
|
|
|
{
|
2021-09-02 20:50:00 +02:00
|
|
|
if (!game.press_action)
|
|
|
|
{
|
|
|
|
game.jumppressed = 0;
|
|
|
|
game.jumpheld = false;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-02 20:50:00 +02:00
|
|
|
if (game.press_action && !game.jumpheld)
|
|
|
|
{
|
|
|
|
game.jumppressed = 5;
|
|
|
|
game.jumpheld = true;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2021-09-02 20:50:00 +02:00
|
|
|
if (game.jumppressed > 0)
|
2020-09-22 21:24:23 +02:00
|
|
|
{
|
2021-09-02 20:50:00 +02:00
|
|
|
game.jumppressed--;
|
|
|
|
if (any_onground && game.gravitycontrol == 0)
|
2020-09-22 21:24:23 +02:00
|
|
|
{
|
2021-09-02 20:50:00 +02:00
|
|
|
game.gravitycontrol = 1;
|
|
|
|
for (size_t ie = 0; ie < obj.entities.size(); ++ie)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-03 00:30:30 +02:00
|
|
|
if (obj.entities[ie].rule == 0 && (obj.entities[ie].onground > 0 || obj.entities[ie].onroof > 0))
|
2021-09-02 20:50:00 +02:00
|
|
|
{
|
|
|
|
obj.entities[ie].vy = -4;
|
|
|
|
obj.entities[ie].ay = -3;
|
|
|
|
}
|
2020-09-22 21:24:23 +02:00
|
|
|
}
|
2021-09-02 20:50:00 +02:00
|
|
|
music.playef(0);
|
|
|
|
game.jumppressed = 0;
|
|
|
|
game.totalflips++;
|
2020-09-22 21:24:23 +02:00
|
|
|
}
|
2021-09-02 20:50:00 +02:00
|
|
|
if (any_onroof && game.gravitycontrol == 1)
|
2020-09-22 21:24:23 +02:00
|
|
|
{
|
2021-09-02 20:50:00 +02:00
|
|
|
game.gravitycontrol = 0;
|
|
|
|
for (size_t ie = 0; ie < obj.entities.size(); ++ie)
|
2020-09-22 21:24:23 +02:00
|
|
|
{
|
2021-09-03 00:30:30 +02:00
|
|
|
if (obj.entities[ie].rule == 0 && (obj.entities[ie].onground > 0 || obj.entities[ie].onroof > 0))
|
2021-09-02 20:50:00 +02:00
|
|
|
{
|
|
|
|
obj.entities[ie].vy = 4;
|
|
|
|
obj.entities[ie].ay = 3;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2021-09-02 20:50:00 +02:00
|
|
|
music.playef(1);
|
|
|
|
game.jumppressed = 0;
|
|
|
|
game.totalflips++;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-09-06 13:28:09 +02:00
|
|
|
}
|
|
|
|
}
|
2021-09-02 20:50:00 +02:00
|
|
|
else
|
2020-09-06 13:28:09 +02:00
|
|
|
{
|
|
|
|
//Simple detection of keypresses outside player control, will probably scrap this (expand on
|
|
|
|
//advance text function)
|
|
|
|
if (!game.press_action)
|
|
|
|
{
|
|
|
|
game.jumppressed = 0;
|
|
|
|
game.jumpheld = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.press_action && !game.jumpheld)
|
|
|
|
{
|
|
|
|
game.jumppressed = 5;
|
|
|
|
game.jumpheld = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-19 08:23:44 +02:00
|
|
|
/* The rest of the if-tree runs only if enter is pressed and it has not
|
|
|
|
* already been processed with 'separate interact' off.
|
|
|
|
*/
|
|
|
|
if (!enter_pressed || (enter_already_processed && !game.separate_interact))
|
2020-09-06 13:28:09 +02:00
|
|
|
{
|
|
|
|
// Do nothing
|
|
|
|
}
|
2021-05-04 04:12:30 +02:00
|
|
|
else if (game.swnmode == 1
|
|
|
|
&& (game.swngame == 1 || game.swngame == 6 || game.swngame == 7))
|
2020-09-06 13:28:09 +02:00
|
|
|
{
|
|
|
|
//quitting the super gravitron
|
|
|
|
game.mapheld = true;
|
|
|
|
//Quit menu, same conditions as in game menu
|
2021-09-02 21:21:46 +02:00
|
|
|
game.mapmenuchange(MAPMODE, true);
|
2020-09-06 13:28:09 +02:00
|
|
|
game.gamesaved = false;
|
2020-11-04 03:45:33 +01:00
|
|
|
game.gamesavefailed = false;
|
2020-09-06 13:28:09 +02:00
|
|
|
game.menupage = 20; // The Map Page
|
|
|
|
}
|
2020-09-06 13:28:18 +02:00
|
|
|
else if (game.intimetrial && graphics.fademode == 0)
|
2020-09-06 13:28:09 +02:00
|
|
|
{
|
|
|
|
//Quick restart of time trial
|
|
|
|
graphics.fademode = 2;
|
|
|
|
game.completestop = true;
|
Revert part of "Fix music stopping when restarting time trial"
This reverts only a part of f196fcd896defc0b24690851c701b8273ba8074b -
as the original commit author did not do their changes atomically, they
also squashed in a de-duplication within the same commit. So I'm only
reverting the part of the commit that wasn't the de-duplication, which
is simply the changes to the music.fadeout() calls.
This is being (partially) reverted for several reasons:
1. It's not the correct behavior. What this does instead is persist the
track through after you restart the time trial, instead of fading it
out, then restarting it again. This is in contrast to behavior in
2.2, and I see no reason to not keep the same behavior.
2. It's a single-case patch. The time trials are not the only time in
the game a music track could fade out and then be restarted with the
same track - custom levels could do the same thing too. Instead of
fixing only one case, we should strive to fix EVERY case.
The original commit author (trelbutate) also didn't write anything in
the commit description of f196fcd896defc0b24690851c701b8273ba8074b. What
you should write in the commit description is things like rationale,
analysis, and other good information that would be useful to anyone
looking at your commit to understand why you did what you did. Having no
commit description leaves readers in the dark as to why you did what you
did.
Thus, I don't know why trelbutate went with this solution, or if they
knew that it was only a single-case patching, or if they knew that it
wasn't 2.2 behavior.
By not writing the commit description, they miss a chance for
reflection; speaking from personal experience, I myself have gone back
and improved my commits countless times because I wrote commit
descriptions for every single one of them, and sometimes whenever I
write them, I think to myself "hang on a minute, that doesn't sound
quite right" and end up finding improvements.
If trelbutate wrote a commit description, they might have realized that
it wasn't 2.2 behavior, and gone back and fixed up their commit to be
correct. As it stands, though, they didn't have to think about it in the
first place because they never bothered to write a commit description.
2021-04-14 18:20:33 +02:00
|
|
|
music.fadeout();
|
2020-09-06 13:28:09 +02:00
|
|
|
game.quickrestartkludge = true;
|
|
|
|
}
|
2020-09-06 13:28:18 +02:00
|
|
|
else if (game.intimetrial)
|
|
|
|
{
|
|
|
|
//Do nothing if we're in a Time Trial but a fade animation is playing
|
|
|
|
}
|
|
|
|
else
|
2020-09-06 13:28:09 +02:00
|
|
|
{
|
|
|
|
//Normal map screen, do transition later
|
2021-09-02 21:21:46 +02:00
|
|
|
game.mapmenuchange(MAPMODE, true);
|
2020-09-06 13:28:09 +02:00
|
|
|
map.cursordelay = 0;
|
|
|
|
map.cursorstate = 0;
|
|
|
|
game.gamesaved = false;
|
2020-11-04 03:45:33 +01:00
|
|
|
game.gamesavefailed = false;
|
2020-11-16 00:32:44 +01:00
|
|
|
if (script.running)
|
|
|
|
{
|
|
|
|
game.menupage = 3; // Only allow saving
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.menupage = 0; // The Map Page
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-09-06 13:28:09 +02:00
|
|
|
|
Fix bringing up map menu during gamemode(teleporter)
When gamemode(teleporter) gets run in a script, it brings up a read-only
version of the teleporter screen, intended only for displaying rooms on
the minimap.
However, ever since 2.3 allowed bringing up the map screen during
cutscenes (in order to prevent softlocks), bringing up the map screen
during this mode would (1) do an unnecessary animation of suddenly
switching back to the game and bringing up the menu screen again (even
though the menu screen has already been brought up), and (2) would let
you close the menu entirely and go back to GAMEMODE, thus
unintentionally closing the teleporter screen and kind of ruining the
cutscene.
To fix this, when you bring up the map screen, it will instead instantly
transition to the map screen. And when you bring it down, it will also
instantly transition back to the teleporter screen.
But that's not all. The previous behavior was actually kind of a nice
failsafe, in that if you somehow got stuck in a state where a script ran
gamemode(teleporter), but stopped running before it could take you out
of that mode by running gamemode(game), then you could return to
GAMEMODE yourself by bringing up the map screen and then bringing it
back down. So I've made sure to keep that failsafe behavior, only as
long as there isn't a script running.
2020-12-29 00:36:32 +01:00
|
|
|
if (!game.mapheld
|
|
|
|
&& (key.isDown(27) || key.isDown(game.controllerButton_esc))
|
|
|
|
&& (!map.custommode || map.custommodeforreal))
|
2020-09-06 13:28:09 +02:00
|
|
|
{
|
|
|
|
game.mapheld = true;
|
|
|
|
//Quit menu, same conditions as in game menu
|
2021-09-02 21:21:46 +02:00
|
|
|
game.mapmenuchange(MAPMODE, true);
|
2020-09-06 13:28:09 +02:00
|
|
|
game.gamesaved = false;
|
2020-11-04 03:45:33 +01:00
|
|
|
game.gamesavefailed = false;
|
2020-09-06 13:28:09 +02:00
|
|
|
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!
|
|
|
|
{
|
|
|
|
game.deathseq = 30;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
static void mapmenuactionpress(bool version2_2);
|
2020-06-23 00:30:10 +02:00
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void mapinput(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
const bool version2_2 = GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2);
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//TODO Mouse Input!
|
|
|
|
//game.mx = (mouseX / 2);
|
|
|
|
//game.my = (mouseY / 2);
|
|
|
|
|
|
|
|
game.press_left = false;
|
|
|
|
game.press_right = false;
|
|
|
|
game.press_action = false;
|
|
|
|
game.press_map = false;
|
2021-04-19 08:23:44 +02:00
|
|
|
game.press_interact = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
if (version2_2 && graphics.fademode == 1 && graphics.menuoffset == 0)
|
2020-06-25 23:41:44 +02:00
|
|
|
{
|
|
|
|
// Deliberate re-addition of the glitchy gamestate-based fadeout!
|
|
|
|
|
|
|
|
// First of all, detecting a black screen means if the glitchy fadeout
|
|
|
|
// gets interrupted but you're still on a black screen, opening a menu
|
|
|
|
// immediately quits you to the title. This has the side effect that if
|
|
|
|
// you accidentally press Esc during a cutscene when it's black, you'll
|
|
|
|
// immediately be quit and lose all your progress, but that's fair in
|
|
|
|
// glitchrunner mode.
|
|
|
|
// Also have to check graphics.menuoffset so this doesn't run every frame
|
|
|
|
|
2020-08-03 06:43:55 +02:00
|
|
|
// Have to close the menu in order to run gamestates
|
2020-06-25 23:41:44 +02:00
|
|
|
graphics.resumegamemode = true;
|
2020-08-03 06:43:55 +02:00
|
|
|
// Remove half-second delay
|
|
|
|
graphics.menuoffset = 250;
|
2020-06-25 23:41:44 +02:00
|
|
|
|
|
|
|
// Technically this was in <=2.2 as well
|
|
|
|
obj.removeallblocks();
|
|
|
|
|
|
|
|
if (game.menupage >= 20 && game.menupage <= 21)
|
|
|
|
{
|
|
|
|
game.state = 96;
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Produces more glitchiness! Necessary for credits warp to work.
|
Fix aggressive glitchrunner hardreset causing issues quitting to menu
This fixes the bug where in glitchrunner mode, quitting to the menu
would always put you back at the play menu on the first option, instead
of the menu you entered the game from.
The problem is the script.hardreset() that gets called before the game
actually quits to the menu, so when Game::quittomenu() gets called to
quit to the menu, all the variables that keep track of whether you're in
a certain gamemode, such as game.insecretlab and map.custommode, all get
prematurely reset before that function can read them and put you back to
the correct menu.
The solution here is to simply reset only what's needed when quitting to
the menu. Specifically, in order for credits warp to work,
script.running needs to be set to false and all the text boxes need to
be removed. Text boxes need to be gone so the "- Press ACTION to advance
text -" prompt will stay up without a text box, enabling the player to
increment the gamestate at will by pressing ACTION, and the script needs
to stop running so further text boxes don't spawn in.
Fixes #389.
2020-08-14 04:26:52 +02:00
|
|
|
script.running = false;
|
2021-09-13 06:02:15 +02:00
|
|
|
graphics.textboxes.clear();
|
2020-06-25 23:41:44 +02:00
|
|
|
|
|
|
|
game.state = 80;
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
if (game.fadetomenu && !version2_2)
|
2020-05-08 00:23:55 +02:00
|
|
|
{
|
|
|
|
if (game.fadetomenudelay > 0)
|
|
|
|
{
|
|
|
|
game.fadetomenudelay--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.quittomenu();
|
Clean up all exit paths to the menu to use common code
There are multiple different exit paths to the main menu. In 2.2, they
all had a bunch of copy-pasted code. In 2.3 currently, most of them use
game.quittomenu(), but there are some stragglers that still use
hand-copied code.
This is a bit of a problem, because all exit paths should consistently
have FILESYSTEM_unmountassets(), as part of the 2.3 feature of per-level
custom assets. Furthermore, most (but not all) of the paths call
script.hardreset() too, and some of the stragglers don't. So there could
be something persisting through to the title screen (like a really long
flash/shake timer) that could only persist if exiting to the title
screen through those paths.
But, actually, it seems like there's a good reason for some of those to
not call script.hardreset() - namely, dying or completing No Death Mode
and completing a Time Trial presents some information onscreen that
would get reset by script.hardreset(), so I'll fix that in a later
commit.
So what I've done for this commit is found every exit path that didn't
already use game.quittomenu(), and made them use game.quittomenu(). As
well, some of them had special handling that existed on top of them
already having a corresponding entry in game.quittomenu() (but the path
would take the special handling because it never did game.quittomenu()),
so I removed that special handling as well (e.g. exiting from a custom
level used returntomenu(Menu::levellist) when quittomenu() already had
that same returntomenu()).
The menu that exiting from the level editor returns to is now handled in
game.quittomenu() as well, where the map.custommode branch now also
checks for map.custommodeforreal. Unfortunately, it seems like entering
the level editor doesn't properly initialize map.custommode, so entering
the level editor now initializes map.custommode, too.
I've also taken the music.play(6) out of game.quittomenu(), because not
all exit paths immediately play Presenting VVVVVV, so all exit paths
that DO immediately play Presenting VVVVVV now have music.play(6)
special-cased for them, which is fine enough for me.
Here is the list of all exit paths to the menu:
- Exiting through the pause menu (without glitchrunner mode)
- Exiting through the pause menu (with glitchrunner mode)
- Completing a custom level
- Completing a Time Trial
- Dying in No Death Mode
- Completing No Death Mode
- Completing an Intermission replay
- Exiting from the level editor
- Completing the main game
2021-01-07 23:20:37 +01:00
|
|
|
music.play(6); //should be after game.quittomenu()
|
2020-05-08 00:23:55 +02:00
|
|
|
game.fadetomenu = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
if (game.fadetolab && !version2_2)
|
2020-05-08 00:30:26 +02:00
|
|
|
{
|
|
|
|
if (game.fadetolabdelay > 0)
|
|
|
|
{
|
|
|
|
game.fadetolabdelay--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.returntolab();
|
|
|
|
game.fadetolab = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 23:41:44 +02:00
|
|
|
if(graphics.menuoffset==0
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
&& ((!version2_2 && !game.fadetomenu && game.fadetomenudelay <= 0 && !game.fadetolab && game.fadetolabdelay <= 0)
|
2020-07-17 00:11:54 +02:00
|
|
|
|| graphics.fademode == 0))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Fix up/down being reversed in in-game menu in Flip Mode
This bug is technically NOT a regression - the code responsible for it
has been around since the source release.
However, it hasn't been a problem until Graphic Options and Game Options
were added to the pause screen. Since then, if you opened the pause menu
in Flip Mode, pressing up would move to the menu option below, and
pressing down would move to the menu option above. Notably, left and
right still remain the same.
This is because the map screen input code assumes that the menu options
will be flipped around - however, this has never been the case. What
happens instead is that the menu options get flipped around time when in
Flip Mode - flipping what's already flipped - so it ends up the same
again.
(Incidentally enough, the up/down reversing code is present on the title
screen, and is correct - if you happen to set graphics.flipmode to true
on the title screen, the title screen doesn't negate the flipped menu
options, so pressing up SHOULD be treated like pressing down, and vice
versa. However, in 2.3, it's not really possible to set
graphics.flipmode to true on the title screen without using GDB or
modifying the game. In 2.2 and previous, you can just complete the game
in Flip Mode, and the variable won't be reset; 2.3 cleaned up all exit
paths to the menu to make sure everything got reset.)
This isn't a problem when there's only two options, but since 2.3 adds
two more options to the pause screen, it's pretty noticeable.
Anyway, this is fixed by simply removing the branch of the
graphics.flipmode if-else in mapinput(). The 'else' branch is now the
code that gets executed unconditionally. Don't get confused by the diff;
I decided to unindent in the same commit because it's not that many
lines of code.
2021-03-06 04:34:15 +01:00
|
|
|
if (key.isDown(KEYBOARD_LEFT) || key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_a) || key.isDown(KEYBOARD_w)|| key.controllerWantsLeft(true))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Fix up/down being reversed in in-game menu in Flip Mode
This bug is technically NOT a regression - the code responsible for it
has been around since the source release.
However, it hasn't been a problem until Graphic Options and Game Options
were added to the pause screen. Since then, if you opened the pause menu
in Flip Mode, pressing up would move to the menu option below, and
pressing down would move to the menu option above. Notably, left and
right still remain the same.
This is because the map screen input code assumes that the menu options
will be flipped around - however, this has never been the case. What
happens instead is that the menu options get flipped around time when in
Flip Mode - flipping what's already flipped - so it ends up the same
again.
(Incidentally enough, the up/down reversing code is present on the title
screen, and is correct - if you happen to set graphics.flipmode to true
on the title screen, the title screen doesn't negate the flipped menu
options, so pressing up SHOULD be treated like pressing down, and vice
versa. However, in 2.3, it's not really possible to set
graphics.flipmode to true on the title screen without using GDB or
modifying the game. In 2.2 and previous, you can just complete the game
in Flip Mode, and the variable won't be reset; 2.3 cleaned up all exit
paths to the menu to make sure everything got reset.)
This isn't a problem when there's only two options, but since 2.3 adds
two more options to the pause screen, it's pretty noticeable.
Anyway, this is fixed by simply removing the branch of the
graphics.flipmode if-else in mapinput(). The 'else' branch is now the
code that gets executed unconditionally. Don't get confused by the diff;
I decided to unindent in the same commit because it's not that many
lines of code.
2021-03-06 04:34:15 +01:00
|
|
|
game.press_left = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
Fix up/down being reversed in in-game menu in Flip Mode
This bug is technically NOT a regression - the code responsible for it
has been around since the source release.
However, it hasn't been a problem until Graphic Options and Game Options
were added to the pause screen. Since then, if you opened the pause menu
in Flip Mode, pressing up would move to the menu option below, and
pressing down would move to the menu option above. Notably, left and
right still remain the same.
This is because the map screen input code assumes that the menu options
will be flipped around - however, this has never been the case. What
happens instead is that the menu options get flipped around time when in
Flip Mode - flipping what's already flipped - so it ends up the same
again.
(Incidentally enough, the up/down reversing code is present on the title
screen, and is correct - if you happen to set graphics.flipmode to true
on the title screen, the title screen doesn't negate the flipped menu
options, so pressing up SHOULD be treated like pressing down, and vice
versa. However, in 2.3, it's not really possible to set
graphics.flipmode to true on the title screen without using GDB or
modifying the game. In 2.2 and previous, you can just complete the game
in Flip Mode, and the variable won't be reset; 2.3 cleaned up all exit
paths to the menu to make sure everything got reset.)
This isn't a problem when there's only two options, but since 2.3 adds
two more options to the pause screen, it's pretty noticeable.
Anyway, this is fixed by simply removing the branch of the
graphics.flipmode if-else in mapinput(). The 'else' branch is now the
code that gets executed unconditionally. Don't get confused by the diff;
I decided to unindent in the same commit because it's not that many
lines of code.
2021-03-06 04:34:15 +01:00
|
|
|
if (key.isDown(KEYBOARD_RIGHT) || key.isDown(KEYBOARD_DOWN) || key.isDown(KEYBOARD_d) || key.isDown(KEYBOARD_s)|| key.controllerWantsRight(true))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Fix up/down being reversed in in-game menu in Flip Mode
This bug is technically NOT a regression - the code responsible for it
has been around since the source release.
However, it hasn't been a problem until Graphic Options and Game Options
were added to the pause screen. Since then, if you opened the pause menu
in Flip Mode, pressing up would move to the menu option below, and
pressing down would move to the menu option above. Notably, left and
right still remain the same.
This is because the map screen input code assumes that the menu options
will be flipped around - however, this has never been the case. What
happens instead is that the menu options get flipped around time when in
Flip Mode - flipping what's already flipped - so it ends up the same
again.
(Incidentally enough, the up/down reversing code is present on the title
screen, and is correct - if you happen to set graphics.flipmode to true
on the title screen, the title screen doesn't negate the flipped menu
options, so pressing up SHOULD be treated like pressing down, and vice
versa. However, in 2.3, it's not really possible to set
graphics.flipmode to true on the title screen without using GDB or
modifying the game. In 2.2 and previous, you can just complete the game
in Flip Mode, and the variable won't be reset; 2.3 cleaned up all exit
paths to the menu to make sure everything got reset.)
This isn't a problem when there's only two options, but since 2.3 adds
two more options to the pause screen, it's pretty noticeable.
Anyway, this is fixed by simply removing the branch of the
graphics.flipmode if-else in mapinput(). The 'else' branch is now the
code that gets executed unconditionally. Don't get confused by the diff;
I decided to unindent in the same commit because it's not that many
lines of code.
2021-03-06 04:34:15 +01:00
|
|
|
game.press_right = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip))
|
|
|
|
{
|
|
|
|
game.press_action = true;
|
|
|
|
}
|
2021-05-06 20:58:38 +02:00
|
|
|
if (game.menupage < 12
|
|
|
|
|| (game.menupage >= 20 && game.menupage <= 21)
|
|
|
|
|| (game.menupage >= 30 && game.menupage <= 32))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (key.isDown(KEYBOARD_ENTER) || key.isDown(game.controllerButton_map) ) game.press_map = true;
|
2020-06-23 06:36:50 +02:00
|
|
|
if (key.isDown(27) && !game.mapheld)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
game.mapheld = true;
|
2021-05-06 20:58:38 +02:00
|
|
|
if (game.menupage < 9
|
|
|
|
|| (game.menupage >= 20 && game.menupage <= 21))
|
2020-06-23 06:20:05 +02:00
|
|
|
{
|
|
|
|
game.menupage = 30;
|
|
|
|
}
|
2020-06-23 06:36:50 +02:00
|
|
|
else if (game.menupage < 12)
|
2020-06-23 06:20:05 +02:00
|
|
|
{
|
2021-04-11 22:45:42 +02:00
|
|
|
game.menupage = 32;
|
2020-06-23 06:20:05 +02:00
|
|
|
}
|
2020-06-23 06:36:50 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
graphics.resumegamemode = true;
|
|
|
|
}
|
2021-04-18 07:25:21 +02:00
|
|
|
music.playef(11);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (key.isDown(KEYBOARD_ENTER) || key.isDown(27)|| key.isDown(game.controllerButton_map) ) game.press_map = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//In the menu system, all keypresses are single taps rather than holds. Therefore this test has to be done for all presses
|
|
|
|
if (!game.press_action && !game.press_left && !game.press_right)
|
|
|
|
{
|
|
|
|
game.jumpheld = false;
|
|
|
|
}
|
|
|
|
if (!game.press_map && !key.isDown(27))
|
|
|
|
{
|
|
|
|
game.mapheld = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.mapheld = true;
|
|
|
|
game.jumpheld = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!game.mapheld)
|
|
|
|
{
|
|
|
|
if(game.press_map && game.menupage < 10)
|
|
|
|
{
|
|
|
|
//Normal map screen, do transition later
|
2020-04-01 23:52:45 +02:00
|
|
|
graphics.resumegamemode = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!game.jumpheld)
|
|
|
|
{
|
|
|
|
if (game.press_action || game.press_left || game.press_right || game.press_map)
|
|
|
|
{
|
|
|
|
game.jumpheld = true;
|
|
|
|
}
|
|
|
|
|
2020-11-16 00:32:44 +01:00
|
|
|
if (script.running && game.menupage == 3)
|
|
|
|
{
|
|
|
|
// Force the player to stay in the SAVE tab while in a cutscene
|
|
|
|
}
|
|
|
|
else if (game.press_left)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
game.menupage--;
|
|
|
|
}
|
|
|
|
else if (game.press_right)
|
|
|
|
{
|
|
|
|
game.menupage++;
|
|
|
|
}
|
|
|
|
|
2020-06-23 00:32:21 +02:00
|
|
|
if (game.press_action)
|
|
|
|
{
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
mapmenuactionpress(version2_2);
|
2020-06-23 00:32:21 +02:00
|
|
|
}
|
2020-06-23 00:30:10 +02:00
|
|
|
|
|
|
|
if (game.menupage < 0) game.menupage = 3;
|
|
|
|
if (game.menupage > 3 && game.menupage < 9) game.menupage = 0;
|
|
|
|
|
|
|
|
if (game.menupage == 9) game.menupage = 11;
|
|
|
|
if (game.menupage == 12) game.menupage = 10;
|
|
|
|
|
|
|
|
if (game.menupage == 19) game.menupage = 21;
|
|
|
|
if (game.menupage == 22) game.menupage = 20;
|
|
|
|
|
2021-04-09 12:09:12 +02:00
|
|
|
if (game.menupage == 29) game.menupage = 32;
|
|
|
|
if (game.menupage == 33) game.menupage = 30;
|
2020-06-23 00:30:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
static void mapmenuactionpress(const bool version2_2)
|
2020-06-23 00:30:10 +02:00
|
|
|
{
|
2020-06-23 00:35:26 +02:00
|
|
|
switch (game.menupage)
|
|
|
|
{
|
|
|
|
case 1:
|
2020-06-23 00:37:19 +02:00
|
|
|
if (obj.flags[67] && !game.inspecial() && !map.custommode)
|
2020-06-23 00:31:14 +02:00
|
|
|
{
|
|
|
|
//Warp back to the ship
|
|
|
|
graphics.resumegamemode = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-06-23 00:31:14 +02:00
|
|
|
game.teleport_to_x = 2;
|
|
|
|
game.teleport_to_y = 11;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-06-23 00:31:14 +02:00
|
|
|
//trace(game.recordstring);
|
|
|
|
//We're teleporting! Yey!
|
|
|
|
game.activetele = false;
|
|
|
|
game.hascontrol = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-06-23 00:31:14 +02:00
|
|
|
int i = obj.getplayer();
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
2020-06-23 00:31:14 +02:00
|
|
|
{
|
|
|
|
obj.entities[i].colour = 102;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-06-23 00:31:14 +02:00
|
|
|
//which teleporter script do we use? it depends on the companion!
|
|
|
|
game.state = 4000;
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
2020-06-23 00:35:26 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2020-11-04 03:45:33 +01:00
|
|
|
if (!game.gamesaved && !game.gamesavefailed && !game.inspecial())
|
2020-06-23 00:31:14 +02:00
|
|
|
{
|
|
|
|
game.flashlight = 5;
|
|
|
|
game.screenshake = 10;
|
|
|
|
music.playef(18);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-06-23 00:31:14 +02:00
|
|
|
game.savetime = game.timestring();
|
|
|
|
game.savearea = map.currentarea(map.area(game.roomx, game.roomy));
|
|
|
|
game.savetrinkets = game.trinkets();
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-06-23 00:31:14 +02:00
|
|
|
if (game.roomx >= 102 && game.roomx <= 104 && game.roomy >= 110 && game.roomy <= 111) game.savearea = "The Ship";
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-11-04 03:45:33 +01:00
|
|
|
bool success;
|
2020-04-02 23:06:56 +02:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2020-06-23 00:31:14 +02:00
|
|
|
if(map.custommodeforreal)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-02-21 00:40:11 +01:00
|
|
|
success = game.customsavequick(cl.ListOfMetaData[game.playcustomlevel].filename);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-06-23 00:31:14 +02:00
|
|
|
else
|
|
|
|
#endif
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-11-04 03:45:33 +01:00
|
|
|
success = game.savequick();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-11-04 03:45:33 +01:00
|
|
|
game.gamesaved = success;
|
|
|
|
game.gamesavefailed = !success;
|
2020-06-23 00:31:14 +02:00
|
|
|
}
|
2020-06-23 00:35:26 +02:00
|
|
|
break;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-06-23 00:35:26 +02:00
|
|
|
case 10:
|
2020-06-23 05:58:09 +02:00
|
|
|
//return to pause menu
|
|
|
|
music.playef(11);
|
2021-04-11 22:45:42 +02:00
|
|
|
game.menupage = 32;
|
2020-06-23 00:35:26 +02:00
|
|
|
break;
|
|
|
|
case 11:
|
2020-06-23 00:31:14 +02:00
|
|
|
//quit to menu
|
|
|
|
|
|
|
|
//Kill contents of offset render buffer, since we do that for some reason.
|
|
|
|
//This fixes an apparent frame flicker.
|
2021-02-26 00:37:03 +01:00
|
|
|
ClearSurface(graphics.tempBuffer);
|
2020-06-23 00:31:14 +02:00
|
|
|
graphics.fademode = 2;
|
2021-01-04 07:17:31 +01:00
|
|
|
music.fadeout();
|
2020-06-23 00:31:14 +02:00
|
|
|
map.nexttowercolour();
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
if (!version2_2)
|
2020-06-25 23:41:44 +02:00
|
|
|
{
|
|
|
|
game.fadetomenu = true;
|
2021-08-06 00:05:14 +02:00
|
|
|
game.fadetomenudelay = 19;
|
2020-06-25 23:41:44 +02:00
|
|
|
}
|
2021-08-05 20:53:02 +02:00
|
|
|
music.playef(11);
|
2020-06-23 00:35:26 +02:00
|
|
|
break;
|
2020-06-23 00:31:14 +02:00
|
|
|
|
2020-06-23 00:35:26 +02:00
|
|
|
case 20:
|
2020-06-23 00:31:14 +02:00
|
|
|
//return to game
|
|
|
|
graphics.resumegamemode = true;
|
2021-06-14 02:33:49 +02:00
|
|
|
music.playef(11);
|
2020-06-23 00:35:26 +02:00
|
|
|
break;
|
|
|
|
case 21:
|
2020-06-23 00:31:14 +02:00
|
|
|
//quit to menu
|
|
|
|
game.swnmode = false;
|
|
|
|
graphics.fademode = 2;
|
|
|
|
music.fadeout();
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
if (!version2_2)
|
2020-07-17 00:11:54 +02:00
|
|
|
{
|
|
|
|
game.fadetolab = true;
|
2021-08-06 00:05:14 +02:00
|
|
|
game.fadetolabdelay = 19;
|
2020-07-17 00:11:54 +02:00
|
|
|
}
|
2021-06-14 02:34:14 +02:00
|
|
|
music.playef(11);
|
2020-06-23 00:35:26 +02:00
|
|
|
break;
|
2020-06-23 00:47:25 +02:00
|
|
|
case 30:
|
|
|
|
// Return to game
|
|
|
|
graphics.resumegamemode = true;
|
2021-04-18 07:25:21 +02:00
|
|
|
music.playef(11);
|
2020-06-23 00:47:25 +02:00
|
|
|
break;
|
|
|
|
case 31:
|
2021-04-09 17:53:55 +02:00
|
|
|
// Graphic options and game options
|
|
|
|
music.playef(11);
|
|
|
|
game.gamestate = TITLEMODE;
|
|
|
|
graphics.flipmode = false;
|
|
|
|
game.ingame_titlemode = true;
|
|
|
|
graphics.ingame_fademode = graphics.fademode;
|
|
|
|
graphics.fademode = 0;
|
|
|
|
|
|
|
|
// Set this before we create the menu
|
|
|
|
game.kludge_ingametemp = game.currentmenuname;
|
|
|
|
game.createmenu(Menu::options);
|
|
|
|
map.nexttowercolour();
|
|
|
|
break;
|
2020-06-23 00:47:25 +02:00
|
|
|
case 32:
|
2021-04-09 17:53:55 +02:00
|
|
|
// Go to quit prompt
|
|
|
|
music.playef(11);
|
|
|
|
game.menupage = 10;
|
|
|
|
break;
|
2020-06-23 00:31:14 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void teleporterinput(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Todo Mouseinput!
|
|
|
|
//game.mx = (mouseX / 2);
|
|
|
|
//game.my = (mouseY / 2);
|
|
|
|
|
|
|
|
int tempx, tempy;
|
|
|
|
|
|
|
|
game.press_left = false;
|
|
|
|
game.press_right = false;
|
|
|
|
game.press_action = false;
|
|
|
|
game.press_map = false;
|
2021-04-19 08:23:44 +02:00
|
|
|
game.press_interact = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-01 23:52:45 +02:00
|
|
|
if(graphics.menuoffset==0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (key.isDown(KEYBOARD_LEFT)|| key.isDown(KEYBOARD_a) || key.controllerWantsLeft(false) ) game.press_left = true;
|
|
|
|
if (key.isDown(KEYBOARD_RIGHT) || key.isDown(KEYBOARD_d)|| key.controllerWantsRight(false) ) game.press_right = true;
|
|
|
|
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v)
|
|
|
|
|| key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_DOWN)|| key.isDown(KEYBOARD_w)|| key.isDown(KEYBOARD_s) || key.isDown(game.controllerButton_flip)) game.press_action = true;
|
2021-04-19 08:23:44 +02:00
|
|
|
if (!game.separate_interact && (key.isDown(KEYBOARD_ENTER) || key.isDown(game.controllerButton_map)))
|
|
|
|
{
|
|
|
|
game.press_map = true;
|
|
|
|
}
|
|
|
|
if (key.isDown(KEYBOARD_e) || key.isDown(game.controllerButton_interact))
|
|
|
|
{
|
|
|
|
game.press_interact = true;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//In the menu system, all keypresses are single taps rather than holds. Therefore this test has to be done for all presses
|
2021-04-19 08:23:44 +02:00
|
|
|
if (!game.press_action && !game.press_left && !game.press_right && !game.press_interact) game.jumpheld = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
if (!game.press_map) game.mapheld = false;
|
2020-06-21 02:34:45 +02:00
|
|
|
|
|
|
|
if (key.isDown(27))
|
|
|
|
{
|
2020-07-11 09:15:06 +02:00
|
|
|
if (!map.custommode || map.custommodeforreal)
|
|
|
|
{
|
2020-07-11 09:21:23 +02:00
|
|
|
// Go to pause menu
|
2020-07-11 09:15:06 +02:00
|
|
|
game.mapheld = true;
|
2020-07-11 09:21:23 +02:00
|
|
|
game.menupage = 30;
|
2020-07-11 09:15:06 +02:00
|
|
|
game.gamestate = MAPMODE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Close teleporter menu
|
|
|
|
graphics.resumegamemode = true;
|
|
|
|
}
|
2021-06-14 02:27:53 +02:00
|
|
|
music.playef(11);
|
2020-06-21 02:34:45 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.mapheld = true;
|
|
|
|
game.jumpheld = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!game.jumpheld)
|
|
|
|
{
|
2021-04-19 08:23:44 +02:00
|
|
|
if (game.press_action || game.press_left || game.press_right || game.press_map || game.press_interact)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
game.jumpheld = true;
|
|
|
|
}
|
|
|
|
|
2020-07-05 03:58:13 +02:00
|
|
|
bool any_tele_unlocked = false;
|
|
|
|
if (game.press_left || game.press_right)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < map.teleporters.size(); i++)
|
|
|
|
{
|
|
|
|
point& tele = map.teleporters[i];
|
|
|
|
|
2021-03-24 20:12:39 +01:00
|
|
|
if (map.isexplored(tele.x, tele.y))
|
2020-07-05 03:58:13 +02:00
|
|
|
{
|
|
|
|
any_tele_unlocked = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.press_left && any_tele_unlocked)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-07-05 03:50:58 +02:00
|
|
|
do
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
game.teleport_to_teleporter--;
|
2020-04-15 04:32:30 +02:00
|
|
|
if (game.teleport_to_teleporter < 0) game.teleport_to_teleporter = map.teleporters.size() - 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
tempx = map.teleporters[game.teleport_to_teleporter].x;
|
|
|
|
tempy = map.teleporters[game.teleport_to_teleporter].y;
|
|
|
|
}
|
2021-03-24 20:12:39 +01:00
|
|
|
while (!map.isexplored(tempx, tempy));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-07-05 03:58:13 +02:00
|
|
|
else if (game.press_right && any_tele_unlocked)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-07-05 03:50:58 +02:00
|
|
|
do
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
game.teleport_to_teleporter++;
|
2020-04-15 04:32:30 +02:00
|
|
|
if (game.teleport_to_teleporter >= (int) map.teleporters.size()) game.teleport_to_teleporter = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
tempx = map.teleporters[game.teleport_to_teleporter].x;
|
|
|
|
tempy = map.teleporters[game.teleport_to_teleporter].y;
|
|
|
|
}
|
2021-03-24 20:12:39 +01:00
|
|
|
while (!map.isexplored(tempx, tempy));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-04-19 08:23:44 +02:00
|
|
|
if ((game.separate_interact && game.press_interact) || game.press_map)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
tempx = map.teleporters[game.teleport_to_teleporter].x;
|
|
|
|
tempy = map.teleporters[game.teleport_to_teleporter].y;
|
|
|
|
if (game.roomx == tempx + 100 && game.roomy == tempy + 100)
|
|
|
|
{
|
|
|
|
//cancel!
|
2020-04-01 23:52:45 +02:00
|
|
|
graphics.resumegamemode = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//teleport
|
2020-04-01 23:52:45 +02:00
|
|
|
graphics.resumegamemode = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
game.teleport_to_x = tempx;
|
|
|
|
game.teleport_to_y = tempy;
|
|
|
|
|
|
|
|
//trace(game.recordstring);
|
|
|
|
//We're teleporting! Yey!
|
|
|
|
game.activetele = false;
|
|
|
|
game.hascontrol = false;
|
|
|
|
|
|
|
|
int i = obj.getplayer();
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
2020-06-13 05:36:08 +02:00
|
|
|
{
|
|
|
|
obj.entities[i].colour = 102;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
i = obj.getteleporter();
|
Use explicit INBOUNDS_VEC() instead of checking sentinel -1
It's better to do INBOUNDS_VEC(i, obj.entities) instead of 'i > -1'.
'i > -1' is used in cases like obj.getplayer(), which COULD return a
sentinel value of -1 and so correct code will have to check that value.
However, I am now of the opinion that INBOUNDS_VEC() should be used and
isn't unnecessary.
Consider the case of the face() script command: it's not enough to check
i > -1, you should read the routine carefully. Because if you look
closely, you'll see that it's not guaranteed that 'i' will be initialized
at all in that command. Indeed, if you call face() with invalid
arguments, it won't be. And so, 'i' could be something like 215, and
that would index out-of-bounds, and that wouldn't be good. Therefore,
it's better to have the full bounds check instead of checking only one
bounds. Many commands are like this, after some searching I can also
name position(), changemood(), changetile(), changegravity(), etc.
It also makes the code more explicit. Now you don't have to wonder what
-1 means or why it's being checked, you can just read the 'INBOUNDS' and
go "oh, that checks if it's actually inbounds or not".
2020-09-09 13:15:14 +02:00
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
2020-06-13 04:31:08 +02:00
|
|
|
{
|
|
|
|
obj.entities[i].tile = 6;
|
|
|
|
obj.entities[i].colour = 102;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
//which teleporter script do we use? it depends on the companion!
|
|
|
|
game.state = 4000;
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void gamecompleteinput(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
game.press_left = false;
|
|
|
|
game.press_right = false;
|
|
|
|
game.press_action = false;
|
|
|
|
game.press_map = false;
|
2021-04-19 08:23:44 +02:00
|
|
|
game.press_interact = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-30 20:13:02 +02:00
|
|
|
//Do this before we update map.bypos
|
|
|
|
if (!game.colourblindmode)
|
|
|
|
{
|
2020-11-03 00:23:53 +01:00
|
|
|
graphics.updatetowerbackground(graphics.titlebg);
|
2020-04-30 20:13:02 +02:00
|
|
|
}
|
|
|
|
|
2020-04-30 19:56:27 +02:00
|
|
|
//Do these here because input comes first
|
2020-11-03 00:23:53 +01:00
|
|
|
graphics.titlebg.bypos += graphics.titlebg.bscroll;
|
2020-04-30 19:56:27 +02:00
|
|
|
game.oldcreditposition = game.creditposition;
|
Don't re-draw credits scroll background every frame
While I was working on my over-30-FPS patch, I found out that the tower
background in the credits scroll was being completely re-drawn every
single frame, which was a bit wasteful and expensive. It's also harder
to interpolate for my over-30-FPS patch. I'm guessing this constant
re-draw was done because the math to get the surface scroll properly
working is a bit subtle, but I've figured the precise math out!
The first changes of this patch is just removing the unconditional
`map.tdrawback = true;`, and having to set `map.scrolldir` everywhere to
get the credits scrolling in the right direction but make sure the title
screen doesn't start scrolling like a descending tower, too.
After that, the first problem is that it looks like the ACTION press to
speed up the credits scrolling doesn't speed up the background, too. No
problem, just shove a `!game.press_action` check in
`gamecompletelogic()`.
However, this introduces a mini-problem, which is that NOW when you hold
down ACTION, the background appears to be slowly getting out of sync
with the credits text by a one-pixel-per-second difference. This is
actually due to the fact that, as a result of me adding the conditional,
`map.bscroll` is no longer always unconditionally getting set to 1,
while `game.creditposition` IS always unconditionally getting
decremented by 1. And when you hold down ACTION, `game.creditposition`
gets decremented by 6.
Thus, I need to set `map.bscroll` when holding down ACTION to be 7,
which is 6 plus 1.
Then we have another problem, which is that the incoming textures desync
when you press ACTION, and when you release ACTION. They desync by
precisely 6 pixels, which should be a familiar number. I (eventually)
tracked this down to `map.bypos` being updated at the same time
`map.bscroll` is, even though `map.bypos` should be updated a frame
later AFTER updating `map.bscroll`.
So I had to change the `map.bypos` update in `gamecompleteinput()` and
`gamecompletelogic()` to be `map.bypos += map.bscroll;` and then place
it before any `map.bscroll` update, thus ensuring that `map.bscroll`
updates exactly one frame before `map.ypos` does. I had to move the
`map.bypos += map.bscroll;` to be in `gamecompleteinput()`, because
`gamecompleteinput()` comes first before `gamecompletelogic()` in the
`main.cpp` game loop, otherwise the `map.bypos` update won't be delayed
by one frame for when you press ACTION to make it go faster, and thus
cause a desync when you press ACTION.
Oh and then after that, I had to make the descending tower background
draw a THIRD row of incoming tiles, otherwise you could see some black
flickering at the bottom of the screen when you held down ACTION.
All of this took me way too long to figure out, but now the credits
scroll works perfectly while being more optimized.
2020-04-30 05:52:33 +02:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip))
|
|
|
|
{
|
|
|
|
game.creditposition -= 6;
|
Turn (super)patrons/githubfriends into arrays & move them to new file
So, originally, I wanted to keep them on Game, but it turns out that if
I initialize it in Game.cpp, the compiler will complain that other files
won't know what's actually inside the array. To do that, I'd have to
initialize it in Game.h. But I don't want to initialize it in Game.h
because that'd mean recompiling a lot of unnecessary files whenever
someone gets added to the credits.
So, I moved all the patrons, superpatrons, and GitHub contributors to a
new file, Credits.h, which only contains the list (and the credits max
position calculation). That way, whenever someone gets added, only the
minimal amount of files need to be recompiled.
2020-07-03 12:13:15 +02:00
|
|
|
if (game.creditposition <= -Credits::creditmaxposition)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-01 23:52:45 +02:00
|
|
|
if(graphics.fademode==0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-01 23:52:45 +02:00
|
|
|
graphics.fademode = 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
Turn (super)patrons/githubfriends into arrays & move them to new file
So, originally, I wanted to keep them on Game, but it turns out that if
I initialize it in Game.cpp, the compiler will complain that other files
won't know what's actually inside the array. To do that, I'd have to
initialize it in Game.h. But I don't want to initialize it in Game.h
because that'd mean recompiling a lot of unnecessary files whenever
someone gets added to the credits.
So, I moved all the patrons, superpatrons, and GitHub contributors to a
new file, Credits.h, which only contains the list (and the credits max
position calculation). That way, whenever someone gets added, only the
minimal amount of files need to be recompiled.
2020-07-03 12:13:15 +02:00
|
|
|
game.creditposition = -Credits::creditmaxposition;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-03 00:23:53 +01:00
|
|
|
graphics.titlebg.bscroll = +7;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
game.press_action = true;
|
|
|
|
}
|
|
|
|
if (key.isDown(KEYBOARD_ENTER)|| key.isDown(game.controllerButton_map)) game.press_map = true;
|
|
|
|
|
|
|
|
if (!game.mapheld)
|
|
|
|
{
|
|
|
|
if(game.press_map)
|
|
|
|
{
|
|
|
|
//Return to game
|
2020-04-01 23:52:45 +02:00
|
|
|
if(graphics.fademode==0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-01 23:52:45 +02:00
|
|
|
graphics.fademode = 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void gamecompleteinput2(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
game.press_left = false;
|
|
|
|
game.press_right = false;
|
|
|
|
game.press_action = false;
|
|
|
|
game.press_map = false;
|
2021-04-19 08:23:44 +02:00
|
|
|
game.press_interact = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-05-02 03:23:52 +02:00
|
|
|
//Do this here because input comes first
|
|
|
|
game.oldcreditposx = game.creditposx;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip))
|
|
|
|
{
|
|
|
|
game.creditposx++;
|
2020-05-02 03:23:52 +02:00
|
|
|
game.oldcreditposx++;
|
2020-01-01 21:29:24 +01:00
|
|
|
if (game.creditposy >= 30)
|
|
|
|
{
|
2020-04-01 23:52:45 +02:00
|
|
|
if(graphics.fademode==0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-01 23:52:45 +02:00
|
|
|
graphics.fademode = 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
music.fadeout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
game.press_action = true;
|
|
|
|
}
|
|
|
|
if (key.isDown(KEYBOARD_ENTER) || key.isDown(game.controllerButton_map)) game.press_map = true;
|
|
|
|
|
|
|
|
if (!game.mapheld)
|
|
|
|
{
|
|
|
|
if(game.press_map)
|
|
|
|
{
|
|
|
|
//Return to game
|
2020-04-01 23:52:45 +02:00
|
|
|
if(graphics.fademode==0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-01 23:52:45 +02:00
|
|
|
graphics.fademode = 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
music.fadeout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|