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

978 Commits

Author SHA1 Message Date
Misa
c7774a3eb9 Turn words into an array instead of an std::vector
It never changes its size, so it doesn't need to be a dynamically-sized
vector.
2020-07-06 11:19:24 -04:00
Misa
689af99220 Make currentletter a char instead of an std::string
It's only one character... why does it have to be a fully-fledged
std::string?
2020-07-06 11:19:24 -04:00
Misa
56b2f43ff8 Move tempword and currentletter off of scriptclass
There's no reason for these temporary variables to be a permanent part
of the class itself.
2020-07-06 11:19:24 -04:00
Misa
f28fcd78e8 Fix softlock from interrupted completestop
In summary, if you got to gamestate 1002 or 1012 without an advancetext,
and you had completestop on, you were basically softlocked. So just add
those gamestates there and advance the gamestate if advancetext is off.
2020-07-05 10:14:26 -04:00
Misa
d06fadadf2 Fix Map.cpp relying on editor.h to include Script.h
This would mean that NO_CUSTOM_LEVEL builds wouldn't compile.
2020-07-05 10:13:12 -04:00
Misa
1dfc536b0f Fix infinite loop pressing left/right in tele menu w/ no teles unlocked
This infinite loop would occur because once you pressed left or right,
the game keeps searching through all the list of teleporters until it
finds one that is unlocked. But if there's none that are unlocked, then
the game goes into an infinite loop, which brings up the Not Responding
dialog on Windows so you can kill it.

Normally, you're not supposed to have no teleporters unlocked while
being able to access a teleporter, but you can achieve this by going to
Class Dismissed from a custom level (while making sure you don't start
in 0,0, because there's a teleporter there that you would unlock).

The solution is to make sure at least one teleporter is unlocked before
doing any searching.
2020-07-04 22:48:16 -04:00
Misa
aa873ce172 Use proper do-while for teleporter searching loop
A do-while is just a while-loop, but the inner block will always run
once before the conditional is checked.

It looks like in order to achieve this desired behavior (always run the
block once before checking the conditional), instead of using a do-while
loop, Terry just used a normal while-loop and copy-pasted the inner
block on the outside.

So I'm de-duplicating the code.
2020-07-04 22:48:16 -04:00
Misa
7f61147973 Fix still being able to unlock things in custommode
This was caused by the fact that not all unlocks were done through the
Game::unlocknum() function. Some just set the unlock number directly.
But it's fixed now.
2020-07-02 23:59:42 -04:00
Ethan Lee
c4853688b4 Separate mkdirs from path string generation 2020-07-02 15:57:40 -04:00
Misa
029cc9d4b9 Fix wrong function being used to set color of coins
It should be setcolreal(), and not setcol().

Fixes #347.
2020-07-02 15:33:27 -04:00
Ethan Lee
c3e4e8589d Check saves dir in addition to levels dir for migration 2020-07-02 14:58:04 -04:00
Ethan Lee
d057c6a348 PHYSFS_mkdir uses the mount location when a system is mounted 2020-07-02 14:56:59 -04:00
Ethan Lee
ee610238b5 Try to preserve the script args for createentity when using default args 2020-07-02 14:34:21 -04:00
Misa
d22b895e22 Allow edentity terminals to use any sprite they want
Checkpoints can use any sprite they want, why not terminals, too?
2020-07-02 01:06:50 -04:00
Misa
450663594f Add G keybind to go to room
Ved has this useful feature where instead of having to manually travel
to a room whose coordinates you know, you can just press G and type in
coordinates to go there.

VCE added this, but I changed the text to be "x,y" instead of "(x,y)"
because otherwise it could confuse someone into thinking they need to
type parentheses when in reality they don't need to and typing them will
just make it not work.

Also I made sure to add an error message if the user types in an invalid
format. Failing silently would just confuse people, and maybe they'll
start thinking the feature doesn't work or something like that. VCE
doesn't have this helpful error message.

Lastly, VCE has a bug where if you use the shortcut to go from one
horizontally/vertically warping room to another, the background of the
previous room will still be there and scroll off with the background of
the room you went to, instead of just having the new background only.
This is because they forgot a 'graphics.backgrounddrawn = false;'. But
don't worry, *I* didn't forget about it.
2020-07-02 01:06:50 -04:00
Misa
76d8dc5bf2 Refactor/de-duplicate entity text input
This is basically FIQ's patch from VCE, except he never upstreamed it
because he said something along the lines of it seeming to not fit the
purpose of upstream.

But anyway, it basically just de-duplicates all the text input and text
finishing handling code and cuts down on the large amount of copy-paste
in the editor functions. It makes things way more maintainable.

Interesting note, it seems like FIQ had the intent to refactor the text
input in editor settings (i.e. the level metadata details), but never
got around to it in VCE. Maybe we'll finish that job for him later.
2020-07-02 01:06:50 -04:00
Ethan Lee
0f450f3e39 Move the VSync work to Screen.
The problem we're running into is entirely contained in the Screen - we need to
either decouple graphics context init from Screen::init or we need to take out
the screenbuffer interaction from loadstats (which I'm more in favor of since we
can just pull the config values and pass them to Screen::init later).
2020-07-02 00:19:40 -04:00
Misa
d854c61960 Add Shift+F1/F2/F3 hotkeys
Allowing users to reverse cycle tilesets/tilecols/enemies prevents them
from having to press the hotkey a zillion times in order to get to the
one they want if the one they want just happens to be behind the current
one they're on.
2020-07-01 23:49:23 -04:00
Misa
5132ccf1e6 Allow using Space Station tilecol -1
This tilecol conveniently lets players use one of the unpatterned Space
Station tilesets you see on the left side of tiles.png but never get to
use without Direct Mode.

It does have a few weird quirks, but it should be safe to use.
2020-07-01 23:49:23 -04:00
Misa
e8cf521ed7 Abstract tileset/tilecol/enemy switching to functions
This results in me having to copy-paste less code around, because
editorinput() is big enough as it is.
2020-07-01 23:49:23 -04:00
Misa
a0f8b83563 Re-organize editor shortcuts logic
Previously, it was:

    if (ed.settingsmod)
    {
        (Settings menu controls)
        ...
    }
    else
    {
        (Literally everything else
        Also a bunch of copy-pasted ed.keydelay checks)
        ...
    }

Now it is:

    if (ed.settingsmod)
    {
        (Settings menu controls)
        ...
    }
    else if (ed.keydelay > 0)
    {
        ed.keydelay--;
    }
    else if (key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL])
    {
        // Ctrl modifiers
        ...
    }
    else if (key.keymap[SDLK_LSHIFT] || key.keymap[SDLK_RSHIFT])
    {
        // Shift modifiers
        ...
    }
    else
    {
        // No modifiers
        ed.shiftkey = false;
        ...
    }

