Commit Graph
100 Commits
Author SHA1 Message Date
Misa b667e44bcf Don't use map.extrarow for menu animations
This fixes all the headaches about map.extrarow having to be the correct
value and which way it should be and whatnot. The latest headache was
the detection that prevent user-initiated menu animations while an
animation was already happening being tripped because
graphics.menuoffset would be 230 (due to closing the menu while being in
a room without a room name), but then going to a room with a room name
would check for 240 instead, and 230 is less than 240. (The numbers are
the wrong way round because I got the ternaries the wrong way round, but
even if the numbers are the correct way round, the bug would still
happen, but it would just be reversed.)

So instead, I've just made it 240 for both. This doesn't change the
duration of the menu animation (because the animation moves in
increments of 25, and 230 / 25 == 240 / 25 under integer division). It
might change the animation slightly, but it was already inconsistent
anyway because map.extrarow was always set to be 1 in custom levels, and
I legitimately would not be able to tell the difference without
recording the animations and nitpicking it frame-by-frame.

Fixes #841.
2021-09-03 17:18:17 -07:00
Misa 70d3c999be Only reset fade booleans when music is actually played
Otherwise, the block that fades existing music out if m_doFadeOutVol is
true will never execute, because m_doFadeOutVol would always be false!
2021-09-03 16:44:19 -07:00
Misa a302692ab2 Add message when player is kicked out of Super Gravitron
The player gets kicked out of the Super Gravitron if they have
invincibility or slowdown enabled. However, this can be confusing if no
message pops up
( https://steamcommunity.com/app/70300/discussions/0/3039355280230178910/ )
. So I've made it so that a text box will pop up when they get kicked
out.
2021-09-03 12:09:53 -07:00
Misa a59e9d51db gamemode(teleporter): Set gamestate to GAMEMODE
This makes it so gamemode(teleporter) will always do an animation, even
if the game is already in TELEPORTERMODE.

I used this script to test:

    gamemode(teleporter)
    delay(5)
    gamemode(teleporter)
    delay(5)
    gamemode(teleporter)

In 2.2, this script starts the map menu bringing-up animation three
times.

In previous 2.3, this script starts the map menu bringing-up animation
once, but then the next gamemode(teleporter) immediately finishes the
animation, and the third gamemode(teleporter) does nothing.

This commit restores it to 2.2 behavior.
2021-09-02 12:29:55 -07:00
Misa 82971296c2 Prevent user-initiated map menu changes during menu animations
This makes it so it's not even possible to stay on the TELEPORTERMODE
screen by opening the map while it's being brought down. It also makes
it so the map animation is able to be canceled when being brought up
just by opening the map and closing it.

Fixes #833.
2021-09-02 12:29:55 -07:00
Misa 4ecec8a327 Call teleporterrenderfixed in TELEPORTERMODE
This restores it to 2.2 behavior, where the cutscene bars timer also
ticked in TELEPORTERMODE. It was a 2.3 regression that the cutscene bars
timer didn't tick there.

This makes it so if you manage to get stuck in TELEPORTERMODE when a
cutscene ends, the cutscene won't be stuck on untilbars() waiting for
the cutscene bars to go away, since the cutscene bars timer now ticks.
2021-09-02 12:29:55 -07:00
Misa 9cfbd1ae51 Fix not-Flip-Mode flag turning off when returning from options menu
We need to check for graphics.setflipmode, not graphics.flipmode,
because graphics.flipmode only gets assigned at the end of the frame
(due to the deferred callback). Otherwise, returning from the options
menu would always turn flag 73 on, which would make you ineligible to
get the Flip Mode trophy, even if you're in Flip Mode.
2021-08-31 15:34:32 -07:00
Misa 48cddf57a6 Reset obj.customscript in hardreset()
This prevents yet another place where stale level data from one level
could have affected another level...
2021-08-31 07:55:40 -07:00
Misa fea2010204 Fix enemy/plat bounds not being drawn if any side touches a screen edge
Enemy/platform bounds are intended to not be drawn if they cover the
whole screen, since that's what their default bounds are.

However, the code inadvertently made it so if ANY of the bounds touched
a screen edge, the bounds wouldn't be drawn. This is because the
conditionals used "and"s instead of "or"s. The proper way to write the
positive conditional is "x1 is 0 and y1 is 0 and x2 is 320 and y2 is
240", and when you invert that conditional, you need to also invert all
"and"s to be "or"s. This is not the first time that the game developers
failed to properly negate conjunctional statements...
2021-08-28 13:03:04 -07:00
Misa fd4415317d Replace Gravitron RNG with seeded Xoshiro
This is to make it so RNG is deterministic when played back with the
same inputs in a libTAS movie even if screen effects or backgrounds are
disabled.

That way, Gravitron RNG is on its own system (seeded in hardreset()),
separate from the constant fRandom() calls that go to visual systems and
don't do anything of actual consequence.

The seed is based off of SDL_GetTicks(), so RTA runners don't get the
same Gravitron RNG every time. This also paves the way for a future
in-built input-based recording system, which now only has to save the
seed for a given recording in order for it to play back
deterministically.
2021-08-27 12:28:35 -07:00
Misa 69e36229ec Add -A Win32 flag to README
This avoids failure modes made possible by mismatching 32-bit and 64-bit
settings.
2021-08-26 13:29:05 -07:00
Misa c591b79daf Reset words array in hardreset()
Otherwise, levels could leave stale arguments in the array, and then the
behavior of another level loaded right after might end up being
different because of that.
2021-08-25 11:12:23 -07:00
Misa 580096dded Update comments about contributor ordering
I reordered them but forgot to update these comments...
2021-08-24 09:42:23 -07:00
Misa d472363542 Fix positioning of "Thanks for playing!"
When the screen reached the bottom of the credits, it ended up being 10
pixels higher (and not perfectly centered) than in 2.2 and previous.
2021-08-24 09:39:20 -07:00
Misa 676294332f Add Vee to credits
He did say to feel free to not credit him, but I'd like to add him
anyways just for completeness's sake.
2021-08-24 09:39:19 -07:00
Misa e69fd80bac Add KyoZM to Credits.h
They were in CONTRIBUTORS.txt but not Credits.h.

In the future we ought to just parse CONTRIBUTORS.txt directly somehow,
but This Works Okay for now.
2021-08-24 09:38:36 -07:00
Misa b9c028fd9b Alphabetically sort contributors by first name, not last
This is done for consistency with Terry's patrons, which are sorted by
first name and not last.

Also some people go with their usernames and so don't have a last name
to speak of, which ended up being pretty weird.
2021-08-24 09:37:36 -07:00
Misa 89d1873a5a Add Elijah Stone's GitHub handle to CONTRIBUTORS.txt
They were the odd one out out of everyone else.
2021-08-24 09:31:59 -07:00
Misa da6871f6f4 Fix missing at-symbols on people in CONTRIBUTORS.txt
For consistency.
2021-08-24 09:14:42 -07:00
Misa 9bdd45b7e1 Update Misa's name in credits
Kai is my last name. Elizabeth is my middle name. I went with my middle
name as last name for a while before figuring out what I wanted my last
name to be.
2021-08-24 09:13:07 -07:00
Misa 950b9523ce Add Visual Studio string list
If people compile with VS 2019, then putting in VS 2010 will just result
in a weird error that's not really indicative of anything.
2021-08-24 09:11:02 -07:00
Misa 4e910c2182 Update license exceptions last updated date
Terry updated it last on November 22nd but forgot to update the 'last
updated' date...
2021-08-24 09:10:23 -07:00
Misa 749a885d9a Actually finally fix createentity default args
Third time's the charm.

The fundamental problem with the previous attempts was that they ended
up saying arguments existed due to stale `words` anyway. So to actually
know if an argument exists or not, we need to assign to `argexists` _as_
we parse the line.

And make sure to take care of that last argument too.

Also I thoroughly tested this this time around. I'm done pulling my hair
out over this.
2021-08-22 22:47:47 -07:00
Misa 01ae5c6c70 Allow custom levels to use 2 billion tile numbers once again
Ever since tilesheets got expanded, custom levels could use as many
tiles as they wanted, as long as it fit under the 32-bit signed integer
limit.

Until 6c85fae339 happened and they were
reduced to 32,767 tiles.

So I'm being generous again and changing the type of the contents array
(in mapclass and editorclass) back to int. This won't affect the
existing tilemaps of the main game, they'll still stay short arrays. But
it means level makers can use 2 billion tiles once again.
2021-08-22 21:30:53 -07:00
Misa 92aace50f6 Don't assume tilesheet size in Direct Mode
This lets users place down tiles above 1199 in Direct Mode, if their
tilesheet has more than 1200 tiles.

I don't like the copy-pasted code here but it'll have to make do.
2021-08-22 21:13:28 -07:00
Misa 731fb89c90 Add being able to use Lab rainbow background in editor
If you use Lab tilecol 6, you get the rainbow background. However, this
is unintended, because the associated autotiling is... not very good.

To combat that, Ved disallows using the Lab rainbow background outside
of Direct Mode. We will follow Ved here and only allow switching to the
rainbow background if you're in Direct Mode. Also make sure if someone
is disabling Direct Mode with the rainbow background that it gets reset
properly.
2021-08-22 20:56:47 -07:00
Misa 3947949ebb Add being able to use Shift+W to change warp dir backwards
A minor convenience, but a convenience is a convenience.
2021-08-22 20:51:51 -07:00
Misa d2153aee87 Refactor warp dir switching to separate function
This is so the same code can be used to go in reverse instead of
copy-pasting it.
2021-08-22 20:51:21 -07:00
Misa 0489293885 Remove default arguments from ed switch_* funcs
I don't like default arguments and if we're going to be moving to C
we'll need to remove them anyway.
2021-08-22 20:44:18 -07:00
Misa 52918ba510 Increment total flips for flip tokens and flipgravity(player)
They flip the player, they should count towards total flips like gravity
lines do.
2021-08-22 20:39:05 -07:00
Misa 8329afc6df Replace main game music with music area map
The main game used a set of copy-pasted code to set the music of each
area. There WAS some redundancy built-in, but only three rooms in each
direction from the entrance of a zone.

Given this, it's completely possible for players to mismatch the music
of the area and level. In fact, it's easy to do it even on accident,
especially since 2.3 now lets you quicksave and quit during cutscenes.
Just play a cutscene that has Pause music, then quicksave, quit, and
reload. Also some other accidental ways that I've forgotten about.

To fix this, I've done what mapclass has and made an areamap. Except for
music. This map is the map of the track number of every single room,
except for three special cases: -1 for do nothing and don't change music
(usually because multiple different tracks can be played in this room),
-2 for Tower music (needs to be track 2 or 9 depending on Flip Mode),
and -3 for the start of Space Station 2 (track 1 in time trials, track 4
otherwise).

I've thoroughly tested this areamap by playing through the game and
entering every single room. Additionally I've also thoroughly tested all
special cases (entering the Ship through the teleporter or main
entrance, using the Ship's jukebox, the Tower in Flip Mode and regular
mode, and the start of Space Station 2 in time trial and in regular
mode).

Closes #449.
2021-08-22 20:35:06 -07:00
Misa 5bb12a7fc1 Set Secret Lab/Super Gravitron hidden names
It seems appropriate that these rooms should have their names shown on
the map screen.
2021-08-22 20:33:03 -07:00
Misa 2af04ad0fa Make fade out duration proportional to volume
This is the same behavior as SDL_mixer. Else, a fadeout would last the
same amount of time no matter the volume, which is a regression.
2021-08-22 16:57:13 -07:00
Misa ad88939dbb Fix regression with niceplay() moving back and forth between zones
2.3 has a regression where if you move back and forth between a zone,
you can get the wrong music playing in a zone. An example is the
Overworld and Lab. Just walk in to the Lab and immediately walk back
out, and you'll get Potential for Anything playing in the Overworld.

This regression was caused by facb079b35.
That commit removed assigning -1 to currentsong when a fadeout was
called.

Basically, the previous behavior was: currentsong is 4, we enter Lab and
nicechange gets queued to 3 but currentsong gets set to -1, then going
back nicechange gets queued to 4 again.

However, if we don't assign -1, then going back will keep nicechange at
3. Why? Because niceplay() checks for currentsong before assigning
nicechange. If currentsong is still the same then it doesn't assign
nicechange.

To fix this, just always unconditionally assign nicechange.
2021-08-22 16:57:11 -07:00
Misa 1c3274645d Fix up style in musicclass::play()
- Multiline comment instead of single-line.
- Spacing fixes.
- Long line broken up into smaller ones.
2021-08-22 15:27:39 -07:00
Misa 4f881b9e26 Fix enemy movement types 10/12 causing memory leaks
If spawned as a custom enemy (createentity entry 56), or spawned outside
of the rooms they spawn in in the main game, they will repeatedly clone
themselves every frame, which profusely leaks memory. In fact it quickly
causes a crash in 2.2 and previous, but 2.3 fixes that crash, so it just
keeps spawning enemies endlessly, which eventually lags the game, and
eventually can out-of-memory your system (bad!).

The problem is those movement types rely on entclass::setenemyroom() to
change their `behave` to be 11 or 13. Else, the new entity created will
still have `behave` 10 or 12, which will create ANOTHER entity in the
same way, and so on, and so forth.

So to fix this, just make it so if an enemy is still `behave` 10 or 12
by the end, then, just set it to -1. That way it'll stay still and won't
cause any harm.

I considered setting the `behave` to 11 or 13 respectively, but, that's
probably going farther than just fixing a memory leak, and anyways, it's
not that much useful for me as a custom level maker, and the entities
spawned aren't really controllable.
2021-08-19 16:50:44 -07:00
Misa 7c18123327 Wrap level dir enumerate callback pointer in struct
In order to let callers provide their OWN callback functions through the
callback function WE provide to PhysFS, we casted the function pointer
to a void pointer.

Unfortunately, this is apparently undefined behavior... if your compiler
doesn't have an extension for it. And most compilers on most
architectures do. (In fact compilers on POSIX systems most certainly
have it due to dlsym() returning a void* which could actually be a
pointer to a function sometimes.)

But imo, it's better to be safe than sorry in this regard. Especially
when given GCC's approach to optimizing int + 100 > int (spoilers: they
remove it entirely! It's faster, but also broken!).

I've decided to wrap it in a struct. And as a nice side effect, if we
ever need more data to be passed through... well we already have this
struct.

Technically, it's also standards-compliant to cast a _pointer to_ a
function pointer to a void pointer. But that extra layer of pointer
indirection would get real confusing to conceptualize real fast (or at
least is more confusing than just putting it in a struct).
2021-08-19 00:48:05 -07:00
Misa 8bade56841 Fix regression with regaining focus resuming music
Since you've been able to resume music stopped by stopmusic() with
resumemusic(), if a track was stopped by stopmusic(), the unfocus pause
itself would end up resuming the track when regaining focus.

The solution is to simply check for if music.currentsong is -1 or not.
2021-08-18 20:50:02 -07:00
Misa 208382a8d1 Fix regression with platv values not parsed as 2.2-and-prev
So, platv is a room property that controls the speed of custom entity
platforms in the room (unless, of course, they're created with
createentity). Problem is, this is how 2.2-and-previous coding standards
were:

    ed.level[game.roomx-100+((game.roomy-100)*ed.maxwidth)]

Overly long, verbose, not entirely clear unless you already know what it
means? Copy-pasted over and over due to all of the above? Surely a
recipe for not making any coding errors!

Ironically enough, copy-pasting is basically the best approach here
(short of refactoring the whole thing, like I did in
945d5f244a), since if you don't ACTUALLY
copy-paste and just re-type it on your own, you'll end up making more
mistakes. Like what happened here:

    ed.level[game.roomx-100+((game.roomy-100)*ed.mapwidth)].platv

Do you see the mistake...? Yeah, mapwidth (with a P) instead of maxwidth
(with an X). You'd have to look closely to find it.

So what does this mean for platv? Well, it means that it multiples the
y-coordinate of the room by the map width instead of the max width (20),
like every other room property. So that means if your map width is less
than 20, like say, map width 10, the platv value for (2,2) will be
stored in (2,1)'s room properties instead of (2,2)'s. Because if you go
off of map width, the room index for (2,2) is 2 + 2 * 10 = 22, but if
you go off of max width, the room index for (2,1) is 2 + 1 * 20 = 22.

Now this wouldn't be bad, except for another 2.2-and-previous
standard... kind of just not exposing things directly to the end user.
Whether that's simply not documenting something (as in the case of
ifwarp and warpdir, which by all measures were completely intended to be
used in custom levels but just simply were never known properly until I
discovered how to use them in 2019), or in this case, not giving any way
for the user to fiddle with platv from the in-game editor. Because if
there was a way to do that, and someone decided to test to see if platv
worked okay, they would discover something was up.

