1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-26 22:48:30 +02:00
Commit Graph

133 Commits

Author SHA1 Message Date
Misa
243f9b92f8 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 13:35:21 -04:00
Misa
4fa435f784 Separate pressing Enter to open map from pressing Enter to interact
This is a lot of copy-pasted code, but a little bit of copy-pasting
never hurt anyone...

The keybind to interact with activity zones and teleporters is now
separate from the keybind to open the map, or return to the editor from
in-editor playtesting, or restart a time trial. The keybind is now E,
and the default controller bind is X. No controller button prompts, but
the game didn't have controller button prompts anyways, so whatever.

Doing this now because if people's muscle memory are going to be broken
by not being able to spam the map keybind anymore, at least we can help
a bit by changing the keybind so they can keep spamming it - their
muscle memory is going to be broken anyways.

This option has to be enabled by going to the speedrunner menu options
and selecting "interact button". It is disabled by default.

All prompt text needs to be string-interpolated every time they are
drawn, because it is possible for people to change which interact button
they use in the middle of gameplay, via the in-game options.

Closes #736.
2021-05-19 00:04:00 -07:00
Misa
b3c2f56c79 Factor out slowdown/invincibility conds to function
This factors out the slowdown and invincibility conditionals to a
function. This means less copy-pasted code, and it also conveys intent
(that we don't want to allow competitive options if we have either of
these cheats enabled).

This function isn't implemented in the header because then we would have
to include Map.h for map.invincibility, and transitive includes are
evil. Although, map.invincibility ought to be on Game instead (it was
only mapclass due to 2.2-and-previous argument passing), but that's a
bunch of variable reshuffling that can be done later.
2021-05-03 22:32:06 -04:00
Misa
516e71c7da Remove customlevelstatsloaded from Game
This boolean is assigned, and it is checked... but it's never assigned
to true, thus making it useless. I also checked 2.2 source and the same
thing happens there; to prevent any confusion, I'm removing this.
2021-04-17 09:53:17 -04:00
Misa
e8316c7e9a Implement music and sound volume sliders
This adds music and volume sliders to the audio options. To use the
sliders, you navigate to the given option, then press ACTION, and your
selection will be transferred to the slider. Pressing left or right will
move the slider accordingly. Then you can press ACTION to confirm the
volume is what you want and deselect it, or you can press Esc to cancel
the volume change, and it will revert to the previous volume; both
actions will write your settings to disk.

Most of this commit is just adding infrastructure to support having
sliders in menus (without copy-pasting code), which is a totally
completely new user interface that has never been used before in this
game. If we're going to be adding something new, I want to make sure
that it at least is done the RIGHT way.

