1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-30 16:38:29 +02:00
Commit Graph

1588 Commits

Author SHA1 Message Date
Vittorio Romeo
082a0c2205 Fix '-Wpedantic' warnings under gcc 10.x 2021-04-10 20:53:01 -04:00
viri
6e1054e362 CONTRIBUTORS.txt: Update contact info 2021-04-09 22:39:33 -04:00
Misa
f96f5703ff Fix level list segfault when upgrading old levelstats.vvv
So some people reported the levels list crashing when they loaded it.
But this wasn't reproducible every time. They didn't provide any
debugging information, so I had to use my backup plan: doing a full
audit of the code path taken for loading the levels list.

And then I found this. It turns out this was because I used a
LOAD_ARRAY_RENAME() macro on an std::vector. You can't do that because
you need to use push_back() to resize a vector, so the macro will end up
indexing into nothing, causing a segfault. However, this code path would
only be taken if you have an old levelstats.vvv, from 2.2 and previous -
which explains why it wasn't 100% reproducible. But now that I know you
need an old levelstats.vvv, this bug happens 100% of the time.

Anyways, to fix this, just ditch the macro and expand it manually, while
replacing the indexing with a proper usage of push_back().
2021-04-09 22:22:05 -04:00
Misa
0f0e218cf6 Use macros to calculate accessibility offset
This means the offset is calculated at compile-time, and we can use a
proper case-switch here instead of an else-if chain.
2021-04-09 17:42:58 -04:00
Misa
b5f1cbb2d1 Clean up unused vars/funcs from eee98b0e07
eee98b0e07 made some functions and
variables unused, which generate compiler warnings. So I've removed
them.
2021-04-09 17:42:58 -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
Misa
9e560e31cf Blacklist non-.vvvvvv files in level metadata
While the game does support playing levels with filenames that don't
have the .vvvvvv extension, it doesn't do it well.

Namely, those files can't be loaded or saved into the editor (because a
.vvvvvv always gets tacked on to your input when saving or loading). In
2.3, this gets worse because you can't load a level without a .vvvvvv
extension from command-line playtesting (because a .vvvvvv automatically
gets added) and you can't load per-level custom assets.