So... since I refactored room properties in
945d5f244a, I kind of broke platv by
fixing it. Now levels that relied on platv being the broken way don't
work.

How do I fix it, and thus break it again? Well, I'll do what I did for
scripts - handle the scrambling when reading and writing the level, and
keep things sane at least internally.

Thus: editorclass::load() will unscramble platv data in the right way,
and editorclass::save() will re-scramble platv in the right way too.
2021-08-18 19:19:33 -07:00
Misa a13d26d866 Add option to delete all custom level save data
To match the option to nuke all main game save data, there is also now
an option to nuke all custom level save data separately (which is just
all custom level quicksaves, along with stars for level completion). It
has its own confirmation menu too. It does not delete any levels from
the levels folder.
2021-08-18 16:02:11 -07:00
Misa 3a2265ef0d Add being able to delete a custom level quicksave
Custom level quicksaves are NOT affected by the clear data menu, so the
player should be able to delete quicksaves this way. The quicksave
confirmation menu now has an extra option to delete the save (and that
option also has its own confirmation menu before deleting).
2021-08-18 16:02:11 -07:00
Misa bc47b86645 If loaded level assets fail to mount, print message to non-console users
This error case can happen, but if it does, non-console users get an
ERROR page with no further information. So use setLevelDirError if this
failure mode happens. And Menu::errorloadinglevel needs to be changed to
accomodate that.
2021-08-18 10:08:39 -07:00
Misa 124d77c041 Don't use PHYSFS_getRealDir() to check for .zip
Not sure why the original implementation decided to do things this way
instead of snprintf'ing a path to the .zip itself. Otherwise, if the
level is from data.zip, PHYSFS_getRealDir() will return the path of
data.zip, which then fails to mount for separate reasons.
2021-08-18 09:57:55 -07:00
Misa a1df4c1383 Revert "Fix loading levels that are... uh, just levels."
This reverts commit ea74b93f38.

