1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-12-23 10:09:43 +01:00
Commit graph

761 commits

Author SHA1 Message Date
Misa
f53ed222d3 Interpolate activity zone prompt fading in and out
To make it real smooth, just in case it was noticeable that it only
updated at 1000/34 FPS before (well, except in slowmode, it's really
noticeable THERE).

Also this removes the re-typing out of (game.act_fade/10.0f) for every
single R, G, and B in gamerender().
2020-06-19 09:05:48 -04:00
Misa
c56df48d75 Interpolate text box alpha
This makes text boxes fade in and out pretty smoothly.

This requires that the textboxclass::setcol() be in Graphics::drawgui(),
so now it's moved there.

Text box fading is only really noticeable if you're playing in slowmode.
2020-06-19 09:05:48 -04:00
Misa
4ba9954eb8 Move cursor delay update logic to maplogic()
Otherwise it'll go really really fast.

Incidentally this also basically de-duplicates it and results in less
copy-pasted code overall.
2020-06-19 09:05:48 -04:00
Misa
837ccfc735 Move gravity line color updating to gamelogic()
So it doesn't keep updating really quickly.
2020-06-19 09:05:48 -04:00
Misa
40cedc8c94 Move general oldxp/oldyp updating to just before gameinput()
This has to be done in order to fix rendering when on a conveyor or
moving platform and actively moving with or against it. Pretty sure this
shouldn't break anything, oldxp/oldyp is mostly visual after all (and by
the time it's used for gravity line collision checking,
updateentitylogic() would've already gotten around to it anyway).

Incidentally, this also fixes a jitter that would occur if you were
moving at the time you died or collected a trinket or custom crewmate,
due to the game temporarily freezing and either doing deathsequence or
completestop.
2020-06-19 09:05:48 -04:00
Misa
3b41721563 Interpolate bringing up and down quit/pause/teleporter screen
Now it's really, really smooth. Except for like the last frame when it
goes down, which I sometimes didn't notice (but maybe it didn't happen
every time due to being lucky on the delta timesteps or something,
whatevs.)
2020-06-19 09:05:48 -04:00
Misa
45c7292096 Simplify menu-off rendering/logic code
Since "if (graphics.resumegamemode)" and "if (menuoffset > 0)" both do
the same thing, they've been combined with an "or" conjunction.

As well, the map.extrarow check in maplogic() has been refactored to use
a variable instead of duplicating the entire code block. Not that it
matters anyway, because the difference between 240 and 230 is only 10
pixels, far short of the 25 pixel increment that bringing the menu up
and down uses, and both 240 and 230 integer-divided by 25 have the same
non-remainder value of 9.
2020-06-19 09:05:48 -04:00
Misa
a22a872886 Move menu offset logic to maplogic()
This is the logic that handles the timer that brings up and down the
teleporter, pause screen, and Esc screen. So now it doesn't go crazy
fast.
2020-06-19 09:05:48 -04:00
Misa
9ea5734abb Move backboxrect off of Graphics
No need for a temporary rect to be on the Graphics class itself.
2020-06-19 09:05:48 -04:00
Misa
4e533c65a5 Interpolate upwards-moving star BG
So that it's smooth at full FPS.
2020-06-19 09:05:48 -04:00
Misa
3b09bb36e8 Move upwards-moving star BG to Graphics::updatebackground()
So it doesn't go really really quick.
2020-06-19 09:05:48 -04:00
Misa
61d2526669 Put rainbow BG timer in Graphics::updatebackground()
Otherwise it'll go way too fast.
2020-06-19 09:05:48 -04:00
Misa
684aa38ff2 Interpolate Lab backboxes
So that they look buttery smooth.
2020-06-19 09:05:48 -04:00
Misa
1c38b63a37 Move Lab backbox updates to Graphics::updatebackground()
So that the backboxes don't go NYOOOOOOOOM.
2020-06-19 09:05:48 -04:00
Misa
92cd695859 Interpolate left-moving star background
So that it looks all smooth and such.
2020-06-19 09:05:48 -04:00
Misa
55ae3c73a9 Update left-moving star BG in fixed timestep loop
Otherwise they will move too fast.
2020-06-19 09:05:48 -04:00
Misa
495bea2e87 Update text boxes in the inner fixed-timestep loop
So they don't go really quickly.
2020-06-19 09:05:48 -04:00
Misa
4e3406d5aa Remove useless function Graphics::textboxcleanup()
It was made useless after my refactor to remove the 'active' system from
text boxes.
2020-06-19 09:05:48 -04:00
Misa
905696c263 Update trophy text timer in fixed-timestep gamelogic()
Otherwise it, too, goes by too quickly.
2020-06-19 09:05:48 -04:00
Misa
92ee33043d Update activity prompt fade in fixed-timestep gamelogic()
Otherwise it goes by too quickly.
2020-06-19 09:05:48 -04:00
Misa
e897543383 Interpolate fade amount
This makes the fadeouts and fadeins (screenwipes) much more buttery
smooth.
2020-06-19 09:05:48 -04:00
Misa
8fde6f28a3 Update screenshake position in fixed-timestep loop
Otherwise the screen will shake too fast for my liking.