Closes #706.
2021-04-11 20:56:16 -04:00
Misa
2a3f17f1f7 Add audio category to options menu
The audio category contains the MMMMMM soundtrack option, as well as
stubs for the soon-to-be-implemented volume slider options.
2021-04-11 20:56:16 -04:00
Vittorio Romeo
082a0c2205 Fix '-Wpedantic' warnings under gcc 10.x 2021-04-10 20:53:01 -04:00
Misa
8e4b904f57 Fix whitespace from eee98b0e07
eee98b0e07 introduced mixed indentation
and one trailing whitespace, which I've cleaned up.
2021-04-09 17:42:58 -04:00
TerryCavanagh
eee98b0e07 Clean up of options menus for v2.3 (fixes #696) 2021-04-09 20:39:12 +10:30
Misa
f6ea05f521 Factor timestep calculation out to Game function
This is so we can grab the game's timestep anywhere else in the codebase
without copy-pasting it.
2021-04-02 16:13:54 -04:00
Misa
f8f6f3b96e Add option to re-enable 1-frame input delay
This is an option for speedrunners whose muscle memory is precisely
trained and used to the 1-frame input delay that existed in 2.2 and
below. It is located in Game Options -> Advanced Options, and is off by
default.

To re-add the 1-frame input delay, we simply move the key.Poll() to the
start of the frame, instead of before an input function gets ran -
undoing what #535 did.

There is a frame ordering-sensitive issue here, where toggling
game.inputdelay at the wrong time could cause double-polling. However,
we only toggle it in an input function, which regardless is always
guaranteed to be ran after key.Poll() (it either happened at the start
of the frame or just before the input function got ran), so this is not
an issue. But, in case we ever need to toggle this variable in the
future, we can just use the defer callbacks system to defer the toggle
to the end of the frame - also added by #535.

Added at the request of Habeechee on the VVVVVV speedrunning Discord
server.
2021-04-02 11:18:32 -04:00
Misa
100d986431 Remove mainmenu from Game
Since mainmenu is only ever used in Input.cpp, I might as well make it
clearer by moving it into a static global variable in Input.cpp. (The
same applies to fadetolab/fadetomenu, but I didn't think much about
those at the time... that'll be a refactor for later.)
2021-03-25 23:32:39 -04:00
Misa
d45e6f6254 Remove game.gametimer in favor of game.frames
PR #279 added game.gametimer solely for the editor ghosts feature. It
seems that whoever originally wrote it (Leo for the now-dead VVVVVV:
Community Edition, I believe) forgot that the game already had its own
timer, that they could use.

The game timer does increment on unfocus pause (whereas this doesn't),
but that's a separate issue, and it ought to not do that.
2021-03-21 20:53:11 -04:00
Misa
3da0e31215 Remove game.shouldreturntoeditor in favor of using defer callback
game.shouldreturntoeditor was added to fix a frame ordering issue that
was causing a bug where if you started playtesting in a room with a
horizontal/vertical warp background, and exited playtesting in a
different room that also had a horizontal/vertical warp background and
which was different, then the background of the room you exited in would
slowly scroll offscreen, when you re-entered the editor, instead of the
background consisting entirely of the actual background of the room.

Namely, the issue was that the game would render one more frame of
GAMEMODE after graphics.backgrounddrawn got set to false, and re-set it
to true, thus negating the background redraw, so the editor background
would be incorrect.

With defer callbacks, we can now just use a couple lines of code,
instead of having to add an extra kludge variable and putting handling
for it all over the code.
2021-03-21 02:55:42 -04:00
Misa
30719b87db De-duplicate "Game Saved" telesave textbox
The "Game Saved" text box, along with its associated telesave() call,
exists in both Game.cpp and Script.cpp, so one of them is the copy-paste
of the other. Unfortunately this copy-paste resulted in an inconsistency
where both of them don't check for the same things when deciding whether
or not the telesave should actually happen (this is why you don't
copy-paste, kids... it's scary!).

Either way, de-duplicating this now is less work for me later.
2021-03-21 02:53:25 -04:00
Misa
5de884f584 De-duplicate Level Complete sequence textboxes
Every Level Complete sequence is the same copy-pasted thing, but with
minor changes. To make my work easier, I'm de-duplicating them so I have
less text boxes to change later, and less grind to grind.
2021-03-21 02:53:25 -04:00
Misa
2c8d338e47 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-18 23:01:00 -04:00
Misa
22d71affba De-duplicate number of menu text bytes
I've moved this to a define that gets declared in Game.h. I could've
made it a const int, but that's only legal in C++ mode.
2021-03-06 22:14:24 -05:00
Misa
40c6a01917 Make saveFilePath not an std::string
Since it only ever gets assigned from FILESYSTEM_getUserSaveDirectory(),
and that function returns a C string, and the variable is only ever read
from again, this doesn't need to be an std::string.
2021-03-06 22:13:39 -05:00
Misa
6a3a1fe147
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 17:23:59 -05:00
Misa
626aac59fb Fix No Death Mode results being reset before being shown
This does the same thing as the last commit, but for No Death Mode
instead of Time Trials. Whenever you die in No Death Mode, or complete
it, all the relevant variables get copied to variables prefixed with
'ndmresult' that never get reset by script.hardreset(), and these
variables are what titlerender() use, instead of the "live" ones.
2021-01-18 13:06:15 -05:00
Misa
4d7baa9e9e Fix Time Trial results being reset before being shown
This makes it so when a Time Trial gets completed, all the relevant
variables get copied onto variables prefixed with 'timetrialresult',
which never get reset by script.hardreset(). Then titlerender() will use
those variables accordingly.
2021-01-18 13:06:15 -05:00
Misa
b1558f574c Remove game.savemystats
This variable seems to have been intended to make sure
game.savestatsandsettings() was called at the end of the frame, or make
sure that it didn't get called more than once per frame. I don't see any
frame ordering-related reason why it needs to be called specifically at
the end of the frame (the function doesn't modify any state), so it's
more plausible that it was added to make sure it didn't get called more
than one per frame.

However, upon further analysis, none of the code paths where
game.savemystats is used ever calls or sets game.savemystats more than
once, and a majority of the code directly calls
game.savestatsandsettings() anyway, so there's no reason for this
variable to exist. If we ever need to make sure it doesn't get called
more than once, and there's no way to change the code paths around to
prevent it otherwise, we can use the defer callbacks system that I added
to #535, when it gets merged.
2021-01-11 00:26:14 -05:00
Misa
775ac4c40c 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-28 21:12:51 -05:00
Misa
0eddd2d015 De-duplicate menu animation code when bringing up map screen
When bringing up the map screen, the game does a small menu animation
where the menu comes in from the bottom. The code to calculate the menu
offset is copy-pasted everywhere, so I thought I'd de-duplicate it to
make my life easier when working with it. I also included the
game.gamestate assignment in the de-duplicated function, so it would be
easier for a future bugfix.

At the same time, I'm also removing all the BlitSurfaceStandard()s that
copied menubuffer to backBuffer. The red flag is that this blit happened
for every single entry point to MAPMODE and TELEPORTERMODE, except for
the script command gamemode(teleporter). Pressing Enter to bring up the
map screen, pressing Enter to quit the Super Gravitron, pressing Esc to
bring up the pause screen, and pressing Enter to bring up the teleporter
screen all do this blit, so if this blit was there to fix a bug, then
there's a bug with using the script command gamemode(teleporter)... but,
as far as I can tell, there isn't.

That's because the blit basically does nothing. All the blit does is
copy menubuffer onto backBuffer. Then the next thing that happens is
that either maprender() or teleporterrender() will be called, and the
first thing that those functions will always do is fill backBuffer with
solid black, completely overriding the previous blit. So that's why
removing this blit won't have any effect, and it can be safely removed
for code clarity.
2020-12-28 19:55:23 -05:00
Misa
55163e90d5 Allow Game::savestats() to accept a pointer to ScreenSettings
Another step to fix the bug #556 is to allow Game::savestats() to accept
a pointer to an existing ScreenSettings struct. This entails refactoring
Game::savesettings() and Game::serializesettings() to accept the
function as well, along with adding Screen::GetSettings() so the
settings of the current Screen can be easily grabbed.
2020-12-21 20:15:30 -05:00
Misa
b62908f0f4 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-21 19:37:34 -05:00
Dav999-v
444074a931 Add error messages for failed writes to disk of settings
Changing settings would most of the time attempt to save unlock.vvv and
now also settings.vvv, but there would be no feedback whether the files
have been saved successfully or not. Now, if saving fails when changing
settings in the menu, a warning message will be shown. The setting will
still be applied of course, but the user will be informed it couldn't
be saved. This message can be silenced until the game is restarted,
because I can imagine this could get very annoying when someone already
knows their settings aren't writeable.

Also, some options didn't even save settings in the first place. These
are turning off invincibility, and by coincidence precisely all the
options in the advanced options menu. I made sure these options now do
so.
2020-12-18 14:16:53 -05:00
Misa
fb19787489 Remove duplicate game.controllerSensitivity proxy
It wasn't a direct duplicate of key.sensitivity, but it was still
basically the same thing. Although to be fair, at least the case-switch
conversion didn't get duplicated everywhere unlike game.slowdown.

So now key.sensitivity functions the same as game.controllerSensitivity,
and it only gets converted to its actual value whenever a joystick input
happens in key.Poll(), unlike previously where it got converted every
single frame on the title screen (there was even a comment that said
"TODO bit wasteful doing this every poll").
2020-12-18 10:02:18 -05:00
Misa
bc9dff8c2a Remove game.gameframerate as duplicate of game.slowdown
game.gameframerate seems to exist for converting the value of
game.slowdown into an actual timestep value, when really the timestep
value should just use game.slowdown directly with a fast lookup table.
Otherwise, there's a bunch of duplicated game.slowdown case-switches
everywhere, which adds up to a large, annoying pile should the values be
changed in the future. But now the duplicate variable has been removed,
and with it, all the copy-pasted case-switches.

Also, the game speed text rendering in Menu::accessibility and
Menu::setslowdown has been factored out to a function and de-duplicated
as well.
2020-12-18 10:02:18 -05:00
Misa
ee44f81d4c Remove duplicate using-MMMMMM variable from Game
game.usingmmmmmm was a duplicate of music.usingmmmmmm, and has been
removed.
2020-12-18 10:02:18 -05:00
Misa
40b7ddda05 Remove duplicate screen configuration variables
There were some duplicate Screen configuration variables that were on
Game, when there didn't need to be.

 - game.fullScreenEffect_badSignal is a duplicate of
   graphics.screenbuffer->badSignalEffect
 - game.fullscreen is a duplicate of !graphics.screenbuffer->isWindowed
 - game.stretchMode is a duplicate of graphics.screenbuffer->stretchMode
 - game.useLinearFilter is a duplicate of
   graphics.screenbuffer->isFiltered

These duplicate variables have been removed now.

I put indentation when handling the ScreenSettings struct in main() so
the local doesn't live for the entirety of main() (which is the entirety
of the program).
2020-12-18 10:02:18 -05:00
Misa
5759408ded Remove Game::shouldreturntopausemenu
This kludge variable was used to re-set the warp background after coming
back from the in-game settings menus. But since #522 got merged, this
has no longer been necessary.
2020-11-07 16:25:04 -05:00
Misa
5aa8b99113 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 12:06:57 -05:00
Dav999-v
4ebf89e844 Add error message if quicksave fails 2020-11-03 22:05:26 -05:00
Dav999-v
5dbb90c7fd Add error message if telesave fails
At least, whenever it would say "Game Saved", it now instead gives an
error message if saving is not successful.
2020-11-03 22:05:26 -05:00
Misa
cbceeccf78 Clean up and prevent unnecessary qualifiers to self
By "unnecessary qualifiers to self", I mean something like using the
'game.' qualifier for a variable on the Game class when you're inside a
function on the Game class itself. This patch is to enforce consistency
as most of the code doesn't have these unnecessary qualifiers.

To prevent further unnecessary qualifiers to self, I made it so the
extern in each header file can be omitted by using a define. That way,
if someone writes something referring to 'game.' on a Game function,
there will be a compile error.

However, if you really need to have a reference to the global name, and
you're within the same .cpp file as the implementation of that object,
you can just do the extern at the function-level. A good example of this
is editorinput()/editorrender()/editorlogic() in editor.cpp. In my
opinion, they should probably be split off into their own separate file
because editor.cpp is getting way too big, but this will do for now.
2020-09-28 01:34:40 -04:00
Misa
7fcc1c8cdc De-duplicate reading/writing main game telesave/quicksave
The game has four different functions for the same XML schema:
Game::loadtele(), Game::savetele(), Game::loadquick(), and
Game::savequick(). This essentially means one XML schema has been
copy-pasted three different times.

I can at least trim that number down to being copy-pasted only one time
by de-duplicating the reading and writing part. So both Game::loadtele()
and Game::loadquick() now use Game::readmaingamesave(), and
Game::savetele() and Game::savequick() now use
Game::writemaingamesave().

This will make it take less work to add XML forwards compatibility
(#373).
2020-09-25 13:32:41 -04:00
Nichole Mattera
1376e65b5d Added ability to bind restart to a controller. 2020-08-08 19:02:14 -04:00
AllyTally
48d7523e34 fix tab instead of spaces 2020-08-01 16:09:24 -04:00
AllyTally
06e5eb38d9 Fix #380
Achievements could be unlocked in custom levels/make and play, so this adds the wrapper function `game.unlockAchievement` which calls `NETWORK_unlockAchievement` if `map.custommode` is false.
Also, this function and `Game::unlocknum` have both been `ifdef`ed to be empty if MAKEANDPLAY is defined.
2020-08-01 16:09:24 -04:00
Misa
52f7a587fe Separate includes into sections and alphabetize them
Okay, so basically here's the include layout that this game now
consistently uses:

[The "main" header file, if any (e.g. Graphics.h for Graphics.cpp)]
[blank line]
[All system includes, such as tinyxml2/physfs/utfcpp/SDL]
[blank line]
[All project includes, such as Game.h/Entity.h/etc.]

And if applicable, another blank line, and then some special-case
include screwy stuff (take a look at editor.cpp or FileSystemUtils.cpp,
for example, they have ifdefs and defines with their includes).
2020-07-19 21:37:40 -04:00
Misa
b5ff65c84e Remove unnecessary includes from header files
Including a header file inside another header file means a bunch of
files are going to be unnecessarily recompiled whenever that inner
header file is changed. So I minimized the amount of header files
included in a header file, and only included the ones that were
necessary (system includes don't count, I'm only talking about includes
from within this project). Then the includes are only in the .cpp files
themselves.

This also minimizes problems such as a NO_CUSTOM_LEVELS build failing
because some file depended on an include that got included in editor.h,
which is another benefit of removing unnecessary includes from header
files.
2020-07-19 21:37:40 -04:00
Misa
2af396fb30 Consistently use angle brackets for SDL.h includes
That's how it should be done, because the SDL headers aren't going to be
installed in this repository. The game was a bit inconsistent before but
now it isn't anymore.
2020-07-19 21:37:40 -04:00
Misa
199a8f45d6 Fix -playmusic command line option not working
There's a bug where playtesting from Ved doesn't properly play the music
of the level, due to no fault with Ved.

This was because the music was being faded out by
scriptclass::startgamemode() case 23 after main() called music.play().
To fix this, just call music.play() when all the other variables are
being set in Game::customloadquick().
2020-07-11 15:03:37 -04:00
Misa
3932c75acc Remove unnecessary stub destructors
It's a bit misleading to have these stub destructors when they don't do
anything special.
2020-07-08 19:14:21 -04:00
Misa
6b0b86d434 Remove unused attribute advanced_mode from Game
This attribute does absolutely nothing. In fact, it does so much nothing
I can safely remove reading and writing it!
2020-07-08 19:14:21 -04:00
Ethan Lee
d3f9a36941 Refactor startup to load config before calling Screen::init 2020-07-08 14:30:57 -04:00
Misa
8366e08fbe Remove usage of std::string from MenuOption
Instead, the string in MenuOption is just a buffer of 161 chars, which
is 40 chars (160 bytes if each were the largest possible UTF-8 character
size) plus a null terminator. This is because the maximum length of a
menu option that can be fit on the screen without going past is 40
chars.
2020-07-06 11:19:24 -04:00
Misa
fc03fca838 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-06 11:19:24 -04:00