The only place where extensionless level files are supported is when
loading level metadata. But this makes it so they no longer work. This
is technically an API break, but it's easily fixed (just add the
.vvvvvv), plus there's nothing to be gained from not having an
extension, plus basically no one ever actually did this in the first
place (as far as I know, I am the only person to have ever done this,
and no one else ever has).
2021-04-09 11:26:59 -04:00
TerryCavanagh
8b1efb4335 Default to 60 FPS mode (fixes #702) 2021-04-09 20:40:22 +10:30
TerryCavanagh
eee98b0e07 Clean up of options menus for v2.3 (fixes #696) 2021-04-09 20:39:12 +10:30
TerryCavanagh
d9d5cbbab2 Changed the wording on "Invincibility" and "Game Speed" accessibility options
I've wanted to do this one for a very long time
2021-04-09 17:53:15 +10:30
Misa
300f1b7919 Switch assets mounting to dedicated directory
This fixes an issue where you would be able to mount things other than
custom assets in per-level custom asset directories and zips.

To be fair, the effects of this issue were fairly limited - about the
only thing I could do with it was to override a user-made quicksave of a
custom level with one of my own. However, since the quicksave check
happens before assets are mounted, if the user didn't have an existing
quicksave then they wouldn't be able load my quicksave. Furthermore,
mounting things like settings.vvv simply doesn't work because assets
only get mounted when the level gets loaded, but the game only reads
from settings.vvv on startup.

Still, this is an issue, and just because it only has one effect doesn't
mean we should single-case patch that one effect only. So what can we
do?

I was thinking that we should (1) mount custom assets in a dedicated
directory, and then from there (2) mount each specific asset directly -
namely, mount the graphics/ and sounds/ folders, and mount the
vvvvvvmusic.vvv and mmmmmm.vvv files. For (1), assets are now mounted at
a (non-existent) location named .vvv-mnt/assets/. However, (2) doesn't
fully work due to how PhysFS works.

What DOES work is being able to mount the graphics/ and sounds/ folders,
but only if the custom assets directory is a directory. And, you
actually have to use the real directory where those graphics/ and
sounds/ folders are located, and not the mounted directory, because
PHYSFS_mount() only accepts real directories. (In which case why bother
mounting the directory in the first place if we have to use real
directories anyway?) So already this seems like having different
directory and zip mounting paths, which I don't want...

I tried to unify the directory and zip paths and get around the real
directory limitation. So for mounting each individual asset (i.e.
graphics/, sounds/, but especially vvvvvvmusic.vvv and mmmmmm.vvv), I
tried doing PHYSFS_openRead() followed by PHYSFS_mountHandle() with that
PHYSFS_File, but this simply doesn't work, because PHYSFS_mountHandle()
will always create a PHYSFS_Io object, and pass it to a PhysFS internal
helper function named openDirectory() which will only attempt to treat
it as a directory if the PHYSFS_Io* passed is NULL. Since
PHYSFS_mountHandle() always passes a non-NULL PHYSFS_Io*,
openDirectory() will always treat it like a zip file and never as a
directory - in contrast, PHYSFS_mount() will always pass a NULL
PHYSFS_Io* to openDirectory(), so PHYSFS_mount() is the only function
that works for mounting directories.

(And even if this did work, having to keep the file open (because of the
PHYSFS_openRead()) results in the user being unable to touch the file on
Windows until it gets closed, which I also don't want.)

As for zip files, PHYSFS_mount() works just fine on them, but then we
run into the issue of accessing the individual assets inside it. As
covered above, PHYSFS_mount() only accepts real directories, so we can't
use it to access the assets inside, but then if we do the
PHYSFS_openRead() and PHYSFS_mountHandle() approach,
PHYSFS_mountHandle() will treat the assets inside as zip files instead
of just mounting them normally!

So in short, PhysFS only seems to be able to mount directories and zip
files, and not any loose individual files (like vvvvvvmusic.vvv and
mmmmmm.vvv). Furthermore, directories inside directories works, but
directories inside zip files doesn't (only zip files inside zip files
work).

It seems like our asset paths don't really work well with PhysFS's
design. Currently, graphics/, sounds/, vvvvvvmusic.vvv, and mmmmmm.vvv
all live at the root directory of the VVVVVV folder. But what would work
better is if all of those items were organized into a subfolder, for
example, a folder named assets/. So the previous assets mounting system
before this patch would just have mounted assets/ and be done with it,
and there would be no risk of mounting extraneous files that could do
bad things. However, due to our unorganized asset paths, the previous
system has to mount assets at the root of the VVVVVV folder, which
invites the possibility of those extraneous bad files being mounted.

Well, we can't change the asset paths now, that would be a pretty big
API break (maybe it should be a 2.4 thing). So what can we do?

What I've done is, after mounting the assets at .vvv-mnt/assets/, when
the game loads an asset, it checks if there's an override available
inside .vvv-mnt/assets/, and if so, the game will load that asset
instead of the regular one. This is basically reimplementing what PhysFS
SHOULD be able to do for us, but can't. This fixes the issue of being
able to mount a quicksave for a custom level inside its asset directory.

I should also note, the unorganized asset paths issue also means that
for .zip files (which contain the level file), the level file itself is
also technically mounted at .vvv-mnt/assets/. This is harmless (because
when we load a level file, we never load it as an asset) but it's still
a bit ugly. Changing the asset paths now seems more and more like a good
thing to do...
2021-04-05 16:39:37 -04:00
Misa
798bf9e490 Add filename to mountAssetsFrom() error message
This will clarify which directory, exactly, failed to mount. I know it
gets printed earlier in the mounting process, but it can't hurt to print
it twice, just to be sure. Also this is for consistency.
2021-04-05 16:39:37 -04:00
Misa
ff3cba9cee Replace asset load calls with loadAssetToMemory()
All assets now use FILESYSTEM_loadAssetToMemory() instead of
FILESYSTEM_loadFileToMemory().
2021-04-05 16:39:37 -04:00
Misa
72ae6921ea Add FILESYSTEM_loadAssetToMemory()
This is currently just a wrapper around FILESYSTEM_loadFileToMemory(),
but assets are supposed to use this function instead of the regular one.
2021-04-05 16:39:37 -04:00
Misa
aea5611e5b Remove default argument from loadFileToMemory()
Default function arguments are the devil, and it's better to be more
explicit about what you're passing into the function. Also because we
might become C-only in the future and to help faciliate that, we should
get rid of C++-isms like default function arguments now.
2021-04-05 16:39:37 -04:00
Misa
a11920e1a9 Remove redundant getDirSeparator() calls in init()
PHYSFS_getDirSeparator() already gets called and stored in pathSep at
the top of FILESYSTEM_init(). So clearly, two people worked on this
function and forgot that both pieces of code existed at the same time
(or it was one person independently forgetting both).
2021-04-05 16:39:37 -04:00
Misa
34ec943b5c Remove getDirSeparator() usage from mountAssetsFrom()
PhysFS uses platform-independent notation, so we really don't need to
care about getting the correct dir separator here. Especially since we
don't ever do so anywhere else (e.g. load/saveTiXml2Document()), either.
2021-04-05 16:39:37 -04:00
Misa
d95ba3a8b3 Rename FILESYSTEM_mount() to FILESYSTEM_mountAssetsFrom()
This is to make it clear that this is not a general-purpose mounting
function; it is a helper function for FILESYSTEM_mountAssets()
specifically for treating a directory or file as an assets directory,
and mounting assets from there.
2021-04-05 16:39:37 -04:00
Misa
43692388c0 Use FILESYSTEM_mount() when mounting zips
There's no reason to handle mounting .zip files differently than
mounting a directory... we already mount .data.zip files using
FILESYSTEM_mount(), so why go through the trouble of opening a .zip
manually (which means on Windows the .zip can't be touched for the
duration of playing the custom level), making up a place to mount it at,
and then mount that made-up name, instead of just using
FILESYSTEM_mount()?

Whoever cobbled this asset mounting thing together really didn't fully
understand what they were doing.
2021-04-05 16:39:37 -04:00
Misa
a8a09a207f Properly camel-case FILESYSTEM_[un]mountassets()
They are now camel-cased to be consistent with the rest of the
filesystem functions.
2021-04-05 16:39:37 -04:00
Misa
9c8ecdb0f4 Return early if FILESYSTEM_mountassets() fails
This way, we avoid the unnecessary graphics.reloadresources() call - if
we can't mount assets, why bother reloading resources?

The return type of FILESYSTEM_mount() has been changed from void to bool
to indicate success, accomodating its callers accordingly.
2021-04-05 16:39:37 -04:00
Misa
1e375f9ecf Un-export FILESYSTEM_mount()
This function is never used outside of FileSystemUtils.cpp; there is no
reason to export it.
2021-04-05 16:39:37 -04:00
Ethan Lee
5060b4dfe3 Only do focus fullscreen toggling on X11.
I haven't been able to reproduce this old thing on any setup I have. The patch
from 2013 was originally for X11, and Wayland's fullscreen doesn't allow for
this sort of thing, so let's start scoping this down for eventual removal when
X11 is finally out of our minds forever.
2021-04-05 11:07:32 -04:00
Misa
510ec07021 Re-fix resumemusic/musicfadein once again
So it looks like facb079b35 (PR #316) had
a few issues.

The SDL performance counter doesn't really work that well. Testing
reveals that unfocusing and focusing the game again results in
the resumemusic() script command resuming the track at the wrong time.
Even when not unfocusing the game at all, stopping a track and resuming
it resumes it at the wrong time. (Only disabling the unfocus pause fixes
this.)

Furthermore, there's also the fact that the SDL performance counter
keeps incrementing when the game is paused under GDB. So... yeah.

Instead of dealing with the SDL performance counter, I'm just going to
pause and resume the music directly (so the stopmusic() script command
just pauses the music instead). As a result, we no longer can keep
constantly calling Mix_PauseMusic() or Mix_ResumeMusic() when focused or
unfocused, so I've moved those calls to happen directly when the
relevant SDL events are received (the constant calls were originally in
VCE, and whoever added them (I'm pretty sure it was Leo) was not the
sharpest tool in the shed...).

And we are going to switch over to using our own fade system instead of
the SDL mixer fade system. In fact, we were already using our own fade
system for fadeins after collecting a trinket or a custom level
crewmate, but we were still using the mixer system for the rest. This is
an inconsistency that I am glad to correct, so we're also doing our own
fadeouts now.

There is, however, an issue with the fade system where the length it
goes for is inaccurate, because it's based on a volume-per-frame second
calculation that gets truncated. But that's an issue to fix later - at
least what I'm doing right now makes resumemusic() and musicfadein()
work better than before.
2021-04-02 16:13:54 -04:00
Misa
6d3a73c540 Add pause(), pauseef(), and resumeef() to musicclass
musicclass already had a resume() function for music.

These are just wrappers around the appropriate SDL_mixer functions, to
avoid direct function calls to the mixer API. So if we ever need to do
something with all callers of pausing and resuming in the future, or we
switch to a different audio backend, the work is already done for us.

Also it just looks cleaner to be calling our musicclass function instead
of doing a direct API call to the mixer.
2021-04-02 16:13:54 -04:00
Misa
92b3c0b413 Factor fade amount calculation to separate function
This makes it so to reuse this code, we don't have to copy-paste it.

Additionally, I added a check for the milliseconds being 0, to avoid a
division by zero. Logically and mathematically, if the fade amount is 0
milliseconds, then that means the fade should happen instantly -
however, dividing by zero is undefined (both in math and in C/C++), so
this check needs to be added.
2021-04-02 16:13:54 -04:00
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
4b3409e2e8 Remove advancetext check from teleporter prompt logic
This fixes being unable to use teleporters while the "- Press ACTION to
advance text -" prompt is up, which is used to perform credits warp.

In 2.2 and 2.0, this advancetext check was only in gamerender() for
rendering the "- Press ENTER to Teleport -" prompt and didn't affect any
logic. In 2.3, I moved the check (and the rest of the conditional it was
in) to gamelogic() - same as the activity zone prompt conditionals - so
if you gained control while being in a prompt zone, the prompt wouldn't
suddenly appear[1].

As a side effect, this ended up aligning rendering and logic together,
so if you couldn't see the teleporter prompt, you weren't able to
teleport - whereas in 2.2 and 2.0, you could still use the teleporter
even though the prompt wasn't up.

So by removing the advancetext check, you are now able to use the
teleporter again, AND the "- Press ENTER to Teleport -" prompt will also
show up as well.

Habeechee reported this regression on the VVVVVV speedrunning Discord
server.

[1]: f07a8d2143, PR #421
2021-04-02 11:16:42 -04:00
Misa
cd2f5ccde9 Add period to glitchrunner mode description text
This is to be consistent with the other options in the Advanced Options
menu.
2021-04-02 11:15:53 -04:00
Misa
91bc438d79 Fix funcs not being reassigned if delta func is last func in list
One of the solutions to the quit signal unfocus pause regression is to
add a no-op delta func to the unfocused func table. However, this
results in the game being stuck in unfocus pause forever, because when
it reaches the end of a list on a delta func, it won't reassign the
active functions - only when the end of a list is a fixed func will it
do so. A workaround is to then add a no-op fixed func afterwards, but
that's inelegant.

The solution in the end to the quit signal regression is to not bother
with adding a delta func, so the game as of right now actually never has
a delta func at the end of a list, and probably never will - but this is
one piece of technical debt I don't want to leave laying around. In case
we're ever going to put a delta function at the end of a list, I've made
it so that delta functions will now reassign the list of active funcs if
they happen to be at the end of the func list.
2021-04-02 11:15:18 -04:00
Misa
03a0b1feb2 Call VVV_exit() when SDL_QUIT is received
This fixes a regression introduced by #535 where a quit signal (e.g.
Ctrl-C) sent to the window while the game was in unfocus pause wouldn't
close the game.

One problem was that key.quitProgram would only be checked when control
flow switched back to the outer loop in main(), which would only happen
when the loop order state machine switched to a delta function. As the
unfocused func table didn't have any delta functions, this means
key.quitProgram would never be checked.

So a naïve solution to this would just be to add a no-op delta func
entry to the unfocused func table. However, we then run into a separate
issue where a delta function at the end of a func list never reassigns
the active funcs, causing the game to be stuck in the unfocus pause
forever. Active func reassignment only happens after fixed funcs. So
then a naïve solution after that would be to simply add a no-op fixed
func entry after that. And indeed, that would fix the whole issue.

However, I want to do things the right way. And this does not seem like
the right way. Even putting aside the separate last-func-being-delta
issue, it mandates that every func list needs a delta function. Which
seems quite unnecessary to me.

Another solution I considered was copy-pasting the key.quitProgram check
to the inner loops, or adding some sort of signal propagation to
the inner loops - implemented by copy-pasting checks after each loop -
so we didn't need to copy-paste key.quitProgram... but that seems really
messy, too.

So, I realized that we could throw away key.quitProgram, and simply call
VVV_exit() directly when we receive an SDL_QUIT event. This fixes the
issue, this removes an unnecessary middleman variable, and it's pretty
cleanly and simply the right thing to do.
2021-04-02 11:14:24 -04:00
Terry Cavanagh
4ebbfe476a
Merge pull request #588 from InfoTeddy/general-bug-fixes
Fix tile of disappearing platforms during final stretch
2021-04-02 17:51:30 +10:30
Terry Cavanagh
886a57ab83
Merge pull request #667 from InfoTeddy/general-improvements
Add text outlines to textboxless textboxes and gravitron text
2021-04-02 17:49:20 +10:30
Misa
ef091de23e Outline all gravitron text
This includes all text from the Gravitron and Super Gravitron.

This is to make the text more readable if they are placed in weird
situations - for example, in custom levels, where the background these
texts get placed on could be anything (custom level makers are crazy!).
2021-03-30 23:57:00 -07:00
Misa
6538d1e5dd Add Graphics::bigrprint()
Same as bigbprint(), we duplicate some of the calculations because it's
better than duplicating another text printing function.
2021-03-30 23:57:00 -07:00
Misa
f7173027ce Add Graphics::bigbprint()
It's just like bigprint() except it duplicates some of the calculations
because I didn't want to make a bigprintoff() function which would
duplicate even more code. I'm beginning to think these text printing
functions are completely horrible to work with...
2021-03-30 23:57:00 -07:00
Misa
827b3e430b Outline textboxless textboxes
In case they get drawn against a non-contrasting background, it's still
useful to keep them readable by outlining them. This could happen if
someone were to use the Game Complete gamestate sequence in a custom
level (or presses R during Game Complete).
2021-03-30 23:57:00 -07:00
Misa
0c72260c5d Fix oversight with unfocus pause screen in Flip Mode
Flip Mode flips all the unfocus pause screen text upside-down, to make
it read in reverse order. This looks kind of strange to me, and I don't
think it was intended. So I'm flipping the text again so it's the right
way up in Flip Mode.
2021-03-30 23:55:42 -07:00
Misa
f9e76d9dc0 Fix tile of disappearing platforms during final stretch
During the final stretch, after Viridian turns off the Dimensional
Stability Generator, the map goes all psychedelic and changes colors
every 40 frames. Entities change their colors too, including conveyors,
moving platforms, and disappearing platforms.

But play around with the disappearing platforms for a bit and you'll
notice they seem a bit glitchy. If you run on them at the right time,
the tile they use while disappearing seems to abruptly change whenever
the color of the room changes. If there's a color change while they're
reappearing (when you die and respawn in the same room as them), they'll
have the wrong tile and look like a conveyor. And even if you've never
interacted with them at all, dying and respawning in the same room as
them will change their tile to something wrong and also look like a
conveyor.

So, what's the problem? Well, first off, the tile of every untouched
disappearing platform changing into a conveyor after you die and respawn
in the same room is caused by a block of code in gamelogic() that gets
run on each entity whenever you die. This block of code is the exact
same block of code that gets ran on a disappearing platform if it's in
the middle of disappearing.

As a quick primer, every entity in the game has a state, which is just a
number. You can view each entity's state in
entityclass::updateentities().

State 0 of disappearing platforms is doing nothing, and they start with
an onentity of 1, which means they turn to state 1 when they get
touched. State 1 moves to state 2. State 2 does some decrementing, then
moves to state 3 and sets the onentity to 4. State 3 also does nothing.
After being touched, state 4 makes the platform reappear and move to
state 5, but state 5 does the actual reappearing; state 5 then sets the
state back to 0 and onentity back to 1.

So, back to the copy-pasted block of code. The block of code was
originally intended to fast-forward disappearing platforms if they were
in the middle of disappearing, so the player respawn code would properly
respawn the disappearing platform, instead of leaving it disappeared.
What it does is keep updating the entity, while the state of the entity
is 2, until it is no longer in state 2, then sets it to state 4.

Crucially, the original block of code only ran if the disappearing
platform was in state 2. But the other block of code, which was
copy-pasted with slight modifications, runs on ALL disappearing
platforms in final stretch, regardless of if they are in state 2 or not.

Thus, all untouched platforms will be set to state 4, and state 4 will
do the animation of the platform reappearing, which is invalid given
that the platform never disappeared in the first place. So that's why
dying and respawning in the same room as some disappearing platforms
during final stretch will change their tiles to be conveyors.

It seems to me that doing anything with death is wrong, here. The root
cause is that map.changefinalcol() "resets" the tile of every
disappearing platform, which is a function that gets called on every
color change. The color change has nothing to do with dying, so why
fiddle with the death code?

Thus, I've deleted that entire block of code.

What I've done to fix the issue is to make it so the tile of
disappearing platforms aren't manually controlled. You see, unlike other
entities in the game, the tile of disappearing platforms gets manually
modified whenever it disappears or reappears. Other entities use the
tile as a base and store their tile offset in the separate walkingframe
attribute, which will be added to the tile attribute to produce the
drawframe, which is the final thing that gets rendered - but for
disappearing platforms, their tile gets directly incremented or
decremented whenever they disappear or reappear, so when
map.changefinalcol() gets ran to update the tile of every platform and
conveyor, it basically discards the tile offset that was manually added
in.

Instead, what I've done is make it so disappearing platforms now use
walkingframe, and thus their final drawframe will be their tile plus
their walkingframe. Whenever map.changefinalcol() gets called, it is now
free to modify the tile of disappearing platforms accordingly - after
all, the tile offset is now stored in walkingframe, so no weird
glitchiness can happen there.
2021-03-30 23:55:34 -07:00
Misa
a405635cb2 Replace other usage of PHYSFS_getBaseDir() with SDL_GetBasePath()
Ethan, you forgot this other one.

I do have to rejiggle the control flow of the function a bit, so it
doesn't leak memory upon failure. (Although the SDL message box leaks
memory anyway because of X11 so... whatever.) Also, there's a NULL check
for if SDL_GetBasePath() fails now.
2021-03-31 02:51:52 -04:00
Ethan Lee
051fe9eba9 Skip the icon on Apple targets, it also has the icns 2021-03-31 02:50:38 -04:00
Ethan Lee
b99abaf1d5 Put Misa at the top of GitHub Friends 2021-03-31 02:43:15 -04:00
Ethan Lee
4c4f8de0d5 Fix leaking GetBasePath result 2021-03-31 02:43:15 -04:00
Misa
8cf79aaf72 Fix memory leak when pasting text
According to SDL documentation[1], the returned pointer needs to be
freed. A glance at the source code confirms that the function allocates,
and also Valgrind complains about it.

Also if it couldn't allocate, the game no longer segfaults (std::strings
do not check if the pointer is non-NULL for operator+=).

[1]: https://wiki.libsdl.org/SDL_GetClipboardText
2021-03-31 02:29:36 -04:00
Ethan Lee
9d2ebbc982
Re-sync CONTRIBUTORS and GitHub Friends lists 2021-03-30 23:08:25 -04:00
Ethan Lee
b87f6e487a Use SDL_GetBashPath instead of PHYSFS_getBaseDir, latter is made of fail on macOS 2021-03-30 12:18:09 -04:00
Ethan Lee
076a870ba2 VS2010 buildfix 2021-03-30 11:51:42 -04:00
Misa
367e77fb59 Fix targets (question marks) not showing up on minimap
Followup to #635: I had misread the original '==0' comparisons as being
truthy comparisons instead of being falsy comparisons. Whoops.
2021-03-26 00:02:26 -04:00
Misa
892e7c93fc Fix background not changing when pressing Esc on main menu
Followup to #664: Pressing "quit game" instead of using Esc changes the
background, but pressing Esc doesn't. Whoops.
2021-03-25 23:32:59 -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
be10487c5c Set fademode to temp 0 when going to in-game options
While I've decoupled fademode from gamemode starting, being faded out on
the title screen results in a black screen and you being unable to make
any input. So we'll need to store the current fademode in a temporary
variable when going to in-game options, then put it back when we return
to the pause menu. Yes, you can turn on glitchrunner mode during the
in-game options, and then immediately return to the pause menu to
instantly go back to the title screen; this is intended.

Due to frame ordering, putting the fademode back needs to be deferred to
the end of the frame to prevent a 1-frame flicker.

It's actually sufficient enough to do this temporary fademode storage to
fix the whole thing, but I also decided to decouple fademode and
gamemode starting just to be sure.
2021-03-25 23:32:39 -04:00
Misa
82dfa0b86c Decouple fademode from starting gamemode
Assuming glitchrunner mode is off, if you open the pause menu while
fully faded-out and then go to Graphic Options or Game Options, then the
'mode' that you selected previously will kick in again and you'll be
suddenly warped back.

So if you previously started a new game in the main game (mode 0, also
the selected mode if you do this from command-line playtesting), and
then open the pause menu and go to in-game options, then you'll suddenly
go back to starting a new game again. If you had started a custom level,
doing this will warp you back to the start of the level again.

The problem is simple - when the title screen is fully faded out, it
calls startgamemode(). So the solution is simple as well - just decouple
the fademode from calling startgamemode(), and use a different variable
to know when to actually call startgamemode().
2021-03-25 23:32:39 -04:00
Misa
cd0c9ccb31 De-duplicate setting mainmenu and fademode
This makes my work easier later.
2021-03-25 23:32:39 -04:00
Misa
6a6c09f69d Fix 1-frame flicker entering room with warp lines and entity on edge
Custom levels can have warp lines. If you have a warp line and a warping
background in the same room, the warp line takes precedence over the
warp background.

However, whenever you enter a room with a warp line and warp background,
any entities on the warping edges will be drawn with screenwrapping for
one frame, even though they never wrapped at all.

This is due to frame ordering: when the warp line gets created,
obj.customwarpmode gets set to true. Then when the screen edges and
warping logic gets ran, the very first thing that gets checked is this
exact variable, and map.warpx/map.warpy get set appropriately - so
there's no way the entity could legitimately screenwrap.

However, that happens in gamelogic(). gamelogic() is also the one
responsible for creating entities upon room load, but that happens after
the obj.customwarpmode check - so when the game gets around to rendering
in gamerender(), it sees that map.warpx or map.warpy is on, and draws
the screenwrapping, even though map.warpx/map.warpy aren't really on at
all. Only when gamelogic() is called in the frame later do map.warpx and
map.warpy finally get set to false.

To fix this, just set map.warpx and map.warpy to false when creating
warp lines.
2021-03-25 22:29:40 -04:00
Misa
8fd7210d37 De-duplicate warp line creation in createentity()
Copy-pasted code begone. This makes it much clearer what the difference
between all the warp line entities in this function are.
2021-03-25 22:29:40 -04:00
Misa
c8f4c37c88 Add bounds check for color of createentity number 55
I just spotted this one - if vy isn't bounds-checked, this causes bogus
input from the createentity() script command to commit Undefined
Behavior. Should've spotted this one when I was adding bounds checks to
the rest of createentity() earlier, but at least it's fixed now.
2021-03-25 21:43:51 -04:00
Misa
423c79b572 Add bounds checks to room explored getter and setter
This means you can no longer cause Undefined Behavior by exploring a
room that is outside the array of explored room statuses.
2021-03-24 15:55:34 -04:00
Misa
c5e999c1d5 Refactor explored rooms to use setters and getters
This makes it easier to add bounds checks to all accesses of
map.explored. Also, all manually-written existing bounds checks have
been removed, because they're going to go into the new getters and
setters.

The getter is mapclass::isexplored() and the setter is
mapclass::setexplored().
2021-03-24 15:55:34 -04:00
Misa
b340a6ccc4 Add bounds checks to room propety getters and setters
It is no longer possible to cause Undefined Behavior via accessing
out-of-bounds room properties.

What happens instead is - if you attempt to fetch an out-of-bounds room
property, you get a "blank" room property that just has all of the
defaults, plus its tileset is 1 because all tilesets that are nonzero
use tiles2.png, and it closely emulates the previous behavior where it
was some bogus value but definitely not zero. Its Direct Mode is also 1,
because the tiles contained within it are just mishmashed repeats of
existing tiles on the map, and we shouldn't autotile that.

The roomname also gets cleared in case the user attempts to set the room
name of an out-of-bounds room property.

If you attempt to set the property of an out-of-bounds room property,
then nothing happens.
2021-03-24 15:55:34 -04:00
Misa
945d5f244a Refactor room properties to use setter and getter funcs
This replaces all raw ed.level accesses with new setter and getter
funcs, which makes it easier to add bounds checks later. And I've also
removed all the manually-written bounds checks, since they will go into
the new getter and setter.

To get the room properties of a specific room, you use
editorclass::getroomprop(), which returns a pointer to the room
properties - then you just read off of that pointer. To set a room
property, you use editorclass::setroom<PROP>(), where <PROP> is the name
of the property. These are maintained using X macros to avoid
copy-pasting. editorclass::getroompropidx() is a helper function and
shouldn't be used directly.
2021-03-24 15:55:34 -04:00
Misa
cfd5be1bc5 Add bounds checks to tile setter and getters
This removes all traces of Undefined Behavior from getting and placing
tiles.

This mimics the previous behavior (2.2 and below) as reasonably as
possible. `vmult` was previously a vector, there was a bunch of unused
space directly after the end of the usable space of the vector, which
was all filled with zeroes. The same goes for `contents`, having
previously been a vector, and so having a bunch of zeroes immediately
following the end of the in-bounds space. That's why both are 0 if you
index them out of bounds.
2021-03-24 15:55:34 -04:00
Misa
344c93e754 Refactor tiles to use setter and getter functions
This makes it easier to add bounds checks to all accesses of
ed.contents.

To do this, I've added editorclass::gettile(), editorclass::settile(),
and editorclass::getabstile() (with a helper function of
editorclass::gettileidx() that really shouldn't be used directly), and
replaced all raw accesses of ed.contents with those functions
appropriately.

This also makes the code more readable, as a side effect.
2021-03-24 15:55:34 -04:00
Misa
ccdb0c9148 Fix bounds checks in drawentity()
The existing bounds checks were correct sometimes but other times were
not.

The bounds check for 2x2 and 2x1 sprites only covered the top-left
sprite drawn; the other sprites could still be out of bounds. But if the
top-left sprite was out of bounds, then none of the other sprites
wouldn't be drawn - although it ought to be that the other sprites still
get attempted to be drawn. So I've updated the bounds checks
accordingly, and now an out of bounds top-left sprite won't prevent the
drawing of the rest of the sprites.

Similarly, if the sprite of a Gravitron square was out of bounds, that
would prevent its indicators from being drawn. But the indicators
weren't being bounds-checked either (2.3 lets you have less than 1200
tiles in a given tilesheet). So the bounds check has been moved to only
cover the drawframe and the indicator indexes accordingly, and an out of
bounds sprite won't prevent attempting to draw the indicators.
2021-03-24 15:42:28 -04:00
Misa
4e52dccdae Initialize temporary edentity when loading levels
It is possible for any of the QueryIntAttribute()s to fail, most
commonly if the attributes don't exist. If that happens, then that part
of the temporary edentity won't be initialized, and we'll end up having
a partially-uninitialized edentity - then doing much of anything with it
will result in undefined behavior.

To fix this, just initialize the temporary edentity.
2021-03-24 15:26:09 -04:00
Misa
69b0f0b650 Add missing pText NULL checks
If an XML tag doesn't contain anything inside, pText will be NULL. If
that happens without being checked, then NULL will be passed to
SDL_strcmp(). SDL_strcmp() will either call libc strcmp() or use its own
implementation; both implementations will still dereference the NULL
without checking it.

This is undefined behavior, so I'm fixing it. The solution is to do what
is done with all other XML parsing functions, and to make sure pText
gets set to a safe empty string (which is just a pointer to a null
terminator) if it happens to be NULL.
2021-03-24 15:26:09 -04:00
Misa
0da9b5069a Capitalize "OFF" when invincibility is off
All other settings capitalize "ON" and "OFF", so this one should, too.
2021-03-21 20:53:40 -04:00
Misa
9ab61af1da Add period to text outline description
This is to be consistent with all other option descriptions, which all
end in a period as well.
2021-03-21 20:53:40 -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
17169320b4 Fix text box deltaframe flashing on deltaframes after fully opaque
So #434 didn't end up solving the deltaframe flashing fully, only
reduced the chances that it could happen.

I've had the Level Complete image flash a few times when the Game Saved
text box pops up. This seems to be because the Level Complete image is
based off of the text box being at y-position 12, and the Game Saved
text box is also at y-position 12. Level Complete only gets drawn if the
text box additionally has a red channel value of 165, and the Game Saved
text box has a red channel value of 174. However, there is a check that
the text box be fully opaque first before drawing special images. So
what went wrong?

Well, after thinking about it for a while, I realized that even though
there is indeed an opaqueness check, the alpha of the text box updates
BEFORE it gets drawn. And during the deltaframes immediately after it
gets updated, the text box is considered fully opaque. It's completely
possible for the linear interpolation to end up with a red channel value
of 165 during these deltaframes, while the text box is opaque as well.

As always, it helps if you have a high refresh rate, and run the game
under 40% slowdown.

Anyways, so what's the final fix for this issue? Well, use the text box
'target' RGB values instead - its tr/tg/tb attributes instead of its
r/g/b attributes. They are not subject to interpolation and so are
completely reliable. The opaqueness check should still be kept, though,
because the target values don't account for opaqueness. And this way, we
get no more deltaframe flashes during text box fades.

An even better fix would be to not use magic RGB values to draw special
images... but that'd be something to do later.
2021-03-21 19:01:36 -04:00
Ethan Lee
415d4790e2
Fix a crash on first unfocus 2021-03-21 17:19:08 -04:00
Ethan Lee
7abd4bb8d8
Visual Studio buildfix 2021-03-21 17:15:36 -04:00
Misa
4a79f02842 Add braces around sub-object in unfocused_func_list
Clang warns on this. This doesn't fix anything but it does ensure that
whoever's reading it won't be focused as to whether or not omitting the
second set of braces is legal or not.
2021-03-21 17:03:17 -04:00
Misa
02560ca6e5 Remove now-unneeded kludge for finalmode entity colors
Previously, with the wrong loop order, this kludge needed to exist so
entities in finalmode didn't have wrong colors for 1 frame when entering
a room. But now the loop order has been fixed, and so this kludge is no
longer needed.
2021-03-21 02:55:42 -04:00
Misa
287061c768 Fix filter/screenshake/flash update order
In 2.2, at render time, the game rendered screenshakes and flashes if
their timers were above 0, and then decremented them afterwards. The
game would also update the analogue filter right before rendering it,
too.

In 2.3, this was changed so the flash and screenshake timers were
unified, and also done at the end of the frame - right before rendering
happened. This resulted in 1-frame flashes and screenshakes not
rendering at all. The other changes in this patchset don't fix this
either. The analogue filter was also in the wrong order, but that is
less of an issue than flashes and screenshakes.

So, what I've done is made the flash and screenshake timers update right
before the loop switches over to rendering, and only decrements them
when we switch back to fixed functions (after rendering). The analogue
filter is also updated right before rendering as well. This restores
1-frame flashes and screenshakes, as well as restores the correct order
of analogue filter updates.
2021-03-21 02:55:42 -04:00
Misa
094209bd12 Move logical onground/onroof updates to start of gamelogic
This reintroduces 2-frame edge-flipping after the 1-frame input delay
got removed. This is because along with processing input and moving
Viridian, logical onground/onroof assignments need to processed in the
same between-render sequence as well - otherwise Viridian only gets 1
frame of edge-flipping due to frame ordering.
2021-03-21 02:55:42 -04:00
Misa
63a60b11cc Split onground/onroof into visual and logical variables
I will need to separate these into two different variables because I
will need to move logical onground/onroof assignments to the start of
gamelogic() - if I kept them together, however, that would change the
visuals of onground/onroof, which I want to keep consistent with 2.2.
2021-03-21 02:55:42 -04:00
Misa
d5d9d9ba96 Re-remove 1-frame input delay
To do this, GAMEMODE input needs to be processed, and Viridian needs to
be moved, in the same sequence between render frames. So just move
gameinput to after gamerender. Yes, this is not 2.2 order, but gameinput
only handles player input and nothing else - plus a 1-frame input delay
feels really awful to play with in over-30-mode.
2021-03-21 02:55:42 -04:00
Misa
f1f434accc Move key.Poll() calls to just before input funcs
In order to re-remove the 1-frame input delay, we will have to poll
input right after rendering a frame - in other words, just before an
input function gets called.

To do this, I've added a new function enum type - Func_input - that is
the same as a fixed function, but before its function gets called,
key.Poll() gets called. And all input functions have been updated to use
this enum accordingly.
2021-03-21 02:55:42 -04:00
Misa
ab26985fde Re-fix crewmate directions (without copy-pasting)
This once again fixes the facing directions of crewmates upon room load,
except now it covers more cases.

So, here is the saga so far:

- 2.0 (presumably) to 2.2: crewmate direction fix is special-cased at
  the end of mapclass::loadlevel(). Only covers crewmates created during
  the room load, does not cover crewmates created from scripts, only
  covers state 18 of crewmates.

- 2.3 currently (after #220): crewmate direction fix is moved to
  entityclass::createentity(), which covers every avenue of crewmate
  creation (including from scripts), but still only covers state 18.

- This commit: crewmate direction fix now covers every possible state of
  the crewmate, also does not copy-paste any code.

What I've done instead is to make it so createentity() will immediately
call updateentities() on the pushed-back entity. This is kludge-y, but
is completely okay to do, because unlike other entities, crewmate
entities never change their state or have any side-effects from
double-evaluation, meaning calling updateentities() on them is
idempotent and it's okay to call their updateentities() more than once.

This does have the slight danger that if the states of crewmates were to
change in the future to no longer be idempotent, this would end up
resulting in a somewhat hard-to-track-down double-evaluation bug, but
it's worth taking that risk.

This fix is not applied to entity 14 (the supercrewmate) because it is
possible that calling updateentities() on it will immediately remove the
entity, which is not idempotent (it's changing the state of something
outside the object). Supercrewmates are a bit difficult to work with
outside of the main game anyways, and if you spawn them you could
probably just use the changedir() script command to fix their direction,
so I'm not inclined to fix this for them anyway.
2021-03-21 02:55:42 -04:00
Misa
cb5d181ce8 Remove entityclass::createentity() deltaframe kludge
This copy-pasted code only existed because the previous loop order was
incorrect and rendered entities before they would get properly updated
by the fixed render function. Now, the fixed render function is
guaranteed to be called before the render function, so we can rely on
that to update the drawframe and realcol of entities instead of
duplicating the code ourselves in createentity().

The drawframe assignment is still kept to fix the case where dying while
completestop is active (i.e. during a trinket or crewmate rescue
cutscene) and respawning in a different room won't turn everything into
Viridian sprites.
2021-03-21 02:55:42 -04:00
Misa
2d9d0cffa5 Fix 1-frame glitch when going to in-game options from edsettings
The menu creation of Graphic Options or Game Options, as well as the
map.nexttowercolour() call, all need to be deferred until the end of the
frame.
2021-03-21 02:55:42 -04:00
Misa
951679b1f8 Fix 1-frame background glitch when returning from in-game options
The background would change for 1 frame before sending you back to the
pause menu or editor settings. The map.nexttowercolour() call needs to
be deferred until the end of the frame.
2021-03-21 02:55:42 -04:00
Misa
5088ff40e9 Fix 1-frame text glitch when returning to editor settings from options
The returnmenu() needs to be deferred until the end of the frame.
2021-03-21 02:55:42 -04:00
Misa
8a3e292041 Fix 1-frame text glitch returning to pause menu from in-game options
The new loop order introduces a glitch where the menu would display
whichever menu was saved to kludge_ingametemp for 1 frame right as the
user returned to the pause menu. This happened because the
game.returntomenu() happens in titleinput(), which comes before
titlerender(). To fix this, we just need to defer it to the end of the
frame.
2021-03-21 02:55:42 -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
32be2fcd81 Update player lerpoldxp/yp in moveplayer()
Just like gotoposition(), the player would otherwise appear to "zip"
after the command got run. This did not happen in the previous loop
order.
2021-03-21 02:55:42 -04:00
Misa
c8537beac1 Add deferred callbacks to game loop
Sometimes, there needs to be code that gets ran at the end of the game
loop, otherwise rendering issues might occur. Currently, we do this by
special-casing each deferred routine (e.g. shouldreturntoeditor), but it
would be better if we could generalize this deference instead.

Deferred callbacks can be added using the DEFER_CALLBACK macro. It takes
in one argument, which is the name of a function, and that function must
be a void function that takes in no arguments. Also, due to annoying C++
quirks, void functions taking no arguments cannot be attributes of
objects (because they have an implicit `this` parameter), so it's
recommended to create each callback separately before using the
DEFER_CALLBACK macro.
2021-03-21 02:55:42 -04:00
Misa
c8958de537 Update player lerpoldxp/yp in gotoposition()
Otherwise, the player would appear to "zip" during the deltaframes
between their previous position and their new position. This did not
happen in the previous game loop order and only happens in the new one.
2021-03-21 02:55:42 -04:00
Misa
af70076088 Remove now-unneeded deltaframe fix when going to in-game settings
Previously, before the game loop order got fixed, going to the in-game
settings would switch over to the new render function too early, causing
a deltaframe glitch that had to be fixed. But now, the render function
only gets switched when the current gamestate's function list gets
finished executing, so the game won't suddenly switch to titlerender()
in the middle of the ACTION press to the in-game settings screen.

As a consequence, titleupdatetextcol() no longer needs to be exported to
Input.cpp.
2021-03-21 02:55:42 -04:00
Misa
c26b701f5b Remove gravity line kludge from Graphics::drawgravityline()
Now that the game loop order is now fixed, there is no longer any need
for this kludge.
2021-03-21 02:55:42 -04:00
Misa
5e2fc6f0fe Move updating lerpoldxp/yp to start of gamelogic()
The previous location of this loop was placed there because it happened
just after the end of the render function. Now that the loop order is
fixed, the first thing that happens after the render function is the
start of gamelogic(), so this loop should go there now, else entity
positions won't be interpolated.

Also it now preincrements instead of postincrements because I like
preincrements.
2021-03-21 02:55:42 -04:00
Misa
585ae47d78 Remove script.dontrunnextframe kludge
Now that the game loop order is fixed, this kludge (on top of kludge) is
no longer needed, and can be safely removed.
2021-03-21 02:55:42 -04:00
Misa
c82c2afbbd Unindent unfocused_run() and focused_begin() from previous commit
As always, indentation changes are applied in a separate commit to
minimize diff noise.
2021-03-21 02:55:42 -04:00
Misa
1e9fb6aac0 Generalize game loop order and fix it to what it was in 2.2
Okay, so the reason why all render functions were moved to the end of
the frame in #220 is because it's simpler to call two fixed functions
and then a delta function instead of one fixed function, then a delta
function, and then another fixed function.

This is because fixed functions need special handling inside
deltaloop(), and you can't simply duplicate this handling after calling
a delta function. Oh, and to make matters worse, it's not always
fixed-delta-fixed, sometimes (like in MAPMODE and TELEPORTERMODE) it's
delta-fixed-fixed, so we'd need to handle that somehow too.

The solution here is to generalize the game loop and factor out each
function, instead of hardcoding it. Instead of having hardcoded
case-switches directly in the loop, I made a function that returns an
array of functions for a given gamestate, along with the number of
functions, then the game loop processes it accordingly. In fixedloop(),
it iterates over the array and executes each function until it reaches a
delta function, at which point it stops. And when it reaches the end of
the array, it goes back to the start of the array.

But anyway, if it gets to a delta function, it'll stop the loop and
finish fixedloop(). Then deltaloop() will call the delta function. And
then on the next frame, the function index will be incremented again, so
fixedloop() will call the fixed functions again.

Actually, the previous game loop was actually made up of one big loop,
with a gamestate function loop nested inside it, flanked with code that
ran at the start and end of the "big loop". This would be easy to handle
with one loop (just include the beginning and end functions with the
gamestate functions in the array), except that the gamestate functions
could suddenly be swapped out with unfocused functions (the ones that
run when you unfocus the window) at any time (well, on frame boundaries,
since key.isActive only got checked once, guarding the entire "inner
loop" - and I made sure that changing key.isActive wouldn't immediately
apply, just like the previous game loop order) - so I had to add yet
another layer of indirection, where the gamestate functions could
immediately be swapped out with the unfocused functions (while still
running the beginning and end code, because that was how the previous
loop order worked, after all).

This also fixes a regression that the game loop that #220 introduced
had, where if the fixed functions switched the gamestate, the game would
prematurely start rendering the gamestate function of the new gamestate
in the deltaframes, which was a source of some deltaframe glitches. But
fixing this is likely to just as well cause deltaframe glitches, so it'd
be better to fix this along with fixing the loop order, and only have
one round of QA to do in the end, instead of doing one round after each
change separately.

Fixes #464... but this isn't the end of the patchset. There are bugs
that need to be fixed, and kludges that need to be reverted.
2021-03-21 02:55:42 -04:00
Misa
5e440ac48d Remove special text box checks for y-position 180
Y-position 180 would be the position of the Level Complete and Game
Complete special text boxes in Flip Mode. However, since the y-position
of flipme text boxes actually no longer change (because we have to
accomodate changing Flip Mode on-the-fly), these text boxes will never
actually be y-position 180 - so we should remove these checks for
clarity.
2021-03-21 02:53:25 -04:00
Misa
596696dcf3 Make foundtrinket() Flip Mode-aware
A-ha! I've spotted an inconsistency! The normal trinket collection text
boxes (gamestate 1000-1003) is aware of Flip Mode, and will position
themselves accordingly to read the correct way in Flip Mode. However,
foundtrinket() doesn't do this.

Well, now it does.
2021-03-21 02:53:25 -04:00
Misa
db9ee0d8e3 Switch flipme script command to use flipme textbox attribute
This is why the text box attribute was named flipme, after all.

You may have noticed that the flipme command inverts textflipme instead
of simply setting it to true. Well, that's because it should be the same
as the previous behavior, which was essentially to invert it instead of
setting it to true - i.e. calling flipme twice would keep the original
text box position in Flip Mode, which means it would be upside-down
(this is a lot of flipping to keep track of...) - because flipme added
to texty in-place instead of simply assigning to it. (It did the
calculation incorrectly in 2.2 and previous, but I digress.)

Similarly, textflipme is not reset in hardreset(), because none of the
other script text box variables are reset either.
2021-03-21 02:53:25 -04:00
Misa
6939563e6d Switch all flippable text boxes to use createtextboxflipme
This ensures that if the player decides to toggle Flip Mode while one of
these text boxes is up, they won't be oriented improperly. Additionally,
it also de-duplicates a bunch of Flip Mode check code, which is also a
win.
2021-03-21 02:53:25 -04:00
Misa
c7cc2f4adc Add createtextboxreal() and createtextboxflipme()
createtextboxreal() is the same as createtextbox(), but with a flipme
parameter added to create text boxes that have their flipme attribute
set to true. createtextbox() just calls createtextboxreal() with flipme
set to false, and createtextboxflipme() just calls createtextboxreal()
with flipme set to true; this is because I do not want to use C++
function overloading.
2021-03-21 02:53:25 -04:00