It might not counteract how completely huge this code is, but it's at
least organized better.

Also, I had to change the map resize logic around slightly, else it'll
get triggered any time you do a shift modifier keypress.
2020-07-01 23:49:23 -04:00
Misa
cf9c2f8933 Fix deltaframe render glitch when spawning animated double-size entities
Their drawframe needs to be incremented by 2 instead of 1, because
they're double-sized.

Animation type 3 is used by the cloud emitter in The Solution is
Dilution, animation type 6 is used by the radar dish in Comms Relay.
Animation type 4 is used by the maverick bus in B-B-B-Busted, but it's
not noticeable since it spawns offscreen. This bug would cause all of
those entities to appear incorrectly for the deltaframes between the
tick the room got loaded and the next tick after that.

This is noticeable in flibit's tweet showing off my over-30-FPS patch:
https://twitter.com/flibitijibibo/status/1273983014930993153
2020-07-01 17:54:52 -04:00
Misa
2569154010 Don't adhere to slowdown in MAPMODE/TELEPORTERMODE
Now that you have a mini menu in MAPMODE, it's a bit annoying to have to
deal with the slowed-down timestep when pressing left/right/ACTION
inside it. Especially since going to an options menu restores the
timestep back to normal (because it's in TITLEMODE). Also removed it
from TELEPORTERMODE for consistency.
2020-07-01 11:39:17 -04:00
Misa
f7da19b667 Make text() colors consistent with setblockcolour()
It seems a bit strange to have two separate color indexes that are
mostly the same, don'tcha think?
2020-07-01 11:39:17 -04:00
Ethan Lee
8e4be6112d Fix a couple spots where sizeof referred to array size 2020-07-01 00:46:55 -04:00
Ethan Lee
641277b430 Timing fixes for processVsync recreation workaround 2020-07-01 00:46:27 -04:00
Ethan Lee
708c8be089 NULL checks for processVsync 2020-07-01 00:36:04 -04:00
Ethan Lee
ffe425a202 Copypaste error for s_besttimes 2020-07-01 00:31:41 -04:00
Ethan Lee
3d8f53cfd2 Fix memset writing past bestframes 2020-06-30 23:02:18 -04:00
Misa
56c9a1554a Add names for previously disallowed songs
That way, they don't show up as "?: something else" and their proper
names are shown.

I didn't update the song numbers to include the newly-allowed songs
because otherwise it'd no longer correlate with what song numbers you
use for the music() simplified command.
2020-06-30 22:43:17 -04:00
Misa
7620e4664b Allow using any editor song
It was possible to do this already by editing the XML (or by using Ved),
for some reason the in-game editor just didn't let you do so.
2020-06-30 22:43:17 -04:00
Misa
6c19a38e9f De-duplicate editor music name printing
No need to copy-paste the graphics.Print() for every single case.
2020-06-30 22:43:17 -04:00
Misa
ee20067fc2 Read and write best time trial frames
This is basically just bolting on the "frames" part of a time trial
score. There's not enough space to properly show it on the time trial
select screen, maybe we can figure something out later. But I at least
want to implement the functionality now.
2020-06-30 22:42:29 -04:00
Misa
42e6185b12 Fix pressing Enter moving you leftwards in the editor
Whoops.
2020-06-30 22:41:38 -04:00
Misa
97bf731fa3 If invalid valid value, set valid to false
This is just to prevent parsing potentially garbage data, because some
of the code relies on the `valid` value being valid.
2020-06-30 21:07:05 -04:00
Misa
170e93054a Remove extraneous semicolon from MusicTrack::MusicTrack()
I don't know how that got there...
2020-06-30 21:07:05 -04:00
Misa
5fe3b9d0de Add bounds check to musicclass::play()
If the song number (after we've processed it) is out-of-bounds, then
just return and log the error.
2020-06-30 21:07:05 -04:00
Misa
7c2b418761 Account for extra tracks in musicclass::play()
Since each soundtrack is no longer guaranteed to be 16, we'll have to
account for their different lengths when playing music.
2020-06-30 21:07:05 -04:00
Misa
08fe655a5f Parse extra headers from binary blob
Not just the ones that contain specific names.
2020-06-30 21:07:05 -04:00
Misa
4c2f5ed032 Add binaryBlob::getExtra()
This needs to be done because m_headers is a private member of
binaryBlob.
2020-06-30 21:07:05 -04:00
Misa
09dbe8113b De-duplicate track names
Instead of copy-pasting the entire list three times over, why not put it
in an easy to use "X" macro?
2020-06-30 21:07:05 -04:00
Misa
ad540d57f4 Allow D-Pad to act as arrow keys in the editor
This doesn't make the editor completely accessible on controller, but
it's a good start at least. VCE already let you move between rooms with
the D-Pad, though.
2020-06-30 20:47:40 -04:00
Misa
07028d47d5 Add one-time OoB logs to tile-drawing functions
These functions will only complain once if they receive an out-of-bounds
tile. And it's only once because these functions are called frequently
in rendering code.

A macro WHINE_ONCE() has been added in order to not duplicate code.
2020-06-30 18:06:14 -04:00
Misa
5201f67909 Add being able to override the one-way recolor
Disabling the one-way recolor if assets are mounted is needed to make
existing levels not look bad, but what about levels that want to use the
recolor anyway?

The best solution here is to just introduce another bool into the XML,
and make the re-color opt-in and only present if assets are mounted if
that tag is present.
2020-06-30 18:06:14 -04:00
Misa
2d21bab4ea Only re-color one-ways if assets are not mounted
Some levels (like Unshackled) have decided to manually re-color the
one-way tiles on their own, and us overriding their re-color is not
something they would want. This does mean custom levels with custom
assets don't get to take advantage of the re-color, but it's the exact
same behavior as before, so it shouldn't really matter that much.

I would've liked to specifically detect if a custom tiles.png or
tiles2.png was in play, rather than simply disabling it if any asset was
mounted, but it seems that detecting if a specific file was mounted from
a specific zip isn't really PHYSFS's strong suit.
2020-06-30 18:06:14 -04:00
Misa
d610e2dae3 Add bounds checks to drawforetile/drawforetile2/drawforetile3
When I was writing the previous commit I noticed that these functions
didn't have bounds checks, which is a bit bad. So I added them.
2020-06-30 18:06:14 -04:00
Misa
e84194db55 Re-color one-way tiles to match their tileset
One-ways have always had this problem where they're always yellow. That
means unless you specifically use yellow, it'll never match the tileset.

The best way to fix this without requiring new graphics or changing
existing ones is to simply re-tint the one-way with the given color of
the room. That way, the black part of the tile is still black, but the
yellow is now some other color.
2020-06-30 18:06:14 -04:00
Misa
b5783007b3 Adhere to "locked" gravity/warp lines
Ved has this useful feature where you can "lock" a gravity line or warp
line in place, meaning it'll no longer extend its length until it
touches a tile. A line is locked if the p4 of the edentity is 1.

VVVVVV doesn't support this, but now it does. The horrifying thing is
that it stretches the lines out *while rendering the line*, so it looks
like logic and rendering aren't that separate after all (although, I
already learned that when I did my over-30-FPS patch).
2020-06-30 17:52:15 -04:00
Dav999-v
7adf71a21b Change "toggle letterbox" to "scaling mode"
This change was half-backported from the localization branch, except I
just came up with "scaling mode" as a better term than the more generic
"graphics mode". It doesn't make sense to still have the option be
called "toggle letterbox" because a third option (integer mode) was
added at some point.
2020-06-30 16:53:33 -04:00
Dav999-v
e20c01deed Move "resize to nearest" grouped with other resolution-related options
The options for fullscreen and scaling mode were at the top, then there
were various other graphical options, and then the option to resize to
the nearest window size that is of an integer multiple was all the way
below that. Now that last option is moved to be right below the other
options related to window sizing.
2020-06-30 16:53:33 -04:00
Dav999-v
a2d8e57af0 Move some options to a new menu, "advanced options"
VVVVVV's menus are kind of packed to the brim, so I thought it was time
to recategorize the menus a little bit. There's now a new "advanced
options" menu which holds the following options which were moved out of
graphic options, game options and especially accessibility options:

- toggle mouse
- unfocus pause
- fake load screen
- room name background
- glitchrunner mode

I also made the positioning of the titles and descriptions more
consistent, and made some options which were moved to the new menu not
so abbreviated ("load screen" and "room name bg")
2020-06-30 16:53:33 -04:00
Misa
de2d6a1e86 Expose all 9 arguments of createentity()
For whatever reason, not all arguments of createentity() are exposed in
the command.

We have to keep in mind that (1) unspecified arguments default to 0
(instead of the 320 and 240 for argument 8 and 9 that createentity()
usually defaults to), and that (2) arguments persist across commands.
(Why not get rid of argument persistence, you say? Unfortunately, some
levels rely on argument persistence to call gotoposition() without
specifying the third argument, even though you're supposed to specify
all three arguments.)

To add these arguments without breaking levels, I re-added the
createentity() defaults of 320 and 240 for args 8 and 9, and then I
reset the new arguments afterwards when I'm done. Technically this could
be bad if other commands used those higher arguments, but none of them
really do. (Except createcrewman(), but it only sets argument 6 to 0
sometimes anyway, but argument 6 is already supposed to default to 0.)
2020-06-30 16:50:56 -04:00
Misa
db06b336b6 Don't set showtrinkets when loading custom quicksave
Otherwise trinkets could randomly show up on the minimap when levels
don't want them to.
2020-06-30 16:30:09 -04:00
Misa
15e10af08e Display trinkets on the minimap in custommode
I don't really like how copy-pasted the minimap rendering code is, but
whatever. We can refactor it later.
2020-06-30 16:30:09 -04:00
Misa
9e9b1b3c6d Scan for trinkets and put them into shinytrinkets in customs
For showtrinkets() to work, we'll need the correct map data in custom
levels.
2020-06-30 16:30:09 -04:00
Misa
3f7ed4b94a Don't selectively undraw tiles in towers if backgrounds are off
The game for some reason had this thing where it would not draw the
diagonal background tiles if you had animated backgrounds turned off.
Which is weird, because spikes with that background are still drawn as
spikes with that background. And also, it doesn't do this for any of the
tower hallway rooms, which is inconsistent.

Better to simplify the logic in Render.cpp anyways by removing
graphics.drawtower_nobackground() and making it really clear what
exactly we'll do if backgrounds are turned off. ("Aren't we already not
drawing the background? What's this _nobackground() function for?")
2020-06-30 14:34:42 -04:00
Misa
2c18d28880 Add Flip Mode to game options if in M&P or in-game menu and unlocked
Flip Mode will now be in the game options menu if either:
 (1) You're playing the M&P version.
 (2) You have it unlocked and you came here from the in-game pause
     screen.

This is because if you're playing M&P, you'd have to close the game,
edit unlock.vvv, and re-launch the game to toggle Flip Mode, since
there's no other way to do so. And if you're playing the full version,
you'd have to save and exit your session in order to toggle Flip Mode.
2020-06-30 09:21:25 -04:00
Misa
7ce4f1173d Add "resize to nearest" graphics option
If you want your game window to simply be exactly 320x240, or 640x480,
or 960x720 etc. then it's really annoying that there's no easy way to do
this (to clarify, this is different from integer mode, which controls
the size of the game INSIDE the window). The easiest way would be having
to close the game, go into unlock.vvv, and edit the window size
manually. VCE has a 1x/2x/3x/4x graphics option to solve this, although
it does not account for actual monitor size (those 1x/2x/3x/4x modes are
all you get, whether or not you have a monitor too small for some of
them or too big for any of them to be what you want).

I discussed this with flibit, and he said that VCE's approach (if it
accounted for monitor size) wouldn't work on high-retina displays or
high DPIs, because getting the actual multiplier to account for those
monitors is kind of a pain. So the next best thing would be to add an
option that resizes to the nearest perfect multiple of 320x240. That way
you could simply resize the window and let the game correct any
imperfect dimensions automatically.
2020-06-30 09:21:00 -04:00
Misa
e331abcd7e Fix Alt+Enter Glitch if not in glitchrunner mode
The Alt+Enter Glitch is a funny glitch where if you press any toggle
fullscreen keybind during a cutscene, Viridian will stop moving (if
they're being moved by a walk()) and ACTION will start being held down
for them. Meaning in most cases you can interrupt a walk and flip at the
same time.

This can obviously break cutscenes if a casual just wants to toggle
fullscreen, so I'm fixing it. But it will be unfixed in glitchrunner
mode in case you want to glitch out custom levels (I know I do).

More information on the Alt+Enter Glitch is available here:
https://gitgud.io/infoteddy/vvvvvv-knowledge/blob/master/bugs/bugs.md#the-altenter-glitch
(The page is a bit outdated, some bugs have been fixed in 2.3 already.)
2020-06-30 00:20:03 -04:00
Misa
35c540449e Add being able to disable unfocus pause
It's sometimes unwanted by people, and it's unwanted enough that there
exist instructions to hexedit the binary to remove it (
https://distractionware.com/forum/index.php?topic=3247.0 ).

Fun fact, the unfocus pause didn't exist in 2.0.
2020-06-29 22:59:16 -04:00
Misa
3f077ee56a Don't gray out invincibility/slowdown in intermission
When I re-enabled them for intermissions earlier, I forgot to un-gray
them out.
2020-06-29 22:59:16 -04:00
Ethan Lee
e85d5a8714
Merge pull request #326 from InfoTeddy/general-refactors
Refactor how custom level stats are stored, read, and written
2020-06-29 22:31:03 -04:00
Misa
b9bf2cc1c5 Unindent loadcustomlevelstats from previous commit
Done in a separate commit to reduce diff noise.
2020-06-29 18:47:45 -07:00
Misa
be9c405ddd Use returns and don't have rest of loadcustomlevelstats in an 'else'
This will cut down on unnecessary indentation levels.
2020-06-29 18:44:54 -07:00
Misa
9a008dc77c Refactor how custom level stats are stored, read, and written
There were a few problems with the old way of doing things:

(1) Level stats were an ad-hoc object. Basically, it's an object whose
attributes are stored in separate arrays, instead of being an actual
object with its attributes stored in one array.
(2) Level filenames with pipes in them could cause trouble. This is
because the filename attribute array was stored in the XML by being
separated by pipes.
(3) There was an arbitrary limit of only having 200 level stats, for
whatever reason.

To remedy this issue, I've made a new struct named CustomLevelStat that
is a proper object. The separate attribute arrays have been replaced
with a proper vector, which also doesn't have a size limit.

For compatibility with versions 2.2 and below, I've kept being able to
read the old format. This only happens if the new format doesn't exist.
However, I also WRITE the old format as well, in case you want to go
back to version 2.2 or below for whatever reason. It's slightly
wasteful to have both, but that way there's no risk of breaking
compatibility.
2020-06-29 18:39:22 -07:00
Ethan Lee
38a42b484d
Merge pull request #322 from Dav999-v/auto-center-menu
Make menus automatically centered and narrowed
2020-06-29 19:10:39 -04:00
Misa
f64e9237c4 Display centiseconds on time trial result and Game Complete
Centiseconds won't be saved to any save file or anything. This is just
to make speedrunning a bit more competitive, being able to know the
precise time of a time trial or full game run.

The time trial par time on the result screen always has ".99" after it.
This is basically due to the game comparing the number of seconds to the
par number of seconds using less-than-or-equal-to instead of simply
less-than.
2020-06-29 19:09:11 -04:00
Misa
ad27a5c154 Reset width of player in mapclass::resetplayer()
The width of the player can be changed by using the Gravitron OoB
glitch. It will not be reset if the game is in glitchrunner mode.
2020-06-29 19:08:22 -04:00
Misa
66d19d4cf4 Disable two-frame delay fix in glitchrunner mode
The two-frame delay can be utilized to trigger a glitch that spawns
entities in the wrong room.
2020-06-29 19:08:22 -04:00
Misa
d4592cd6b3 Add special case to color gray Warp Zone entities gray
The only reason why gray Warp Zone entities were green originally was
because there is a giant concatenated list of tileset+tilecol
combinations, and by using tileset 3 tilecol 6 you're using the entry
of tileset 4 tilecol 0, which is the green Ship tileset.

So without interfering with the green Ship tileset's entry, I've decided
that the best thing to do is to just add special cases. The enemy color
was easy enough to fix. The platform color was also easy to fix.
However, there exist no existing textures for gray conveyors, so at that
point I decided to just tint the existing green one gray, and then I did
the same for platforms.
2020-06-29 19:07:45 -04:00
Misa
584f73f0a4 Add BlitSurfaceTinted()
This will be used to change the color of existing textures while
preserving their lightness values.
2020-06-29 19:07:45 -04:00
Dav999-v
cc538a0965 Merge remote-tracking branch 'upstream/master' into auto-center-menu
Fix one conflict.
2020-06-29 23:40:10 +02:00
Dav999-v
803d0f45de Document menu width limit better
The reason for the menu width to be limited to 272 pixels was rather
undocumented in the code, now the comment explains more about it.
2020-06-29 23:18:33 +02:00
Misa
ebd381c228 Fix the two-frame-delay when entering a room with an "init" script
This patch is very kludge-y, but at least it fixes a semi-noticeable
visual issue in custom levels that use internal scripts to spawn
entities when loading a room.

Basically, the problem here is that when the game checks for script
boxes and sets newscript, newscript has already been processed for that
frame, and when the game does load a script, script.run() has already
been processed for that frame.

That issue can be fixed, but it turns out that due to my over-30-FPS
game loop changes, there's now ANOTHER visible frame of delay between
room load and entity creation, because the render function gets called
in between the script being loaded at the end of gamelogic() and the
script actually getting run.

So... I have to temporary move script.run() to the end of gamelogic()
(in map.twoframedelayfix()), and make sure it doesn't get run next
frame, because double-evaluations are bad. To do that, I have to
introduce the kludge variable script.dontrunnextframe, which does
exactly as it says.

And with all that work, the two-frame (now three-frame) delay is fixed.
2020-06-29 15:42:51 -04:00
Misa
baf879d9fd Remove unused tmap vars from mapclass
These used to be relevant when the main game tilemaps were stored in
strings, but now they no longer are.
2020-06-29 15:42:51 -04:00
Misa
e1a114d1a5 Un-fix hitbox persistence in map.resetplayer()
It's annoying for casuals to have to close the game if they manage to
get themselves to turn into VVVVVV-Man, but it's amusing enough to
glitchrunners that they mess about with VVVVVV-Man in the main game,
clipping through walls everywhere (well, they call it Big Viridian, but
still).
2020-06-29 15:12:35 -04:00
Misa
387ee4dc79 Un-hardreset certain variables for glitchrunner mode
Ironically enough, resetting more variables in script.hardreset() makes
the glitchy fadeout system even more glitchy. Resetting map.towermode,
for example, makes it so that if you're in towers when you quit to the
menu, script.hardreset() makes it so that the game thinks you're no
longer inbounds (because it no longer thinks you're in a tower and thus
considers coordinates in the space of 40x30 tiles to be inbounds instead
of 40x700 or 40x100 tiles to be inbounds), calls map.gotoroom(), which
resets the gamestate to 0. So if we're using the old system, it's better
to reset only as much as needed.

And furthermore, we shouldn't be relying on script.hardreset() to
initialize variables for us. That should be done at the class
constructor level. So I've gone ahead and initialized the variables in
class constructors, too.
2020-06-29 15:12:35 -04:00
Misa
cb8540d7bd Restore janky gamestate-based quit-to-title system in glitchrunnermode
This was fixed in 2.3 because one of the side effects of this janky
system was being able to accidentally immediately quit to the title if
the screen was black during a cutscene, which is something very likely
to happen to casual players.

Anyway, credits warp uses this gamestate-based system because it
utilizes quitting to the title screen doing gamestate 80. From there,
you increment the gamestate to gamestate 94 to use the Space Station 2
expo script.
2020-06-29 15:12:35 -04:00
Misa
9bab6bd0cb Don't hardreset() game.advancetext in glitchrunner mode
This is the second part of what is necessary for credits warp to work.

The speedrunners call this "text storage". You need to get the
advancetext prompt up without a text box in order to be able to
increment the gamestate without bound. In 2.0, script.hardreset() reset
the text boxes, but not the prompt.
2020-06-29 15:12:35 -04:00
Misa
5848330e66 Re-enable unbounded gamestate increment in glitchrunner mode
This is the first part of what is necessary for credits warp to work.

If the "- Press ACTION to advance text -" prompt is up, and you manage
to keep it up, then you can indefinitely increment the gamestate by
pressing ACTION.

This is first used in credits warp to teleport to the start of Space
Station 2 (by utilizing the Eurogame expo script, triggered by a
gamestate), and then again later by using a teleporter that has a high
gamestate number to increment to the [C[C[C[C[Captain!] cutscene.
2020-06-29 15:12:35 -04:00
Misa
779083b417 Add glitchrunner mode, in game options
Glitchrunner mode is intended to re-enable glitches that existed in
older versions of VVVVVV. These glitches were removed because they could
legitimately affect a casual player's experience. Glitches like various
R-pressing screwery, Space Station 1 skip, telejumping, Gravitron
out-of-bounds, etc. will not be patched.
2020-06-29 15:12:35 -04:00
Dav999-v
46d5fc6576 Correct minimum horizontal spacing check
It should've checked the final spacing and not the intermediate maximum
value. I had changed some things around, and now the minimum spacing
was 5 instead of 0 by mistake.
2020-06-29 02:58:38 +02:00
Dav999-v
0023c821db Make menus automatically centered and narrowed
All menus had a hardcoded X position (offset to an arbitrary starting
point of 110) and a hardcoded horizontal spacing for the "staircasing"
(mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or
something else). Not all menus were centered, and seem to have been
manually made narrower (with lower horizontal spacing) whenever text
ran offscreen during development.

This system may already be hard to work with in an English-only menu
system, since you may need to adjust horizontal spacing or positioning
when adding an option. The main reason I made this change is that it's
even less optimal when menu options have to be translated, since
maximum string lengths are hard to determine, and it's easy to have
menu options running offscreen, especially when not all menus are
checked for all languages and when options could be added in the middle
of a menu after translations of that menu are already checked.

Now, menus are automatically centered based on their options, and they
are automatically made narrower if they won't fit with the default
horizontal spacing of 30 pixels (with some padding). The game.menuxoff
variable for the menu X position is now also offset to 0 instead of 110

The _default_ horizontal spacing can be changed on a per-menu basis,
and most menus (not all) which already had a narrower spacing set,
retain that as a maximum spacing, simply because they looked odd with
30 pixels of spacing (especially the main menu). They will be made even
narrower automatically if needed. In the most extreme case, the spacing
can go down to 0 and options will be displayed right below each other.
This isn't in the usual style of the game, but at least we did the best
we could to prevent options running offscreen.

The only exception to automatic menu centering and narrowing is the
list of player levels, because it's a special case and existing
behavior would be better than automatic centering there.
2020-06-29 02:09:52 +02:00
Misa
18b34d0066 Add logs if a Graphics func was stopped from indexing OoB
This doesn't happen too often, but it'll be useful to people making
custom levels so they know that it can happen, when it does.
2020-06-28 15:48:48 -04:00
Misa
c95c1ab250 Add bounds check to textbox functions that use m
It seems to be a bit bad to blindly use `m` without checking it. In
fact, this has caused a few segfaults already, actually.
2020-06-28 15:48:48 -04:00
Misa
a0f10d80e5 Refactor, de-duplicate, and clean up tilesheet processing
The tilesheets in question are font.png, tiles.png, tiles2.png,
tiles3.png, entcolours.png, teleporter.png, sprites.png, and
flipsprites.png.

This patch removes the hardcoded dimensions when scanning the
tilesheets, because it's simpler that way. It also de-duplicates it so
it isn't a bunch of copy-paste, by using macros. (I had to use macros
because it was the easiest way to optionally pass in some extra code in
the innermost for-loop.)

Also, if the dimensions of a scanned tilesheet aren't exactly multiples
of the dimensions of the tile unit for that given tilesheet (e.g. if the
dimensions of a scanned tiles.png are not exact multiples of 8), then an
SDL_SimpleMessageBox will show up with the error message, a puts() of
the error message will be called, and the program will exit.
2020-06-28 08:44:35 -04:00
Misa
7627a37216 Change a '||' to a '=='
Whoops.
2020-06-28 08:41:19 -04:00
Misa
9363cf4c40 Fix Game::anything_unlocked() always evaluating to true
Whoops.
2020-06-28 08:41:00 -04:00
Misa
22738cdb97 Remove unused/useless vars music.custompd/musicfade(in)/volume
I have no idea why these are here, but it'll simplify readability and
reduce the chance of confusion if I remove them.
2020-06-27 17:23:07 -04:00
Misa
facb079b35 Fix resumemusic/musicfadein not working
It seems like they were unfinished. This commit makes them properly
work.

When a track is stopped with stopmusic() or musicfadeout(),
resumemusic() will resume from where the track stopped. musicfadein()
does the same but does it with a gradual fade instead of suddenly
playing it at full volume.

I changed several interfaces around for this. First, setting currentsong
to -1 when music is stopped is handled in the hook callback that gets
called by SDL_mixer whenever the music stops. Otherwise, it'd be
problematic if currentsong was set to -1 when the song starts fading out
instead of when the song actually ends.

Also, music.play() has a few optional arguments now, to reduce the
copying-and-pasting of music code.

Lastly, we have to roll our own tracker of music length by using
SDL_GetPerformanceCounter(), because there's no way to get the music
position if a song fades out. (We could implicitly keep the music
position if we abruptly stopped the song using Mix_PauseMusic(), and
resume it using Mix_ResumeMusic(), but ignoring the fact that those two
functions are also used on the unfocus-pause (which, as it turns out, is
basically a non-issue because the unfocus-pause can use some other
functions), there's no equivalent for fading out, i.e. there's no
"fade out and pause when it fully fades out" function in SDL_mixer.) And
then we have to account for the unfocus-pause in our manual tracker.

Other than that, these commands are now fully functional.
2020-06-27 17:23:07 -04:00
Misa
2662cd4d06 Refactor KeyPoll::Poll() to use case-switch statements
Reduces the amount of copy-pasted if-expressions.
2020-06-27 17:23:07 -04:00
Misa
a87ebd2945 Remove unnecessary middleman game.infocus
It does the same thing as key.isActive, so no need to make it a separate
variable.
2020-06-27 17:23:07 -04:00
Misa
5052391f60 Make warpdir only re-draw BG if targeted room is current room
It's unnecessary to re-draw the background if you're modifying the warp
direction of some other room.
2020-06-26 10:22:05 -04:00
Misa
1cbecdda86 Use returntomenu(timetrials) instead of returnmenu in timetrialcomplete3
This fixes a corner case where using gamestate 82 from the editor would
put you in a softlock because it would return to the editor settings
menu, which only functions in EDITORMODE and results in a softlock in
TITLEMODE.
2020-06-25 20:27:51 -04:00
Ethan Lee
9804fbc383 Fix gamecontrollerdb.txt path 2020-06-23 19:08:08 -04:00
Misa
94a67ca0aa Only check Secret Lab/Time Trial/NDM for slowdown if ingame_titlemode
This is already done for invincibility. It's kind of unnecessary, but
it's just to make sure if for some reason in the future variables like
insecretlab/intimetrial/nodeathmode don't get reset when exiting to the
menu.
2020-06-23 15:23:57 -04:00
Misa
a3f171b018 Allow toggling invincibility/slowdown in intermission replays
inspecial() includes being in intermission replays, but it's not
necessary to disable invincibility/slowdown for them.
2020-06-23 15:23:57 -04:00
Misa
65f84b15f4 Fix deltaframe tower BG flicker when exiting menu in H/V warp room
To fix this annoying flicker (which, btw, took me WAY too long to do), I
had to introduce yet another kludge variable to signal that the
horizontal/vertical warp background should be re-initialized on the
pause screen.

I think I could technically keep the 'graphics.backgrounddrawn = false;'
in maplogic() and remove the 'graphics.backgrounddrawn = false;' in
Game::returntopausemenu(), but I'm keeping that other one around because
it doesn't hurt and just as a general precaution and safety measure.
2020-06-23 15:23:57 -04:00
Misa
16ebb807db Set backgrounddrawn to false when returning to pause menu
This makes it so the tower background doesn't persist and scroll upwards
if you exit the menu in a warp zone horizontal or vertical room.

Ugh, and while we're on the subject of separating the in-game tower
background and the menu tower background, could we PLEASE separate the
horizontal / vertical warp backgrounds from the tower backgrounds, too?!
2020-06-23 15:23:57 -04:00
Misa
441e7babd7 Fix Flip Mode persisting in in-game options menu
Now graphics.flipmode is turned off when going into the menu, and turned
back on if necessary when exiting.
2020-06-23 15:23:57 -04:00
Misa
c5a5589ce5 Allow pressing Esc to close Esc menu
Another thing that's annoyed me a lot is being unable to simply press
Esc to close the pause menu. You'd have to hover over the "return to
game" or "keep playing" option. This would be even more annoying with
more options on the menu, so allowing to press Esc is a nice
quality-of-life thing.
2020-06-23 15:23:57 -04:00
Misa
f6d73c62ec Allow pressing Esc to go back to pause menu from quit prompt
Allowing for more actions makes things feel smoother.
2020-06-23 15:23:57 -04:00
Misa
b63347b70c Prevent menu input if fading out
Otherwise you could keep re-pressing ACTION on the "yes" option and keep
stalling it until it finally faded out, or quickly go back past menu
options or something.
2020-06-23 15:23:57 -04:00
Misa
3c5ed04678 Make "no, keep playing" go back to pause menu
This is so the menus can stack on top of each other. Well, technically
they don't, but it's the same thing.
2020-06-23 15:23:57 -04:00
Misa
f6330c57fd Reset map.bypos when entering options menus in-game
Otherwise the menu background would have this rendering glitch where the
bypos of the in-game tower wouldn't divide easily and have a bunch of
jitters in an otherwise smooth but overall still somewhat smooth
background.
2020-06-23 15:23:57 -04:00
Misa
ccd6cfab7f Round map.colstate to nearest 5 when entering options menus
Also set map.tdrawback to true when leaving the menu.

This is to fix the interpolated color of the tower background
persisting, as well as making sure the menu background doesn't persist
when exiting.
2020-06-23 15:23:57 -04:00
Misa
8ed9ee1ca2 Fix Graphics::map_option() not uppercasing selected text
Forgot to do this earlier, whoops.
2020-06-23 15:23:57 -04:00
Misa
8c4b48fbfd Fix toggling MMMMMM always playing Presenting VVVVVV
This would be fine, under the assumption that you could never reach the
menu from outside the menu. Well, now you can, so now this has to play
the correct song instead of track 6.
2020-06-23 15:23:57 -04:00
Misa
caa4f0f5c9 Prevent turning on invincibility/slowdown in in-game options menu
Would've been the easiest exploit ever! But I gotta patch it.
2020-06-23 15:23:57 -04:00
Misa
a476121432 Make pressing Esc in ingame_titlemode go back to pause menu
You shouldn't be able to bring up the youwannaquit menu while you're
in-game, that should only be when you're actually not in game.
2020-06-23 15:23:57 -04:00
Misa
aa40eb6327 Move returning to pause menu code to separate function
This code is getting a bit more complicated now, we should maybe stop
copy-pasting it everywhere.
2020-06-23 15:23:57 -04:00
Misa
6582801dc9 Save current menu to temp variable when entering options from in-game
This is to pre-emptively prevent piling up stack frames for what I'll be
adding next, which is pressing Esc in the options menu in-game
automatically moving you back to MAPMODE.
2020-06-23 15:23:57 -04:00
Misa
75326ca2ee Save BG vars to temp vars when entering menu and revert them upon exit
Since the exact same tower background is also used on the menu, we need
to save the current state of the background when entering the menu
(before overwriting it), and then put it back when we're done. Maybe we
ought to separate the in-game and menu tower backgrounds...

This also fixes a semi-hilarious bug where you could make Panic Room go
in the other direction by simply going to the options menu in-game.

This is accomplished by adding convenience functions
mapclass::bg_to_kludge() and mapclass::kludge_to_bg().
2020-06-23 15:23:57 -04:00
Misa
46d1e4053e Set map.scrolldir when going to options in-game
This ensures that the background doesn't start scrolling the wrong way
in the menu.
2020-06-23 15:23:57 -04:00
Misa
a46dd32f12 Consolidate common case 32/33 code
If most of the code in the cases is the same, then just consolidate and
de-duplicate them. It's less error-prone this way.
2020-06-23 15:23:57 -04:00
Misa
6d7bff61b2 Make returning from game/graphic options return to MAPMODE
This is so return doesn't just lead back to more TITLEMODE.
2020-06-23 15:23:57 -04:00
Misa
4c5b018f6c Fix delta rendering glitch when going to options from new Esc menu
Well this is a bit annoying. I can call graphics.updatetowerbackground()
just fine, but I have to get at the title color update routine inside
titlelogic(), which is hard-baked in. So I have to pull that code
outside of the function, export it in the header, and then call it when
I transition to TITLEMODE.
2020-06-23 15:23:57 -04:00
Misa
06102e2db3 Make better Esc menu functional
So now the options do what they do. However, I still need to fix the
1-frame glitch when switching to TITLEMODE, as well as make returning
from the menu return back to MAPMODE, as well as making this better menu
integrate seamlessly with the existing menus.
2020-06-23 15:23:57 -04:00
Misa
4274843a4b Use game.inspecial() in mapmenuactionpress()
Apart from covering more cases with the SHIP option, it also makes the
if-guard for case 3 much less noisy on the eyes.
2020-06-23 15:23:57 -04:00
Misa
949e99c950 Use case-switch in mapmenuactionpress()
This prevents from having to repeat 'if (game.menupage == ...)'
everywhere, which makes for more concise code.

I know you're technically supposed to indent the cases surrounded by
if-guards, but I don't think indenting them here would help anything.
I'd only indent it if the 'if' had an 'else', for example. But if it
surrounds the whole case, then there's no need for indentation.
2020-06-23 15:23:57 -04:00
Misa
5717afaa37 Pull the game.press_action conditional out of all the if-statements
No need to repeat yourself if you can just surround the whole thing in
an 'if (game.press_action)' block, which is much easier.
2020-06-23 15:23:57 -04:00
Misa
13cc7b2a4b Unindent mapmenuactionpress()
Done in a separate commit to minimize diff noise.
2020-06-23 15:23:57 -04:00
Misa
55d001b4f6 Move mapinput() ACTION press handling to separate function
It's a bit too much to consolidate all the ACTION press handling into
one function, especially given the increasing amount of indentation
levels.
2020-06-23 15:23:57 -04:00
Misa
92154f4be1 Add start of better Esc menu
It's not functional yet, but here are the options:

    return to game
        quit to menu
            graphic options
                game options
2020-06-23 15:23:57 -04:00
Misa
a402c990bf Add Graphics::map_option()
Similar to Graphics::map_tab(), this ensures that I don't have to
copy-paste printing the map options for every single game.menupage case
I want, and in this case that's a good thing because there'll be 4
game.menupage cases I'll be using.
2020-06-23 15:23:57 -04:00
Misa
b8403ffe1e Use game.inspecial() for special mode checks in maprender()
This basically adds an extra '|| game.inintermission' because it seems
like the original code forgot about that conditional. You can't save in
level replays, so there's no need to say "You will lose any unsaved
progress." in intermission replays.
2020-06-23 15:23:57 -04:00
Misa
6648246662 Fix -playx/y/rx/ry/gc/music looking at wrong argument
In my previous PR, I wrongly assumed that I could just replace the `i`
handling code of those options with an `i++;` at the beginning, and thus
I could put all blocks' `i++;` into ARG_INNER(). Well I was wrong,
because the code was written the original way for a reason, namely that
we still need `i` to point to the -playx/y/rx/ry/gc/music argv so we can
re-compare which argument led us into this code block.
2020-06-21 21:44:02 -04:00
Misa
33aed057ba Add note to README about "compiler quirks" only applying to 2.2
Only the 2.2 version has these problems, so you don't need to worry
about this section when compiling 2.3.
2020-06-21 20:51:04 -04:00
Misa
b66d303540 De-duplicate 'ed.numcrewmates() - game.crewmates()'
Any decent compiler will optimize this so that it's still only two
function calls (or it gets inlined). However, it's still not very
readable, so I've assigned the result to a variable and used that
instead.
2020-06-21 20:50:39 -04:00
Misa
8a110ead34 De-duplicate 'ed.ListOfMetaData[game.playcustomlevel]'
Whoa, that's a long identifier! Better to replace it with something
short, like 'meta', to save on typing and improve readability.
2020-06-21 20:50:39 -04:00
Misa
b480d5e5a9 De-duplicate Flip Mode code for custom levels' CREW page
Instead of copy-pasting everything and changing a few parts, just have
something that handles that tiny part. This reduces the amount of code
size the custom level CREW page takes up by half.
2020-06-21 20:50:39 -04:00
Misa
9d20f754bc Add macro-like inline func FLIP()
This will be used to keep some text positions the same when in Flip
Mode, instead of having to copy and paste code.

This function being at the very top of the file kind of violates
locality, but it has to be done because it can't be a macro.
2020-06-21 20:50:39 -04:00
Misa
6876dbf70c De-duplicate menu tab rendering
Previously, the code to print all tab names was copied to every single
tab, resulting in 12 more superfluous print statements than needed. This
commit uses graphics.map_tab to de-duplicate all the code.
2020-06-21 20:50:39 -04:00
Misa
aa3c1c8053 Add Graphics::map_tab()
This function is useful to de-duplicate all the map page names at the
bottom, which are MAP, CREW/SHIP/GRAV, STATS, and SAVE. If selected, it
will surround the text in square brackets and automatically handle the
positioning.

Shamelessly copy-pasted from Dav999's localization branch.
2020-06-21 20:50:39 -04:00
Misa
8c9c3d3751 Add being able to press Esc to go to quit menu from teleporter menu
It's always been a bit annoying that if you're in the teleporter menu,
you can't press Escape to go to the "Do you want to quit?" menu.
2020-06-21 20:50:06 -04:00
Misa
afd16ebc73 Add puts() if FILESYSTEM_init() fails
Just to be helpful if someone has a failing FILESYSTEM_init(), but
doesn't know that's their issue and keeps wondering why VVVVVV just
exits with code 1.
2020-06-21 20:25:22 -04:00
Misa
9001a68833 De-duplicate and add safety checks to CLI args, fix brace style
The command-line argument parsing code has a lot of copy-paste. This
copy-paste would get even worse if I added safety checks to make sure
you couldn't index argv out-of-bounds by having an argument like
`-renderer` without having anything after it, i.e. you'd be doing the
command `./VVVVVV -renderer`.

Previously, only the playtest arguments (apart from the recently-added
`playassets`) had this safety check, but the message it printed whenever
the safety check failed was always "-playing option requires one
argument" regardless of whatever argument actually failed to be parsed.
So I fixed it so that all arguments actually output the correct
corresponding failed argument instead.

Also, `strcmp(argv[i], <name>) == 0` is really kind of noisy, even if
you understand what it does perfectly well.

So I refactored it with a bunch of macros. ARG() just does the strcmp()
char* comparison, and ARG_INNER() does the safety check and returns 1,
along with printing a message, if the safety check fails.
2020-06-21 20:25:22 -04:00
Misa
93b13cadac Add -playassets command-line option
This is used if you're loading a level file from STDIN. The game needs
to know the actual level assets directory you're referring to, since
when it gets the level from STDIN, it doesn't know the actual filename
of the level.

Fixes #309.
2020-06-21 20:25:22 -04:00
Misa
d45ff4c269 Abstract assets mounting to FileSystemUtils.cpp
The assets mounting code was put directly in editorclass::load(), but
now it's in a neat little function so it can be called from multiple
places without having to call editorclass::load().
2020-06-21 20:25:22 -04:00
Misa
34e89bfcd3 Move endsWith() to UtilityClass.cpp and put it in header file
This ensures that endsWith() can be used outside of editor.cpp.

When leo60228 originally wrote endsWith(), it was static, but I asked
him on Discord just now and he more-or-less confirmed that it's fine if
it's not static. If it was static, it would be confined to
UtilityClass.cpp now instead!
2020-06-21 20:25:22 -04:00
Misa
ed527bc872 Remove unnecessary music.init() from asset mounting code
graphics.reloadresources() already does music.init().
2020-06-21 20:25:22 -04:00
Misa
c6e800db6f Add '#if !defined(NO_EDITOR)' guards around editorinput/render/logic
These functions aren't needed in a NO_EDITOR build, so it's useful to
reduce the binary size this way.
2020-06-19 18:35:03 -04:00
Misa
5c7e869ee7 Work around SDL2 bug where VSync hint only applies on renderer creation
Ugh, this is terrible and stupid and I hate myself for it.

Anyway, since the SDL2 VSync hint only applies when the renderer is
created, we have to re-create the renderer whenever VSync is toggled.
However, this also means we need to re-create m_screenTexture as well,
AND call ResizeScreen() after that or else the letterbox/integer modes
won't be applied.

Unfortunately, this means that in main(), gameScreen.init() will create
a renderer only to be destroyed later by graphics.processVsync().
There's not much we can do about this. Fixing this would require putting
graphics.processVsync() before gameScreen.init(). However, in order to
know whether the user has VSync set, we would have to call
game.loadstats() first, but wait, we can't, because game.loadstats()
mutates gameScreen! Gahhhhhh!!!!

@leo60228 suggested to fix that problem (
https://github.com/TerryCavanagh/VVVVVV/pull/220#issuecomment-624217939
) by adding NULL checks to game.loadstats() and then calling it twice,
but then you're trading wastefully creating a renderer only to be
destroyed, for wastefully opening and parsing unlock.vvv twice instead
of once. In either case, you're doing something twice and wasting work.
2020-06-19 17:44:53 -04:00
Misa
d898597c1e Don't extern gameScreen, use *graphics.screenbuffer instead
Externing gameScreen is just unnecessary. Still a good idea to have it
off the stack, though.
2020-06-19 17:44:53 -04:00
Misa
0cb21f407e Add inline directives to gameloop(), deltaloop(), fixedloop()
This is to make sure that there's no cost splitting up the game loop
into several different functions to increase code readability.
2020-06-19 09:05:48 -04:00
Misa
7640f8cc8f Add NO_CUSTOM_LEVELS guard around EDITORMODE in deltaloop()
Otherwise a NO_CUSTOM_LEVELS build would fail. Also I got rid of the
'graphics.flipmode = false;' in the fixed loop because I don't think it
does anything.
2020-06-19 09:05:48 -04:00
Misa
867e7bc1e6 Move infocus and network updates to fixedloop()
Updating them every delta frame is way too fast.
2020-06-19 09:05:48 -04:00
Misa
acf47bfeac Unindent fixedloop()
If I did it in the previous commit, it would've been too noisy.
2020-06-19 09:05:48 -04:00
Misa
a9f07ccc8f Move fixed loop to its own function
To improve code readability because otherwise the code would be one
giant blob.
2020-06-19 09:05:48 -04:00
Misa
1fbec9c427 Unindent deltaloop()
Doing it in the same commit makes the diffs too noisy...
2020-06-19 09:05:48 -04:00