Also I'm planning to add an FPS limiting option later (because right
now, un-capping the FPS is pretty wasteful and eats up lots of
resources, especially since I have only a 60hz monitor), and it'd feel
weird if screen shaking updated every delta timestep.
2020-06-19 09:05:48 -04:00
Misa
57f87dc820 Reduce indentation of "else if" in Graphics::cutscenebars()
There's no need to put the if-statement inside an entire else-block if
it's the only if-statement in there.
2020-06-19 09:05:48 -04:00
Misa
2510d3a6ba Interpolate cutscene bars position
Cutscene bars will now smoothly fade in and out at above 30 FPS instead
of at 30 FPS only.
2020-06-19 09:05:48 -04:00
Misa
6655ae418c Update cutscene bars in fixed-timestep loop
This prevents cutscene bars from going really really fast.
2020-06-19 09:05:48 -04:00
Misa
a479c61141 Simplify "else if" indentation for right-side tower screen wrapping
No need to make an entire else-block and indent it when you can just do
"else if" instead.
2020-06-19 09:05:48 -04:00
Misa
a7b62d1098 Update oldxp/oldyp when screen wrapping
This is so it doesn't look like entities "zip" across the room.
2020-06-19 09:05:48 -04:00
Misa
f06ca9172a Set drawframe to tile when creating an entity
This fixes entities being drawframe 0 for 1 frame when being first
created. Incidentally, this also fixes entities created during
completestop being the player sprite, too, which is something not many
people notice.
2020-06-19 09:05:48 -04:00
Misa
298aa95259 Move onground/onroof/animateentities logic to start of gamelogic()
For some reason, it was put near the start of gamerender(), even though
since it handles edge-flipping it seems like it should be in the logic
function already.

This makes sure entity animations don't animate as fast as possible, and
also fixes edge-flipping on normal surfaces.
2020-06-19 09:05:48 -04:00
Misa
57b643d22a Use case-switch for para-check in entclass::setenemy()
It's less verbose this way, and less typing.
2020-06-19 09:05:48 -04:00
Misa
c6659ef656 Initialize oldxp/oldyp in createentity()
This prevents undefined behavior because we use oldxp/oldyp to do linear
interpolation.

It's also initialized in entclass::entclass(), just to be sure. And I've
deduplicated the regular xp/yp initialization in createentity(), too.
2020-06-19 09:05:48 -04:00
Misa
4f4d400ce0 Add linear interpolation of rendered entities
I've added a function Graphics::lerp() which simply interpolates between
two values given a certain alpha value. It's just like drawing a
straight line between two points.

Also, Graphics now has an `alpha` attribute, and it is set on every
deltatime update to be used in linear interpolation.
2020-06-19 09:05:48 -04:00
Misa
fd44098f38 Move render functions to outer deltatime loop
Ok, and this is where the fun starts.

In an ideal world, this would be the end of this patch. However, of
course, there are many, MANY places in the game that update
fixed-timestep timers DIRECTLY inside the render function, which is not
ideal because it means those timers go super fast.