This is reverted for being a bit of a hack in my opinion.
2021-08-18 09:52:38 -07:00
Misa 0fd4f21710 Remove unused dir string
Since 4154066c26 reduced the memory
footprint, it's now unused.
2021-08-18 09:45:07 -07:00
Misa b60bfc6bd8 Remove level menu rendering code in NO_CUSTOM_LEVELS builds
Should have been done earlier, imo. But now that we introduce `ed` the
NO_CUSTOM_LEVEL build fails because of it. So just ifdef it out
entirely.
2021-08-18 09:26:14 -07:00
Misa 9b3ae770fb Account for lack of prev/next options if only one page of levels
Otherwise the seventh and eighth levels would be grouped with the return
menu button.

Fixes #826.
2021-08-18 09:17:41 -07:00
Misa aa439bff16 tokenize(): Check all arguments
63a487d20d only checked for the last
argument, not for all arguments.

Fixes #822.
2021-08-12 23:47:03 -04:00
Misa 63a487d20d createentity command: Actually have p1/p2/p3/p4 defaults
Since createentity() started accepting p1/p2/p3/p4 arguments, it now
unconditionally passes in whatever arguments were present there
previously, when there weren't any before.

This can lead to unexpected behavior when selectively using and then
omitting p1/p2/p3/p4 arguments.

