1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-11-04 18:29:41 +01:00
Commit graph

1691 commits

Author SHA1 Message Date
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
treacherousfiend
f77723d12f Update project generation snippet
The project generation code snippet currently still references SDL2 2.0.10 even though building now requires 2.0.14, just a minor nitpick on my part.
2021-07-25 14:36:51 -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
Ethan Lee
43e8d31aa9 Music: Enforce the quick fade time as soon as we know it's happening.
Not every music path will trip the quick_fade bool that resets the timer to
500ms, so we need to do this as soon as it's asked of us. This fixes the fade
when quitting to the main menu.

Fixes #764
2021-06-14 15:11:39 -04:00
Ethan Lee
8520533296 Music: Reset step_ms on every fade call.
Without this you end up with two problems:
- Fades will start past their fade time, causing it to just not fade at all
- Fades will start in the middle of their fade time, causing dramatic changes
  in volume that are unintentional

The fade system already preserves the volume that music is playing during a
previous fade, so we can always reset the timer and get a good result.

Part of #764
2021-06-14 15:09:23 -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
Terry Cavanagh
67d1d6f01d
Merge pull request #778 from InfoTeddy/general-bug-fixes-7
Use hiddenname for hardestroom if roomname is empty
2021-06-14 13:04:44 +10:30
striker.sh
9188bd23d3 Support for OpenBSD
- use fseeko and ftello like FreeBSD in tinyxml2
- use current directory as basePath if NULL (OpenBSD doesn't actually support this feature it is disabled via a patch in their ports)
2021-06-13 10:48:20 -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
Terry Cavanagh
1d66cfccab
Merge pull request #777 from InfoTeddy/general-improvements
Outline time trial countdown
2021-06-12 22:35:31 +10:30
Terry Cavanagh
2efe7724a7
Merge pull request #775 from InfoTeddy/general-bug-fixes-5
Interpolate gravitron square indicators
2021-06-12 22:35:07 +10:30
Terry Cavanagh
b07d92ac44
Merge pull request #776 from InfoTeddy/general-bug-fixes-6
Explore all rooms when entering Secret Lab
2021-06-12 22:33:37 +10:30
Terry Cavanagh
b06b278bb0
Merge pull request #774 from InfoTeddy/general-bug-fixes-4
Prevent losing level data with rollcredits
2021-06-12 22:33:17 +10:30
Terry Cavanagh
fa3021c714
Merge pull request #773 from InfoTeddy/general-bug-fixes-3
Fix being able to see box corners on map screen with custom graphics
2021-06-12 22:32:36 +10:30
Terry Cavanagh
eb0b7c8e87
Merge pull request #772 from InfoTeddy/general-bug-fixes-2
Fix inconsistencies with controller keybind options
2021-06-12 22:31:50 +10:30
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
Terry Cavanagh
766782da5d
Merge pull request #749 from InfoTeddy/general-bug-fixes-2
Fix tower camera invincibility inconsistencies
2021-05-25 13:05:07 +10:30
Misa
417b7d656d Set newxp/newyp when creating player
This fixes a bug where the player's y-position would be incorrect if
they loaded a save that was on a conveyor and it was their first time
loading in since the game was opened.

This is because on the first load, the game creates a new player entity,
but on subsequent loads, the game re-uses the player entity. Subsequent
loads use mapclass::resetplayer(), which already has the newxp/newyp
fix, but as for the first time, the game does not set newxp/newyp.

So just set newxp/newyp, like in mapclass::resetplayer().
2021-05-24 09:50:01 -04:00
Ethan Lee
73c1c9a798 Revert "Change final stretch song to Piercing the Sky"
Upon further discussion it was decided to keep the soundtrack as originally
shipped, instead of changing it after the fact.

This reverts commit cf51379097.
2021-05-20 23:01:43 -04:00
Misa
8b3c805bc0 Fix Super Gravitron pattern oversight
There is a pattern in the Super Gravitron that is meant to "staircase",
similar to the Gravitron in Intermission 2. Something like:

[]
     []
          []
               []             []
                    []   []

Unfortunately, due to an oversight, this pattern can only ever produce 1
square or 4 squares, which look out of place.

Both gravitrons are state machines (of course). States 20 and 21 in the
Super Gravitron are this staircase pattern (state 20 spawns the squares
on the left, state 21 spawns the squares on the right).

The only way states 20 and 21 can be reached is through state 1, and the
only way state 1 can be reached is through state 3. The only way state 3
can be reached is through states 28, 29, 30, and 31.

In states 20 and 21, the variable used to keep track of the amount of
squares spawned is swnstate4. However, states 28, 29, 30, and 31 all end
up using swnstate4, and at the end of states 28 and 29, swnstate4 will
be 7, and at the end of states 30 and 31, swnstate4 will be 3. This
means if we go to states 20 and 21 after coming from states 28 and 29,
we will only get 1 square, and if we go to states 20 and 21 after coming
from states 30 and 31, we will only get 4 squares.

This can be clearly filed under a failure to reset appropriate state.

What's the solution here? Just reset swnstate4 in state 3, so there will
be 7 squares, as intended. This also fixes the bug for state 22 as well,
which is affected in the same manner.
2021-05-20 20:57:56 -04:00
Misa
448e34e878 Save showtargets to main game save files
This fixes an oversight that could lead to confusion by the player.

showtargets is the variable that shows all unexplored teleporters on the
map as a question mark, so players know where to head to to make
progress. However, it previously was not directly saved to the main game
file. Instead, it would be set to true if flag 12 was turned on in the
save file.

How well does flag 12 correlate with showtargets?

Well, the script that turns on showtargets (bigopenworld and
bigopenworldskip) doesn't turn it on. Neither does completing Space
Station 1.

This flag is only turned on when the player activates Violet's activity
zone for the first time.

Therefore, it's entirely possible that a new player could complete Space
Station 1, then save their game, and come back to resume playing later.
When they do come back, the question marks that Violet told them about
won't show up on the minimap, and they'll be confused. They may not know
where to go.

And it is completely unintuitive for them to know that in order to get
the question marks to show up again, they have to not only talk to
Violet, but then save the game again, and reload the save. Especially
since the question marks only show up after you reload the save, and not
when you talk to Violet (because flag 12 is only a proxy for
showtargets, not the actual variable itself).

So what's the solution? Just save showtargets to the save file directly.
2021-05-20 19:56:25 -04:00
Misa
bc382a4985 Fix tower camera invincibility inconsistencies
If you have invincibility enabled, the tower camera behavior is
inconsistent.

In ascending towers, you can "push" the camera upwards; however you
cannot push it downwards; at least it stays still when it comes up to
you if you stay still. In descending towers, the camera moves quicker
when you're at the bottom of the screen, but it's slower than your
falling speed and quickly loses sight of you; the camera can be pushed
upwards; unfortunately it also does a "bumping" motion if you're
standing still when the camera reaches you, which gets real annoying and
isn't particularly pleasant to look at.

There are two problems, so this does two fixes:

1. Pushing the camera now applies the appropriate counter-offset
   depending on the direction of the tower. You can now push the camera
   downwards in ascending towers.

2. To fix the "bumping" when the camera reaches you if you stand still,
   there are now a 8-pixel-high "gray areas" at the top and bottom of
   the screen where the camera simply won't move if you're in them.

Doing these camera offsets instead of simply canceling the movement if
the player is offscreen is a bit ugly... but it works for now.
2021-05-19 00:26:47 -07:00
Terry Cavanagh
330162d1cb
Merge pull request #743 from InfoTeddy/general-improvements
Separate pressing Enter to open map from pressing Enter to interact
2021-05-19 17:54:52 +10:30
Misa
4fa435f784 Separate pressing Enter to open map from pressing Enter to interact
This is a lot of copy-pasted code, but a little bit of copy-pasting
never hurt anyone...

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

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

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

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

Closes #736.
2021-05-19 00:04:00 -07:00
Misa
92416cd910 Don't update crewmate colors in text boxes every deltaframe
Colors in over-30-FPS mode shouldn't be updating every deltaframe;
mostly to ensure determinism between switching 30-mode and over-30 mode.
I'm going to overhaul RNG in 2.4 anyway, but right now I'm going to fix
this because I missed it.

The RNG of each special text box is stored in a temporary variable on
the text box itself, and only updated if the color uses it (hence the
big if-statement). Lots of code duplication, but this is acceptable for
now.
2021-05-18 21:17:06 -04:00
Terry Cavanagh
d749e7e6e8
Merge pull request #682 from InfoTeddy/general-bug-fixes-4
Add finalmode check to drawfinalmap call
2021-05-17 18:56:32 +10:30
Terry Cavanagh
569403b7e2
Merge pull request #681 from InfoTeddy/general-bug-fixes-3
Remove final_colorframe assignments when entering minitowers
2021-05-17 18:55:52 +10:30
Misa
cf51379097 Change final stretch song to Piercing the Sky
After the dimension destabilizes, the song that plays is Positive Force.
Which has already been played twice in the game at that point (first in
Tower, then in the Gravitron). Since Piercing the Sky is unused, why not
play a song that the player hasn't heard before? It would also be
musically fitting for the scenario.

The song gets played in two places - one for if you have cutscenes
enabled, and one for if you don't - so we just need to change both of
them.

I asked Terry in Discord DMs if he wanted this change and he approved of
it.
2021-05-17 02:02:44 -04:00
Misa
f31b57a6fc Fix deltaframe glitch when spawning No Death Mode trophy
If you have completed No Death Mode, and entered the Master of the
Universe trophy room in the Secret Lab in over-30-FPS mode, it would
appear to start at one position before quickly zipping to another during
the deltaframes.

This is because it updates its position after the initial assignments of
lerpoldxp/lerpoldyp in entityclass::createentity().

Other entities do this too, and what's been done for them is to
copy-paste the lerpoldxp/lerpoldyp updates alongside the xp/yp updates.
However, instead of single-case patching this deltaframe glitch, I've
opted to fix ALL cases by simply moving the lerpoldxp/lerpoldyp
assignments to the end of the function, guaranteeing that all entities
that update their position after the initial assignment in the function
will not have any deltaframe glitches.

Of course, there's still the duplicate lerpoldxp/lerpoldyp updates in
entityclass::updateentities()... I'm not sure what to do about those.
2021-05-16 22:40:16 -04:00
Terry Cavanagh
85bd009dce
Merge pull request #758 from InfoTeddy/general-bug-fixes
Allow using Esc in Super Gravitron quit menu
2021-05-15 08:08:54 +10:30