I'll have to fix those later.
2020-06-19 09:05:48 -04:00
Misa
c63036fcd3 Indent timestep loop
Ok, NOW indent it. I didn't indent it previously because the diffs are
annoying to read if there's an indent that doesn't otherwise change
anything (and even now it's pretty annoying to read).
2020-06-19 09:05:48 -04:00
Misa
e2fe2d4c2b Replace SDL_Delay() with an accumulator
Alright, this is the start of the over-30-FPS patch!

First things first, we'll need to make it possible to have a separate
deltatime loop outside of the fixed timestep loop. And for that, we
can't be using SDL_Delay(), as SDL_Delay() (as you might imagine) blocks
the whole program.

Instead we'll be using this thing called an accumulator. It looks at how
long the previous poll took (the raw deltatime), and lets timesteps pass
accordingly.

On a side note, I've had to split the `time` and `timePrev` declaration
each onto their own separate line, otherwise there's undefined behavior
from `time` not being initialized.

I use `accumulator = fmodf(...)` instead of `accumulator -=
timesteplimit` because otherwise it'll fast-forward if it's behind,
which is a jarring thing to see.

Also in preparation for what's going to come down the over-30-FPS road,
I've also added `deltatime` and `alpha`. `deltatime` is going to be used
if the game is in slowdown mode, and `alpha` is going to be used for
linear interpolation of animations.

By the way, what was the main game loop previously (and is now the new
timestep loop) is now in an extra set of curly braces, but I haven't
indented it yet to reduce the noise in this commit.
2020-06-19 09:05:48 -04:00
Misa
62441edbc9 Account for hours when calculating time trial result time
This prevents being able to "roll over" the amount of minutes to 0 (by
simply waiting for the timer to tick past one hour) and being able to
get a result of 00:13 when your result is really 01:00:13.

By looking only at the minutes, the game would read 01:00:13 as 00:13
instead. So simply add the amount of hours to the time trial result.
2020-06-18 08:42:15 -04:00
Misa
0ee5c07f4a Add #define _POSIX_SOURCE
This is needed for MinGW when compiling C++98, apparently. I put it in
an if-guard because otherwise there'll be a warning from MY compiler
about redefinitions.
2020-06-17 19:15:07 -04:00
Misa
3428d962b3 Add #define __STDC_FORMAT_MACROS
This define is needed in order for the SCNx32/SCNu32 in find_tag() to be
compiled correctly on older `glibc`s.
2020-06-17 19:15:07 -04:00
AllyTally
5e43a44d9a Add 7x7, 9x9, full horizontal and vertical brush sizes 2020-06-17 19:13:48 -04:00
AllyTally
d7dac6b9be Allow using Warp Zone gray tileset in editor
Originally written by Info Teddy
2020-06-17 17:20:43 -04:00
Misa
fc265e3c75 Fix unmounting assets exiting to menu resulting in silence
If you exited to the menu normally (i.e. got on a code path that went
through Game::quittomenu()), the menu music wouldn't play. This is
because FILESYSTEM_unmountassets() was put after music.play(6). So the
game would play the custom level's track 6, and then unmount it, which
meant it could no longer play track 6, but there's nothing telling the
game to play track 6 again. So I just changed the frame ordering around.

I also added a comment to make sure anyone reading the code is aware of
the frame order dependency.
2020-06-17 06:02:26 -04:00
Misa
44bd4ec0b7 Fix custom assets not being unmounted when exiting from editor/credits
If you exited from the editor, custom assets would not be unmounted. But
I made sure to put the FILESYSTEM_unmountassets() before the
music.play(6) because otherwise the menu music wouldn't play.

You could also exit to the menu from a custom level using the
rollcredits() command, so I made sure to put a
FILESYSTEM_unmountassets() when returning to the menu from the credits
as well. I also made sure to put it before the music.playef(18) so
there's no risk of the sound effect not playing properly, or not playing
the non-level-specific one.

I added a comment to both FILESYSTEM_unmountasset()s to make sure anyone
reading the code is aware of the frame order dependency.
2020-06-17 06:02:26 -04:00
Misa
f9dfae0144 Hardcode fix for next-line </edentity>
This is really awful, but there's not much we can do.

TinyXML-2 no matter what will never stop on newlines, so without
changing the XML parser, this is the best we can do - just remove the
"\n            " (that's a linefeed plus exactly 12 spaces) if it
appears at the end of the contents of an edentity tag.

Also a giant comment for good measure.
2020-06-16 21:44:57 -04:00
Misa
bc9f21d7f8 Revert "Fix loading levels saved with 2.2 or earlier"
This reverts commit c2c0644453.

The correct solution for this wasn't to set the whitespace mode to
COLLAPSE_WHITESPACE.
2020-06-16 21:44:57 -04:00
Misa
9a8dc4b6ff Only remove duplicate player entities in scriptclass::hardreset()
Looks like duplicate player entities persisting across rooms is a
semi-useful feature used by some levels. Still, though, it's a bit of a
nuisance to have duplicate player entities persisting across game
sessions. And levels can't rely on this persistence anyway, anyone could
just close the game and re-open it to get rid of the duplicate entities
regardless.
2020-06-15 21:30:39 -04:00
Misa
a8cedd2f91 Prevent out-of-bounds indexing with trinket/crewmate IDs
If a trinket or crewmate ID is out-of-bounds, it will not be created.
This is not only because the `collect`/`customcollect` check in
entityclass::createentity() would then be out-of-bounds, but also
touching it would also be out-of-bounds, too.

Display trinkets will always be created if the ID is out-of-bounds.
Apparently some people (@AllyTally) have been creating display trinkets
with IDs of -1 in order to get a display trinket that always shows up,
which is rather horrifying. But it makes sense, there's a lot more
nonzero int values than there are the amount of int values that are
zero, so it's fairly likely that the `collect` check will always come up
to be true (nonzero). Also, it's more useful to be able to have a
display trinket that always shows up without having to collect a trinket
beforehand, than it is to have it not be created (because technically by
default, you're already in the world where you don't have it created).

Display trinkets still have their `para` set to their ID, though, and if
they managed to gain an `onentity` of 1, bad things could happen... So
just to be sure, I added INBOUNDS checks to crewmates and trinkets in
entityclass::updateentities() so no UB will happen if you collect a
crewmate/trinket with an out-of-bounds ID. Also, I de-duplicated the
`collect`/`customcollect` setting, too.
2020-06-15 21:28:21 -04:00
Terry Cavanagh
9de61c5b76
Merge pull request #293 from InfoTeddy/general-improvements
Make elephant not be flashy if screen effects are disabled
2020-06-16 11:15:08 +10:30
leo60228
a99e976402 Support hex entities in metadata 2020-06-15 20:32:10 -04:00
Misa
529c7bae23 Make elephant not be flashy if screen effects are disabled
The flashy color of the elephant can be hard on people's eyes,
especially if they're the type who want screen effects disabled because
they might have epilepsy. The elephant takes up a good 3/4ths of the
screen, you know. If screen effects are disabled, the elephant will use
color 22, which is a neutral gray.

I'm only adding this because the VVVVVV speedrun mods (@tzann, @mohoc)
invalidate all runs that have the elephant texture removed, even though
many people would be looking at a potentially epilepsy-inducing image
many times a day grinding 100% speedruns. (Imo, their justification for
this is flimsy at best.)
2020-06-15 15:19:50 -07:00
Ethan Lee
f0ec627628 Sigh. 2020-06-15 07:37:05 -04:00
Ethan Lee
3323b7e3cf Maybe check the right size m8 2020-06-14 22:44:34 -04:00
Ethan Lee
bd71fb8a68 Disallow negative size values in BinaryBlob 2020-06-14 22:43:58 -04:00
Ethan Lee
4894639b3a valid needs to have either exactly 1 or 0 2020-06-14 22:40:57 -04:00
Ethan Lee
06a71bab18 Some sanity checks for BinaryBlob header data 2020-06-14 22:39:06 -04:00
Misa
33fd589616 Fix time trial result displaying 00:60 instead of 01:00
If your time was exactly 60 seconds, it would display 00:60 instead of
01:00.
2020-06-14 21:51:41 -04:00
Misa
b53d2ae53f Remove i/j/k attributes from classes that don't need them
The only class that actually needs its i/j/k kept is scriptclass,
because some custom levels rely on it for creating custom activity
zones. So I haven't touched that.

Other than that, there's no chance that anything important relies on
i/j/k in any other class. For that to be the case, it would have to use
i/j/k without initializing it beforehand, and that can simply be
detected by removing the attribute from the header file and seeing where
the compiler complains. And the compiler complains only about cases
where it's initialized first. (Note that due to this check, I *haven't*
removed Graphics's `m` as it precisely does exactly this, using it
without initializing it first.)

Interestingly enough, otherlevelclass and towerclass have unused i/k
variables for whatever reason.
2020-06-14 14:37:29 -04:00
Misa
1f360620cf Add inspecial() checks to savetele() and savequick()
This prevents the game from being saved if you manage to trigger a
savetele() during a "special" gamemode (like if you use the Gravitron
out-of-bounds glitch when replaying Intermission 2, then go to Game
Complete that way).
2020-06-14 07:24:28 -04:00
Misa
93a67bd357 Add Game::inspecial()
It's a function marked for inline that's just a simple shorthand,
because I don't want to type all of those conditionals out.
2020-06-14 07:24:28 -04:00
Misa
da1b58d771 Override custommode if in finalmode when drawing tilesvec
When in finalmode, custommode shouldn't take priority, as finalmode is
main game stuff.
2020-06-13 22:31:12 -04:00
Misa
2d49988f5d Fix indexing out-of-bounds with font printing functions
If you don't have a font.txt, it could happen that a font index is
requested that's out-of-bounds. And that would result in a segfault. So
to fix that I'm adding INBOUNDS checks to all functions that index the
fontmap.
2020-06-13 22:31:12 -04:00
Misa
3b0ec54164 De-duplicate flip mode code with font printing functions
Wow, all 9 functions in total have copy-pasted flip mode code! Glad I
cleaned all that up.
2020-06-13 22:31:12 -04:00
Misa
031402e4bb Fix indexing out-of-bounds with miscellaneous images
This fixes indexing out-of-bounds in the functions that draw all the
special images such as the elephant and teleporters. Let's make sure the
game doesn't segfault.
2020-06-13 22:31:12 -04:00
Misa
d03d8afedf Fix indexing out-of-bounds via tile numbers
If a graphics function was provided an out-of-bounds tile number, it
would happily segfault the game. So I'm adding checks to prevent that.
2020-06-13 22:31:12 -04:00
Misa
5195299e65 Fix indexing out-of-bounds via an entity's drawframe
I tracked down all the functions that took in an entity's drawframe and
made sure that no matter what value an entity's drawframe was, the game
would never segfault.
2020-06-13 22:31:12 -04:00
Misa
6900553f57 Add INBOUNDS macro
I mean, I probably should've done this earlier, but using this saves on
typing and improves readability.
2020-06-13 22:31:12 -04:00
Misa
a922420066 De-duplicate flipmode check in entityclass::entitycollisioncheck()
To deal with using a different image file for Flip Mode, it looks like
copy-paste was used. This isn't exactly maintainable code. So I'm
replacing it with a reference that changes depending on if the game is
in Flip Mode or not, instead.
2020-06-13 22:31:12 -04:00
Misa
4f50883d58 Prevent removing the player entity
Removing the player entity has all sorts of nasty effects, such as
softlocking the game because many inputs require there to be a player
present, such as opening the quit menu.

The most infamous glitch to remove the player entity is the Gravitron
Fling, where the game doesn't see a gravity line at a specific
y-position in the current room, and when it moves the bottom gravity
line it moves the player instead. When the gravity line gets outside the
room, it gets destroyed, so if the player gets dragged outside the room,
they get destroyed, too. (Don't misinterpret this as saying anytime the
player gets dragged outside the room, they get destroyed - it's only the
Gravitron logic that destroys them.)

Also, there are many places in the code that use entity-getting
functions that have a fallback value of 0. If it was possible to remove
the player, then it's possible for this fallback value of 0 to index
obj.entities out-of-bounds, which is not good.

To fix this, entityclass::removeentity() is now a bool that signifies if
the entity was successfully removed or not. If the entity given is the
player (meaning it first checks if it's rule 0, just so in 99% of cases
it'll short-circuit and won't do the next check, which is if
entityclass::getplayer() says the indice to be removed is the player),
then it'll refuse to remove the entity, and return false.

This is a change in behavior where callers might expect
entityclass::removeentity() to always succeed, so I changed the
removeentity_iter() macro to only decrement if removing the entity
succeeded. I also changed entityclass::updateentities() from
'removeentity(i); return true;' to 'return removeentity(i);'.
2020-06-13 15:41:44 -04:00
Misa
51d852601d Remove passing around pointer to gameScreen from KeyPoll::Poll()
Makes for cleaner code this way.
2020-06-13 14:50:33 -04:00
Misa
30bcc08bec Move gameScreen off of the stack and onto the heap
Just so it can be properly used globally like all the other classes.
2020-06-13 14:50:33 -04:00
Misa
60a2e100fc Fix 'if (key.resetWindow)' indentation
It was being indented with tabs instead of spaces.
2020-06-13 14:50:33 -04:00
Ethan Lee
a15d01ad80 Fix fullscreen focus behavior 2020-06-13 10:35:05 -04:00
Ethan Lee
506628cef1 Revert "Fix unfocusing the game while in fullscreen mode"
This reverts commit c322ae131e.
2020-06-13 10:23:52 -04:00
Misa
884035fd2e Add unsigned char static_cast to argument of std::isdigit()
Apparently it results in Undefined Behavior if the argument given isn't
representable as an unsigned char. This means that (potentially) plain
char and signed chars could be unsafe to use as well.

It's rare that this could happen in practice, though. std::isdigit() is
only used by is_positive_num() which is only used by find_tag(), so
someone would have to deliberately put something crazy after an `&#` in
a custom level file in order for this to happen. Still, better to be
safe than sorry and all.
2020-06-13 01:25:17 -04:00
Misa
fdb44cc209 Add <cctype> include
This fixes a compile error that could happen where the compiler doesn't
know what std::isdigit() is, but I'm puzzled as to why this wasn't
happening earlier, 'cause I've only been reported that it happens by
only one person.
2020-06-13 01:25:17 -04:00
Misa
14afae1a40 Add bounds checks to script commands that didn't have them
Continuing from #280, another potential source of out-of-bounds indexing
(and thus, Undefined Behavior badness) comes from script commands. A
majority of them don't do any input validation at all, which means the
potential for out-of-bounds indexing and segfaulting in custom levels.
So it's always good to add bounds checks to them.

Interesting note, the only existing command that has bounds checks is
the flag() command. That means you can't turn out-of-bounds flags on or
off. But there's no bounds checks for ifflag(), or customifflag(), which
means you CAN index out-of-bounds with those commands! That's a bit bad
to do, so.

Also, I decided to add the bounds checks for playef() at the
musicclass::playef() level, instead of just the level of the playef()
command. I don't know of any other cases outside of the command where
musicclass::playef() will index out of bounds, but musicclass is the one
containing the indexed vector anyway, I wanted to cover more cases, and
it's better to be safe than sorry.
2020-06-13 01:24:42 -04:00
Misa
fdce412680 Guard all cases obj.getcompanion() is used unchecked
And this the function with the least amount of cases where its sentinel
value is used unchecked. Thankfully. obj.getplayer() was a bit of a slug
to get through.
2020-06-12 23:55:48 -04:00
Misa
beab344267 Guard all cases obj.getplayer() is used unchecked
obj.getplayer() can return -1, which can cause out-of-bounds indexing of
obj.entities, which is really bad. This was by far the most changes, as
obj.getplayer() is the most used entity-getting function that returns
-1, as well as the most-used function whose sentinel value goes
unchecked.

To deal with the usage of obj.getplayer() in mapclass::warpto(), I just
added general bounds checks inside that function instead of changing all
the callers.
2020-06-12 23:55:48 -04:00
Misa
08e47e839f Guard all cases obj.getteleporter() is used unchecked
obj.getteleporter() is able to return -1. If there's no check on it, it
will end up indexing out-of-bounds, which is Undefined Behavior.
2020-06-12 23:55:48 -04:00
AllyTally
3b76713441 Only add editor ghosts if the editor exists 2020-06-12 19:11:48 -04:00
AllyTally
5c80a4c25e Remove another header initialization 2020-06-12 19:11:48 -04:00
AllyTally
d740205138 Don't initialize game.gametimer in the header file
That's a C++ thing apparently.
2020-06-12 19:11:48 -04:00
AllyTally
805992a1e1 Fix mixed indentation
The editors I use replace tabs with spaces, so I never really thought about mixed indentation happening. Whoops.
2020-06-12 19:11:48 -04:00
AllyTally
1b0b1d32e8 Remove accidental whitespace
Whoops, must have accidentally pressed tab
2020-06-12 19:11:48 -04:00
AllyTally
eb52657c23 Add a player trail to the editor (ghosts)
A few months ago, I added ghosts to the VVVVVV: Community Edition editor. I was told recently I should think
about upstreaming it, and with Terry saying go ahead I finally ported them into VVVVVV. There's one slight
difference however--you can choose whether you have them or not in the editor's settings menu. They're off by
default, and this is saved to the save file.
Anyway, when you're playtesting, the game saves the players position, color, room coordinates and sprite every 3
frames. The max is 100, where if it tries to add more, the oldest one gets removed.
When you exit playtesting, the saved positions appear one at a time, and you can use the Z key to speed it up.

[Here's a video of them in action.](https://o.lol-sa.me/4H21zCv.mp4)
2020-06-12 19:11:48 -04:00
Ethan Lee
b2f842376b Avoid calling music.init on startup, reloadresources does this 2020-06-12 16:24:21 -04:00
Ethan Lee
8d652dc256 Like the thing I did but the opposite 2020-06-12 16:21:45 -04:00
Ethan Lee
f815b1ee62 Replace mkdir with PHYSFS_mkdir 2020-06-12 16:20:18 -04:00
Misa
c2c0644453 Fix loading levels saved with 2.2 or earlier
2.2 and earlier had this god-awful thing where it put the closing tag of
an edentity onto the next line, and then kept the indentation the same.
This requires parsing the XML in an extremely specific way (i.e.
ignoring the whitespace) so the newline and indentation isn't taken as
part of the actual contents of the tag.

2.3 removed this awful whitespace entirely to make it easier on parsers.
When I tested #270, I tested against a 2.3 re-save of Dimension Open and
diffed the two, because I thought testing against the original version
of the level would result in a bunch of noise I didn't want due to the
whitespace change. Well, I did exactly what I intended, and ended up
ignoring the whitespace change so much that levels saved in this stupid
format ended up getting broken.

Luckily, we can just tell TinyXML-2 to parse a document exactly like how
TinyXML-1 would've parsed it, by supplying the COLLAPSE_WHITESPACE enum
to it (by default it's on PRESERVE_WHITESPACE).
2020-06-12 16:01:26 -04:00
Misa
3f4df82583 Remove TinyXML-1
This removes the TinyXML source files, removes it from CMakeLists.txt,
removes all the includes, and removes the functions
FILESYSTEM_saveTiXmlDocument() and FILESYSTEM_loadTiXmlDocument() (use
FILESYSTEM_saveTiXml2Document() and FILESYSTEM_loadTiXml2Document()
instead).

Additionally I've cleaned up the tinyxml2.h include in FileSystemUtils.h
so that it doesn't actually include tinyxml2.h unnecessarily, meaning a
change to TinyXML2 shouldn't rebuild all files that include
FileSystemUtils.h.
2020-06-12 15:08:29 -04:00
Misa
c397c898fc Convert Game::loadcustomlevelstats() to TinyXML2 2020-06-12 15:08:29 -04:00
Misa
683dc1f97d Convert Game::savecustomlevelstats() to TinyXML2 2020-06-12 15:08:29 -04:00
Misa
142241fd74 Convert Game::Game() to TinyXML2 2020-06-12 15:08:29 -04:00
Misa
45e864315e Convert Game::loadsummary() to TinyXML2 2020-06-12 15:08:29 -04:00
Misa
89a8623a46 Convert editorclass::save() to TinyXML2
I tested this one, too. But it seems to be fine as well.
2020-06-12 15:08:29 -04:00
Misa
cfacc7a2dc Convert editorclass::load() to TinyXML2
Ok, it's a bit of a more complicated structure, but it seems to load
fine. I decided to test this one.
2020-06-12 15:08:29 -04:00
Misa
2f2f04c76b Convert custom quicksave loading attempt to TinyXML2
Seems a bit wasteful to do the whole "parse the XML document thing"
instead of a simple file check. It doesn't even fail if the XML document
is invalid, but whatever.
2020-06-12 15:08:29 -04:00
Misa
677dd424ec Convert Game::customsavequick() to TinyXML2
At this point I stopped actually doing a quick test, and just went off
of "if it compiles, it works".
2020-06-12 15:08:29 -04:00
Misa
c03fdc6c01 Convert Game::customloadquick() to TinyXML2
Ok, who's even reading these commit messages at this point?
2020-06-12 15:08:29 -04:00
Misa
c62bfad19d Convert Game::savequick() to TinyXML2
Same steps as converting all other XML-saving functions.
2020-06-12 15:08:29 -04:00
Misa
3419f9fa15 Convert Game::loadquick() to TinyXML2
Same changes as all other XML-loading functions.
2020-06-12 15:08:29 -04:00
Misa
6706197741 Convert Game::savetele() to TinyXML2
I just had to find-and-replace all `new TiXmlDocument` to
`doc.NewDocument` and `new TiXmlText` to `doc.NewText`, along some other
stuff.
2020-06-12 15:08:29 -04:00
Misa
9348bf5b24 Convert Game::loadtele() to TinyXML2
Again, the only thing that needs to be changed is just the code at the
top of the function.
2020-06-12 15:08:29 -04:00
Misa
6274707777 Convert Game::savestats() to TinyXML2
Ok, so it was a bit of a struggle at first figuring out the new API, but
honestly it wasn't so bad in the end.

I made a copy of my old unlock.vvv before testing this, and checking
with `diff` the only difference is the new `encoding="UTF-8"` in the XML
declaration, which isn't a bad thing.
2020-06-12 15:08:29 -04:00
Misa
f2709731e2 Convert Game::loadstats() to TinyXML2
Surprisingly, I only had to change some names and stuff around at the
top of the function. The rest of the function could be left untouched
and it worked fine.
2020-06-12 15:08:29 -04:00
Misa
b17e96df7d Add FILESYSTEM_loadTiXml2Document()
Same as FILESYSTEM_saveTiXml2Document(), except for loading. Read this
as "load TinyXML2 Document", not "load TinyXML to Document".
2020-06-12 15:08:29 -04:00
Misa
45ad048756 Add FILESYSTEM_saveTiXml2Document()
This will eventually replace FILESYSTEM_saveTiXmlDocument(). Read it as
"save TinyXML2 Document", not "save TinyXML to Document".
2020-06-12 15:08:29 -04:00
Misa
b67ac8a43b Add TinyXML2
This adds the TinyXML2 files, as well as updates them in CMakeLists.txt
so it will be compiled in, too. Temporarily, the old TinyXML is kept for
now.
2020-06-12 15:08:29 -04:00
Misa
628eb7b7bf Fix mixed indentation in editor.h
Some of the file was indented with two spaces and the rest indented with
tabs. It feels like two different people worked on the file, one more
than the other. Since most of it uses two spaces, I'll just replace the
tabs with two spaces.
2020-06-11 22:13:52 -04:00
Misa
e7b39757a4 Remove a trailing whitespace from Graphics.h
Don't know why this was here, or how.
2020-06-11 22:13:52 -04:00
Misa
55b2a3aac2 Indent Graphics::reloadresources() with tabs
This is to respect the fact that the top half of the file is indented
with spaces, while the bottom half is indented with tabs.
Graphics::reloadresources() is on the bottom half.
2020-06-11 22:13:52 -04:00
Misa
2967e308ae Remove include guards from Scripts.cpp and TerminalScripts.cpp
These files are never included, so why do they have include guards?
2020-06-11 22:13:52 -04:00
Misa
eb5fb3dff5 Refactor customstring calculation in scriptclass::load()
The previous way manually concatenated the first 7 characters of the
string together (and had an std::min() calculation). The new way instead
does std::string::substr(), which is much more snappy.
2020-06-11 22:13:52 -04:00
Misa
7150c9ef2d Unindent scriptclass::loadcustom() from previous commit
The actual unindent is done in a separate commit to minimize noise,
because diffs are terrible at clearly conveying unindents (it should put
all the minus lines together and all the plus lines together, too).
2020-06-11 22:13:52 -04:00
Misa
6e0119d753 Invert contents check in scriptclass::loadcustom()
The entirety of the rest of scriptclass::loadcustom() is encased in a
block that first checks if the script with the name even exists. Instead
of indenting the rest of the function, just invert the check and reduce
indentation level.
2020-06-11 22:13:52 -04:00
Misa
8edf2f0ac6 Refactor custom scripts to not be stored in one giant vector of lines
This commit refactors custom level scripts to no longer be stored in one
giant vector containing not only every single script name, but every
single script's contents as well. More specifically,
scriptclass::customscript has been converted to an std::vector<Script>
scriptclass::customscripts (note the extra S), and a Script is just a
struct with an std::string name and std::vector<std::string> contents.

This is an improvement in both performance and maintainability. The game
no longer has to look through script contents in case they're actually
script names, and then manually extract the script contents from there.
Instead, all it has to do is look for script names only. And the
contents are provided for free. This results in a performance gain.

Also, the old system resulted in lots of boilerplate everywhere anytime
scripts had to be handled or parsed. Now, the boilerplate is only done
when saving or loading a custom level. This makes code quality much,
much better.

To be sure I didn't actually change anything, I tested by first saving
Dimension Open in current 2.3 (because current 2.3 gets rid of the
awful edentity whitespace), and then resaved it on this patch. There is
absolutely no difference between the current-2.3-resave and
this-patch-resave.
2020-06-11 22:13:52 -04:00
leo60228
dd5c50c94c Fix some leaks 2020-06-07 22:40:03 -04:00
leo60228
887c1fbf96 Don't leak flipbfont 2020-06-07 22:40:03 -04:00
leo60228
abbf6bafb9 Don't leak sounds/music 2020-06-07 22:40:03 -04:00
leo60228
f3b26904ec Don't leak binaryBlob 2020-06-07 22:40:03 -04:00
leo60228
9b91047bba Find SDL_mixer.h instead of assuming it's in the same location as SDL.h 2020-06-07 22:40:03 -04:00
leo60228
8f06915c60 Unstub ~GraphicsResources 2020-06-07 22:40:03 -04:00
leo60228
d193caac98 Revert "Add destructor for SoundTrack/MusicTrack (and explicitly define move constructor to prevent double-free)"
This reverts commit 2f760af439.
2020-06-07 22:40:03 -04:00
leo60228
098fb77611 Set C++ standard to C++98 2020-06-07 22:40:03 -04:00
Misa
d22d08af87 Add C++98/C++03 standards declaration to CMakeFiles.txt
This enforces the C++03 standard for people making pull requests who may
not realize their fancy features are too new and shouldn't be used
(cough, cough, @leo60228).

I did some internet searching and this is what I got from this page:
https://crascit.com/2015/03/28/enabling-cxx11-in-cmake/
2020-06-07 22:39:44 -04:00
leo60228
e71f47f1c9 Clear soundTracks and musicTracks on musicclass::init 2020-06-07 00:04:42 -04:00
leo60228
2f760af439 Add destructor for SoundTrack/MusicTrack (and explicitly define move constructor to prevent double-free) 2020-06-07 00:04:42 -04:00
Misa
c561cd9740 Fix custom assets being unmounted in scriptclass::hardreset()
This resulted in two bugs:
 1. Custom assets would not be unmounted when quitting to the menu.
 2. Custom assets would be unmounted when playtesting a level.

The solution is to unmount assets in Game::quittomenu() instead.
2020-06-03 21:44:56 -04:00
Fussmatte
b7a2cc1c22 Removed another stray line 2020-06-03 15:35:39 -04:00
Fussmatte
e67d6d49c3 Fixed a few vector initialisation errors 2020-06-03 15:35:39 -04:00
Fussmatte
aaa25c7b47 Fixed some custom asset bugs, added .zip level loading
Main game would retain custom level assets, now fixed. Also, custom fonts load properly. Finally, levels can be stored as a zip and placed in the levels folder, with the .vvvvvv file at the root of the zip and custom asset folders (graphics, sounds etc) also at the root.
2020-06-03 15:35:39 -04:00
Dav999-v
3bb4eefaff Fix editor unexpectedly quitting after failed save-and-quit
Also simplified away the success variable.
2020-06-02 09:46:42 -04:00
Dav999-v
ae45391ec0 Add editor saving/loading error messages
Previously, the editor would always say it saved or loaded a level,
even if it was not successful. For example, because a file to load does
not exist, a file to save has illegal characters in its name or the
name is too long to be stored. Now failure is reported. Also, when
quitting the editor and saving before quitting is unsuccessful, the
editor will abort quitting.
2020-06-02 09:46:42 -04:00
Misa
2ef6a056aa Allow for conditional building of Steam and GOG APIs
I think it's a bit silly to always include the Steam and GOG APIs
whenever we build VVVVVV, since the only time they'll ever be used is in
a live build and not a dev build.

So now Steam and GOG are disabled by default. If you want them, you'll
need to add -DSTEAM=ON or -DGOG=ON respectively at CMake time. They're
also both automatically enabled for release builds.
2020-06-01 14:21:06 -04:00
Fussmatte
58df371c3e Changed my name from Stelpjo to my current name, Fußmatte
I also left a note for the in-game credits list to change the "ss" to an eszett when the Unicode font is implemented.
2020-05-31 20:38:06 -04:00
Ethan Lee
43f1204407 Whitespace consistency for FileSystemUtils 2020-05-31 19:43:24 -04:00
Ethan Lee
21b6c22195 Minor visual cleanup of reloadresources 2020-05-31 19:43:24 -04:00
Ethan Lee
f422d02dcd Minor visual cleanup of endsWith 2020-05-31 19:43:21 -04:00
Matt Aaldenberg
b217fec3aa
Per-level custom asset loading functionality (#262) 2020-05-31 19:31:02 -04:00
Misa
cfcfccf58b Fix segfault if say/reply/text asks for more lines than there are
This commit adds bounds checks to those commands in case say()/reply()
asks for more lines than there are left in the all-script-lines buffer
(not just the current script, so in order for it to segfault your script
has to be last in the all-script-lines vector), and in case text() asks
for more lines than there are in the rest of the rest of the parsed
internal script.
2020-05-31 18:29:16 -04:00
Misa
ff6cc1a777 De-duplicate say/reply line adding code
I found it patently ridiculous that `i++; add(customscript[i]);` was
copy-pasted four separate times. Well, at least it's only copy-pasted
twice now.
2020-05-31 18:29:16 -04:00
Misa
79d55baf6d Remove unnecessary references to global self in loadcustom()
For some reason, scriptclass::loadcustom() sometimes refers to
`customscript` as `script.customscript` instead of `customscript`. The
`script.` is unnecessary.
2020-05-31 18:29:16 -04:00
Matt Penny
50798d5add Fix build with CUSTOM_LEVEL_SUPPORT=disabled 2020-05-30 16:33:17 -04:00
Misa
67a6ab3704 Statically allocate Prize for the Reckless tilemap
Looks like this was either forgotten about, or sufficiently scary enough
to not put a `static` on. But I think it's fine if we put a `static` on
it.
2020-05-29 19:39:05 -04:00
Misa
726a79c568 Statically allocate built-in scripts as well
Although it's not an issue, this should minimize the stack footprint of
calling scriptclass::load(), especially if it goes down to calling
scriptclass::loadcustom() or scriptclass::loadother().
2020-05-29 12:48:36 -04:00
Matt Penny
d27ffa51b6 Statically allocate level arrays
This prevents a potential stack overflow if the compiler tries to
allocate all of the arrays at once (observed on MSVC).
2020-05-29 10:21:25 -04:00
Misa
a623190b09 Fix using speak/speak_active without a text beforehand
Otherwise, it would end up indexing a vector out-of-bounds, which is UB
and causes a segfault, too. This is used in some constructs like

    say(-1)
    <internal command>

where the text contents don't matter, only that a text box shows up.
2020-05-23 16:04:04 -04:00
Misa
46559bbe0a De-duplicate speak_active/speak code
The `speak` command is the exact same as the `speak_active` command,
except without one line of code. So instead of copy-pasting the entire
thing, it's better to just combine them into the same chunk of code.
2020-05-23 16:04:04 -04:00
Misa
e9ffa1863f Refactor TerminalScripts.cpp to not store strings in function parameters
Like the previous commit, except for TerminalScripts.cpp.
2020-05-22 09:46:12 -04:00
Misa
815a48c025 Refactor Scripts.cpp to no longer hold strings in function args
Instead each line is now held in a const char* array, like it should be.
This results in less work for the compiler, especially with
optimization, since every time the compiler encounters a constant
argument in a function, it has to go off and locate a place to put it.
But if we're upfront and say, hey, here's all the strings we ever need
conveniently packaged into one place, it'll be much more cooperative.
2020-05-22 09:46:12 -04:00
Misa
9205421090 Clean up editorclass externs into one location
Again, like the previous commit, it should just be put in the header
file of its respective class instead of being a mess everywhere.
2020-05-22 09:46:12 -04:00