Also, plenty of existing levels already only use the 5-argument version
of createentity(). And createcrewman() can take up to 6 arguments at
once. It's not far-fetched that an existing level could createentity()
right after doing a 6-argument createcrewman(), which would lead to a
different behavior than in 2.2 and previous.

So instead, instead of checking if `words[index]` is an empty string (it
only sets the string to be empty if there are enough argument separators
on the line), ACTUALLY check if it's empty. I've added a static array
(no need for it to be exported) that keeps track of this. createentity()
now checks for that instead of `words`.
2021-08-12 00:20:40 -04:00
Misa 87ec35eb45 Cycle tower color if loading level has error
For consistency.
2021-08-12 00:15:33 -04:00
Misa 28e4a155d4 Don't show next/previous page options if only one page
It's possible to get one page of levels by removing all the built-ins,
either by removing them directly from data.zip or by putting files with
the same filenames as them in your level folder that don't contain
nothing.

And hey, there's already a check for if no levels exist at all, so why
not check for this too?
2021-08-12 00:15:21 -04:00
Misa 254cede905 Editor: Play Viridan squeak when entering a script
For consistency.
2021-08-12 00:14:22 -04:00
Misa 71dfbc1860 Allow getting star if more trinkets than level trinkets
Previously, you would only get the trinket completion star if you got
the exact same amount of trinkets as there are custom entity trinkets in
the level file. But if you got more (say, if the level spawned extra
"bonus trinkets"), you wouldn't be able to get the star.

This is true of the custom crewmate case as well, but I've decided to
not change that case, because there are still downsides to the resulting
behavior and it's better to just leave it alone because it's rare for it
to happen anyways.
2021-08-12 00:13:27 -04:00
Misa 448a99ca23 Save showtrinkets to custom level quicksaves
Since custom levels have gained the functionality to show trinkets on
the minimap, it's nice to just save the showtrinkets variable directly
to the save file, without having to make level makers handle it
themselves.
2021-08-12 00:13:05 -04:00
Misa 7699f5aaf1 Display improper zip structure message to non-console users
If a zip file is improperly structured, a message will be displayed when
the player loads the level list.

This will only display the last-displayed improper zip, because there
only needs to be one displayed at a time. Also because doing anything
more would most likely require heap allocation, and I don't want to do
that.
2021-08-10 16:33:52 -04:00
Misa 8dc5d69ef3 Do not close game if custom level has assets issues
It's quite rude to close the game entirely if there is trouble with
assets. Instead, just unload the assets and gracefully return to the
title screen.
2021-08-10 16:33:52 -04:00
Misa ed9cb4ca6d Add graphics wrapping functions
This will wrap text on-the-fly, since I will be introducing text that
needs to be wrapped whose length we can't know in advance. (Or we can,
but, that'd be stupid.)

I took the algorithm from Dav999's localization branch, but it's not
like it's a complicated algorithm in the first place. Plus I think it
actually handles words that get too long to fit on a single line better
than his localization branch. The only difference is that I removed all
the STL, and made it more memory efficient (unlike his localization
branch, it does not copy the entire string to make a version with
newline separator characters).
2021-08-10 16:33:52 -04:00
Misa ee02aa0499 Add fallthrough macro
This macro needs to be used because Clang is stupid and doesn't let you
use /* fallthrough */ comments like GCC does. However, if GCC is too old
(as is the case on CentOS 7), then it won't recognize __has_attribute
either.
2021-08-10 16:33:52 -04:00
Misa 3095871683 Add unfocus audio pause option
Some people prefer the 2.2 behavior where unfocusing pauses the game,
but the music still plays. One such person is Trinket9 on the VVVVVV
Discord server, who wanted it that way.

The reason audio pausing was added in the first place was to prevent
desyncing music in levels with cutscenes that synced to music. Rather
than reverting it, let's add this option instead.
2021-08-10 15:26:44 -04:00
Misa b114be88d5 Disable final color animations if screen effects off
Similar to disabling the elephant flashiness, at least one
photosensitive person has told me the flashy color animation makes their
eyes kind of hurt a little bit. Also it screws up the compression really
badly when they record (especially the green noisy tiles!).

The colors will still cycle, but the individual animations within each
color will be completely static.
2021-08-07 19:22:00 -04:00
Misa 1841f1886a Do not close game if fallback character is missing
It's quite rude to close the game. Especially if the user does not use
the console. They won't know why the game closed.

Instead, just return -1. All usages of font_idx() should be and are
bounds checked anyways. This will result in missing characters, but,
it's not like the characters had a font image in the first place,
otherwise we wouldn't be here. And if the user sees a bunch of
characters missing in their font, they'll probably work out what the
problem is even without having a console. And it's still far better than
abruptly closing the game.

And use WHINE_ONCE to prevent spamming the console.
2021-08-07 13:09:05 -04:00
Misa 3094ddb8f3 Enforce semicolons after usage of WHINE_ONCE
For consistency.

Since WHINE_ONCE ends with a block, the only way to make the compiler
enforce it is to end it with a `do { } while (false)`.
2021-08-07 13:09:05 -04:00
Misa 4a07e98015 Zips: Don't print redundant message if file not found
Let's say you have a zip named LEVELNAME.zip, but the only .vvvvvv file
it contains is NOTLEVELNAME.vvvvvv. This zip would end up printing both
the 'LEVELNAME.vvvvvv is missing' and 'It has .vvvvvv file(s) other than
LEVELNAME.vvvvvv' messages, even though we already know there's
something wrong with the zip, and the 'other level files' message is
redundant, since in this case the problem here is simply just the
.vvvvvv file being named the wrong way.

The 'other level files' message is only intended to be printed when
LEVELNAME.vvvvvv *does* exist, but there's additional .vvvvvv files in
the zip on top of that, so don't print this message if LEVELNAME.vvvvvv
exists.
2021-08-07 13:04:19 -04:00
Misa 8f70cb8667 Fix regression with chunky pixels being the wrong color
Since colors going into FillRect() need to be in BGR format, we need to
use getBGR instead. (Well, actually, it gets passed in RGB, but then at
some point the order gets switched around, and, really, this game's
masks are all over the place, I'm going to fix that in 2.4.)
2021-08-05 22:57:41 -04:00
Misa 45dd7c39b7 Fix cycling title BG more than once per frame
This can happen if you select an option in a menu that (A) returns to
the previous menu and (B) saves settings. If the settings save fails,
this will create another menu on the same frame that cycles the tower BG
after it's already been cycled for that frame. Examples are the slowdown
and glitchrunner menus.

I could fix this by creating a new function that copy-pastes all of
Game::savestatsandsettings_menu() except for the map.nexttowercolour()
at the end. But that's copy-pasting code.

Instead what I've done is added a variable to signal if the color has
already been cycled this frame, so we don't cycle it again. This also
covers cases of possible double-cycling in the future as well.
2021-08-05 21:42:59 -04:00
Misa b9202dee8b Fix frame flickers when fading during loads/exits
This is because the fade delay did not last long enough.

I was under the mistaken impression that the fade animation lasts for 15
frames. However, this does not account for the fact that the offset of
each fade bar is dependent on RNG, and the worst case scenario is that
they have an offset of 96 pixels (in the opposite direction of the
fade).

The actual fade animation timer accounts for the worst case scenario, so
the fade animation actually lasts for (320 pixels plus 96 pixels is 416
pixels, 416 pixels divided by 24 pixels per frame equals 17.333...
frames, but since the actual timer keeps adding/subtracting 24 pixels
per frame until it passes the 416-pixel threshold, that gets rounded up
to...) 18 frames.

And an extra frame to make it so deltaframe interpolation doesn't
suddenly stop on the last deltaframes before the screen is completely
black.

I also need to draw the screen black on the map screen when glitchrunner
mode is off, if there's a fadeout going on. Else that would introduce
yet another frame flicker.
2021-08-05 19:12:23 -04:00
Misa 90660d67a7 Fix trailing whitespace introduced by lssa
No comment.
2021-08-05 19:12:23 -04:00
Misa 6c6d347ccf Always reset player when starting gamemode
This fixes a bug where the player would always be facing right if they
were loading in for the first time. This essentially made them always
ignore the facing direction set in the save file if the facing direction
was leftwards.

The problem is facing direction only gets set in map.resetplayer(), but
if loading in for the first time, that path is never taken (unless you
are loading a main game quicksave that's inside a tower). The solution
is to always reset the player, even after creating them for the first
time.
2021-08-05 17:30:25 -04:00
Misa 0dda1ca5e4 Save stats when setting stat_trinkets
This ensures that if the game crashes afterwards, the new stat_trinkets
value won't be lost.
2021-08-05 17:22:39 -04:00
Misa e184923667 Don't take editor input when fading out
This fixes being able to re-trigger the fadeout while a fadeout is
already happening. It also fixes being able to enter playtesting during
the fadeout, which means the level now has a fadeout you normally can't
do in actual gameplay.
2021-08-05 17:22:20 -04:00
Misa 48a1c7ee61 Don't lerp when drawing all-sides warp background
There's nothing to interpolate. It moves at one pixel per frame. And
interpolating sometimes results in the box being short by 1 pixel to
cover the whole screen on deltaframes, so if you stand on the right edge
of the screen and have a translucent sprite, it will quickly draw over
itself many times, and it looks glitchy. This commit fixes that bug.
2021-08-05 16:44:44 -04:00
Misa be69d76f4f Play Viridian squeak when exiting to menu
For consistency.
2021-08-05 14:56:19 -04:00
Misa 243f9b92f8 Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).

What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 13:35:21 -04:00
Misa b09d0c48e4 Play Viridian squeak when pressing Esc in teleporter menu
For consistency, this should be done to match pressing Esc on the map
screen.
2021-08-05 13:33:17 -04:00
Misa 80dda53603 Play Viridian squeak when returning to Super Gravitron
For consistency.
2021-08-05 13:21:02 -04:00
Misa c0e11d65f2 Play Viridian squeak when returning to Secret Lab
For consistency.
2021-08-05 13:20:51 -04:00
Misa f3ca4ab2e7 Fix generateBase36 generating more than base 36
Two problems: the fRandom() range was from 0..36, but that's 37
characters, not 36. And the check to sort the lower 26 values into the
Latin alphabet used a 'lesser-than-or-equal-to 26' check, even though
that checks for the range of values of 0..26, which is 27 letters, even
though the alphabet only has 26 letters. So just drop the equals sign
from that check.
2021-08-05 08:58:54 -04:00
Misa db76735c07 Fix zip structure checks checking for wrong filename
It was checking for .vvv-mnt-temp-XXXXXX/LEVELNAME.vvvvvv instead of
LEVELNAME.vvvvvv. When PhysFS enumerates the folder, it only gives us
LEVELNAME.vvvvvv, and not .vvv-mnt-temp-XXXXXX/LEVELNAME.vvvvvv.
2021-08-05 08:58:23 -04:00
Misa 3ca7b09012 Fix regression: quick stopping changing drawframe
This fixes a regression that desyncs my Nova TAS after re-removing the
1-frame input delay.

Quick stopping is simply holding left/right but for less than 5 frames.
Viridian doesn't decelerate when you let go and they immediately stop in
place. (The code calls this tapping, but "quick stopping" is a better
name because you can immediately counter-strafe to stop yourself from
decelrating in the first place, and that works because of this same
code.)

So, the sequence of events in 2.2 and previous looks like this:

- gameinput()
  - If quick stopping, set vx to 0
- gamerender()
  - Change drawframe depending on vx
- gamelogic()
  - Use drawframe for collision (whyyyyyyyyyyyyyyyyyyyyyyyyyyy)

And now (ignoring the intermediate period where the whole loop order was
wrong), the sequence of events in 2.3 looks like this:

- gamerenderfixed()
  - Change drawframe depending on vx
- gamerender()
- gameinput()
  - If quick stopping, set vx to 0
- gamelogic()
  - Use drawframe for collision (my mind has become numb to pain)

So, this means that all the player movement stuff is completely the
same. Except their drawframe is going to be different.

Unfortunately, I had overlooked that gameinput() sets vx and that
animateentities() (in gamerenderfixed()) checks vx. Although, to be
fair, it's a pretty dumb decision to make collision detection be based
on the actual sprites' pixels themselves, instead of a hitbox, in the
first place, so you'd expect THAT to be the end of the dumb parade. Or
maybe you shouldn't, I don't know.

So, what's the solution?

What I've done here is added duplicates of framedelay, drawframe, and
walkingframe, for collision use only. They get updated in gamelogic(),
after gameinput(), which is after when vx could be set to 0.

I've kept the original framedelay, drawframe, and walkingframe around,
to keep the same visuals as closely as possible.

However, due to the removal of the input delay, whenever you quick stop,
your sprite will be wrong for just 1 frame - because when you let go of
the direction key, the game will set your vx to 0 and the logical
drawframe will update to reflect that, but the previous frame cannot
know in advance that you'll release the key on the next frame, and so
the visual drawframe will assume that you keep holding the key.

Whereas in 2.2 and below, when you release a direction key, the player's
position will only update to reflect that on the next frame, but the
current frame can immediately recognize that and update the drawframe
now, instead of retconning it later.

Basically the visual drawframe assumes that you keep holding the key,
and if you don't, then it takes on the value of the collision drawframe
anyway, so it's okay. And it's only visual, anyway - the collision
drawframe of the next frame (when you release the key) will be the same
as the drawframe of the frame you release the key in 2.2 and below.

But I really don't care to try and fix this for if you re-enable the
input delay because it's minor and it'd be more complicated.
2021-07-28 20:11:16 -04:00
Misa 95ffc3a62b Fix wrong bounds check when colliding with activity zones
I am so stupid.
2021-06-26 15:59:17 -04:00
Misa 88d31ab3b6 Custom levels: only count inbounds trinkets/crew
In the past, people have reported having glitched levels where they
can't get the trinket star or can't complete the level because the
number of trinkets or crewmates is one higher than what can be obtained
in the level.

How did this happen? Well, it turns out that if you place an entity, and
then resize the level to be smaller, that entity still exists. This is
inconsequential for most entities, but if the entity is a trinket or
crewmate, that entity is still counted towards the number of trinkets or
crewmates in the level.

One fix would be to just remove entities whenever the level is
downsized, but then if someone accidentally downsizes the level and
wants to go back, that entity will be gone. Plus, it would be
inconsistent with tiles, because tiles don't get removed when you
downsize the level. Also, it wouldn't fix existing levels where people
have managed to place trinkets or crewmates out of bounds.

So instead, ed.numtrinkets() and ed.numcrewmates() should simply ignore
trinkets and crewmates that are outside the playable area. That way,
levels with glitched trinkets and crewmates can still be completed, and
can still be completed with the trinket star.
2021-06-19 14:01:38 -04:00
Misa 571f6a7098 Re-add playtesting passthrough code block for non-separate interact
This fixes a regression where you're unable to activate activity zones
in in-editor playtesting if your interact button is not separate from
the map button.

When I originally did #743, I didn't have an option to set the bind to
be non-separate, so I removed this logic without adding a
game.separate_interact check. But when I added the option, I overlooked
this code, and so this regression happened. Whoops.
2021-06-18 10:59:43 -04:00
Misa a0c5724283 Set visualonroof/visualonground to 1 on vertical platforms
This fixes one of two desyncs in my Nova TAS.

The problem is that by adding two frames of edge-flipping to vertically
moving platforms, Viridian's framedelay is updated for one extra frame
after they step off of a vertically-moving platform. This then messes up
Viridian's drawframe for the rest of the TAS until they die in a
drawframe-sensitive trick.

The solution here is to only set the visual onroof/onground to 1
instead. The logical onroof/onground is still 2, so players still have
two frames of edge-flipping off of vertically-moving platforms - it just
won't really look like it (not that you could easily tell anyway).
2021-06-14 14:55:51 -04:00
Misa c02bd9235f Outline text outline text and draw backing
In order to help players spot the difference between outlined text and
non-outlined text, we now outline the text outline text itself (if text
outline is enabled, of course). But drawing the outline alone doesn't
stand out enough, so we have to draw a solid backing against the text as
well, in order to properly show the contrast.
2021-06-12 19:02:14 -04:00
Misa 9c226ab5aa Play Viridian squeak when using return button in audio options
For some reason this button was missing the Viridian squeak.
2021-06-12 19:01:51 -04:00
Misa 3b6c0befb1 Fix being able to start flipped in time trials
This fixes a regression where you're able to start flipped by restarting
and then holding ACTION.

This happens because when the game resets all variables, it turns
hascontrol back on (because of hardreset()). However, this is handled in
the input function, and it's handled before player input is handled, so
the player is able to get 1 frame of being able to flip after a time
trial resets.

Why didn't this happen in 2.2? Because resetplayer() in 2.2 would set
lifeseq to 10, as if the player had died. However, this is inconsistent,
because loading in to the game for the first time would not result in a
lifeseq of 10. So, in 2.2, restarting the time trial would remove that 1
frame of being able to flip because of lifeseq, while 2.3 doesn't set
lifeseq because the player hasn't died.

I could have fixed this by setting lifeseq in the time trial restart
code, but I decided to just set hascontrol to false instead.

Fixes #770.
2021-06-12 18:17:31 -04:00
Misa d292b64c6d Use hiddenname for hardestroom if roomname is empty
In earlier 2.3, if the roomname was empty, Dimension VVVVVV was used
instead. However, instead of doing that, it's better to just use the
hiddenname instead. Both because it's less hardcoded, and some rooms
have hidden names that aren't Dimension VVVVVV.
2021-06-11 23:58:18 -07:00
Misa f205147eaa Outline time trial countdown
This makes the text much more readable against certain backgrounds (if
you have text outline enabled), especially against the Warp Zone
background (when you start in "This is how it is").
2021-06-11 23:56:33 -07:00
Misa 6dd01495f3 Explore all rooms when entering Secret Lab
If you enter the Secret Lab from the title screen, all rooms will be
explored. However, if you enter the Secret Lab via the Secret Lab
entrance cutscene (epilogue), not all rooms will be explored, which is
inconsistent.

To do this, just do an SDL_memset() for the entersecretlab script
command.
2021-06-11 23:51:48 -07:00
Misa d404986e6f Use memset to give 20 trinkets and explore all rooms
SDL_memset() conveys intent better and is snappier than using a
for-loop. Also, using SDL_memset() to explore all rooms is more
future-proof, in case the size of map.explored were to change in the
future, and it's more conducive to optimization.

However, the `i` variable has to be explicitly set because it was
previously used here, but it's much better that it's explicitly set here
rather than being subtlely hidden in the inner for-loop initialization.
2021-06-11 23:51:37 -07:00
Misa 37fd24bd85 Interpolate gravitron square indicators
This is more future-proofing than anything else. The position of the
indicators is just the x-position of the gravitron square divided by 10,
but the gravitron squares will always only ever move at 7 pixels per
frame - so the distance an indicator travels on each frame will only
ever be at most 1 pixel. But just in case in the future gravitron
squares become faster than 10 pixels per frame, their indicators will be
interpolated as well.
2021-06-11 22:20:06 -07:00
Misa 6767249558 Prevent losing level data with rollcredits
When rollcredits is ran during in-editor playtesting, all unsaved data
is lost. To prevent this, just return to the editor if rollcredits is
ran, with a note saying "Rolled credits".
2021-06-11 15:30:29 -07:00
Misa 47460143e2 Fix being able to see box corners on map screen with custom graphics
The text box drawn at the bottom of the map screen isn't wide enough, so
it's possible to see the corners on the right side of the text box if
you have custom graphics like I do.

The solution is to increase the width of the text box by one tile.
2021-06-11 15:07:08 -07:00
Misa 74bbf45fa7 Play Viridian squeak when updating controller keybinds
For consistency, the Viridian squeak is now played whenever the user
updates their controller keybinds.
2021-06-11 12:56:07 -07:00
Misa d25243943e Save settings after changing controller keybind
The game automatically writes settings to disk after any other setting
is changed, so it should do the same whenever the user changes
controller keybinds.
2021-06-11 12:54:36 -07:00
Misa 1ccf85a260 Play Viridian squeak when editing level desc fields
For consistency, the Viridian squeak will now play whenever you start
editing a level description field, or finish editing it (either by
pressing Esc or Enter).
2021-06-11 12:52:28 -07:00
Misa 96660cd235 Add zip structure checks for user friendliness
If a level zip is named LEVELNAME.zip, the level file inside it must
also be named LEVELNAME.vvvvvv, else custom assets won't work.

This is because when we mount the zip file, we simply add
LEVELNAME.vvvvvv to the levels directory. Then whenever we load
LEVELNAME.vvvvvv, we look at the filename, remove the extension, and
look for the assets inside the zip of the same name, LEVELNAME.zip.

As a result, if someone were to make a level zip with assets but
mismatch the filename, the assets wouldn't load. Furthermore, if someone
were to add extra levels in the same zip, they wouldn't have any assets
load for them as well, which could be confusing.

To make things crystal-clear to the user, we now filter out any zips
that have incorrect structures like that, and print a message to the
terminal. Unfortunately nothing gets shown for non-terminal users, but
at least doing this and filtering out the zips is less confusing than
letting them through but with the issues mentioned above.
2021-05-25 15:23:34 -04:00
Misa 153a5c4c3a Factor out "between" calculation to macro and func
FILESYSTEM_mountAssets() has a big comment describing the magic numbers
needed to grab FILENAME from a string that looks like
"levels/FILENAME.vvvvvv".

Instead of doing that (and having to write a comment every time the
similar happens), I've written a macro (and helper function) instead
that does the same thing, but clearly conveys the intent.

I mean, just look at the diff. Using VVV_between() is much better than
having to read that comment, and the corresponding SDL_strlcpy().
2021-05-25 15:23:34 -04:00
Misa 29d2637abd Factor out UNUSED macro to header file
This is so it can be used in other files without having to copy-paste
the define.
2021-05-25 15:23:34 -04:00
Misa 3bcb6938f7 Factor out base 36 generation to separate function
This is so it can be reused without having to copy-paste.

generateBase36() is guaranateed to completely initialize and
null-terminate the buffer that is passed in.
2021-05-25 15:23:34 -04:00