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

235 Commits

Author SHA1 Message Date
Misa
769f99f590 Reduce dependency on libc functions
During 2.3 development, there's been a gradual shift to using SDL stdlib
functions instead of libc functions, but there are still some libc
functions (or the same libc function but from the STL) in the code.

Well, this patch replaces all the rest of them in one fell swoop.

SDL's stdlib can replace most of these, but its SDL_min() and SDL_max()
are inadequate - they aren't really functions, they're more like macros
with a nasty penchant for double-evaluation. So I just made my own
VVV_min() and VVV_max() functions and placed them in Maths.h instead,
then replaced all the previous usages of min(), max(), std::min(),
std::max(), SDL_min(), and SDL_max() with VVV_min() and VVV_max().

Additionally, there's no SDL_isxdigit(), so I just implemented my own
VVV_isxdigit().

SDL has SDL_malloc() and SDL_free(), but they have some refcounting
built in to them, so in order to use them with LodePNG, I have to
replace the malloc() and free() that LodePNG uses. Which isn't too hard,
I did it in a new file called ThirdPartyDeps.c, and LodePNG is now
compiled with the LODEPNG_NO_COMPILE_ALLOCATORS definition.

Lastly, I also refactored the awful strcpy() and strcat() usages in
PLATFORM_migrateSaveData() to use SDL_snprintf() instead. I know save
migration is getting axed in 2.4, but it still bothers me to have
something like that in the codebase otherwise.

Without further ado, here is the full list of functions that the
codebase now uses:

- SDL_strlcpy() instead of strcpy()
- SDL_strlcat() instead of strcat()
- SDL_snprintf() instead of sprintf(), strcpy(), or strcat() (see above)
- VVV_min() instead of min(), std::min(), or SDL_min()
- VVV_max() instead of max(), std::max(), or SDL_max()
- VVV_isxdigit() instead of isxdigit()
- SDL_strcmp() instead of strcmp()
- SDL_strcasecmp() instead of strcasecmp() or Win32 strcmpi()
- SDL_strstr() instead of strstr()
- SDL_strlen() instead of strlen()
- SDL_sscanf() instead of sscanf()
- SDL_getenv() instead of getenv()
- SDL_malloc() instead of malloc() (replacing in LodePNG as well)
- SDL_free() instead of free() (replacing in LodePNG as well)
2021-01-12 14:02:31 -05:00
Misa
d271907f8c Fix Secret Lab Time Trial trophies having wrong colors
Ever since 2.0, the colors of some of the Time Trial trophies in the
Secret Lab don't correspond to the crewmate of the given level. The
trophy for the Tower uses Victoria's color, and the Lab trophy uses
Vermilion's color. The Space Station 2 trophy uses Viridian's color, and
the Final Level trophy uses Vitellary's color.

This doesn't appear to be intentional, and it would be odd if it was,
since this game matches the colors everywhere else (each zone on the map
is colored with their respective crewmate in mind, for instance). Also,
the Lab trophy has the sad expression, which is Victoria's trait - it
would be weird if this was intended for Vermilion instead.

But the biggest piece of evidence that this was unintentional is the
corresponding comment for each color in Graphics::setcol(). It mislabels
yellow as cyan, cyan as yellow, blue as red, and red as blue.

To fix this, I simply have to set the correct color for each trophy in
case 25 of entityclass::createentity(). I could fix it in
Graphics::setcol() itself, but custom levels might depend on those
certain colors being the way they are, so it's a safer bet to just fix
it in the trophy creation case itself.

The diff of this might look weird. Even though all I'm doing is changing
some value assignments around, it looks like the "patience" algorithm
thinks I'm moving a whole case of the trophy switch-case around.
2021-01-08 15:17:36 -08:00
Misa
54ff36da97 Remove unused function Graphics::textboxmove()
This function was marked as unused by cppcheck.
2021-01-02 09:06:42 -05:00
Misa
ca904a4d7c Remove unused function Graphics::textboxcenter()
This function was marked as unused by cppcheck.
2021-01-02 09:06:42 -05:00
Misa
9b3bf69491 Remove unused function Graphics::drawentcolours()
This function was marked as unused by cppcheck.
2021-01-02 09:06:42 -05:00
Misa
6261fa51e9 Remove unused function Graphics::RPrint()
This function was marked as unused by cppcheck.
2021-01-02 09:06:42 -05:00
Misa
42106cb59a Remove unused function Graphics::PrintOff()
This function was marked as unused by cppcheck.
2021-01-02 09:06:42 -05:00
Misa
3434ad8777 Fix variables shadowing other variables
In C++, when you have two variables in different scopes with the same
name, the inner scope wins. Except you have to be really careful because
sometimes they're not (#507). So it's better to just always have unique
variable names and make sure to never clash a name with a variable in an
outer scope - after all, the C++ compiler and standard might be fine
with it, but that doesn't mean humans can't make mistakes reading or
writing it.

Usually I just renamed the inner variables, but for tx/ty in editor.cpp,
I just got rid of the ridiculous overcomplicated modulo calculations and
replaced them with actual simple modulo calculations, because the
existing ones were just ridiculous. Actually, somebody ought to find
every instance of the overcomplicated modulos and replace them with the
actual good ones, because it's really stupid, quite frankly...
2020-11-04 08:38:19 -05:00
Misa
4570140a6a Fix teleporter sprites sometimes being solid colors
This commit fixes a bug that also sometimes occurred in 2.2, where the
teleporter sprite would randomly turn into a solid color and just be a
solid circle with no detail.

Why did this happen? The short answer is an incorrect lower bound when
clamping the teleporter sprite index in `Graphics::drawtele()`. The long
answer is bad RNG with the teleporter animation code. This commit fixes
the short answer, because I do not want to mess with the long answer.

So, here is what would happen: the teleporter's `tile` would be 6. The
teleporter code decrements its `framedelay` each frame. Then when it
reached a `framedelay` of 0, it would call `fRandom()` and essentially
ask for a random number between 0 and 6. If the RNG ended up being
greater than or equal to 4, then it would set its `walkingframe` to -5.
At the end of the routine, the teleporter's `drawframe` ends up being
its `tile` plus its `walkingframe`. So having a `walkingframe` of -5
here is fine, because its `tile` is 6.

Until it isn't. When its `tile` becomes 2, it still keeps its
`walkingframe` around. The code that runs when its `tile` is 2 does have
the possibility of completely resetting its `walkingframe` to be in
bounds (in bounds after its `tile` is added), but that only runs when
its `framedelay` is 0, and in the meantime it'll just use the previous
`walkingframe`.

So you could have a `walkingframe` of -5, plus a `tile` of 2, which
produces a `drawframe` of -3. Then `Graphics::drawtele()` will clamp
that to 0, which just means it'll draw the teleporter backing, and the
teleporter backing is a simple solid color, so the teleporter will end
up being completely and fully solid.

To fix this, I just made `Graphics::drawtele()` clamp to 1 on the lower
bound, instead of 0. So if it ever gets passed a negative teleporter
index, it'll just draw the normal teleporter sprite instead, which is
better.
2020-11-03 19:12:31 -05:00
Misa
25d00b9ba6 Fix crewmates being drawn behind other entities
This fixes the draw order by drawing all other entities first, before
then drawing all humanoids[1] after, including the player afterwards.

This is actually a regression fix from #191. When I was testing this, I
was thinking about where get a crewmate in front of another entity in
the main game, other than the checkpoints in Intermission 1. And then I
thought about the teleporters, because I remember the pre-Deep Space
cutscene in Dimension Open looking funny because Vita ended up being
behind the teleporter. (Actually, a lot of the cutscenes of Dimension
Open look funny because of crewmates standing behind terminals.)

So then I tried to get crewmates in front of teleporters. It actually
turns out that you can't do it for most of them... except for Verdigris.
And then that's what I realized why there was an oddity in WarpClass.cpp
when I was removing the `active` system from the game - for some reason,
the game put a hole in `obj.entities` between the teleporter and the
player when loading the room Murdering Twinmaker. In a violation of
Chesterton's Fence (the principle that you should understand something
before removing it), I shrugged it off and decided "there's no way to
support having holes with my new system, and having holes is probably
bad anyway, so I'm going to remove this and move on". The fact that
there wasn't any comments clarifying the mysterious code didn't help
(but, this *was* 2.2 code after all; have you *seen* 2.2 code?!).

And it turns out that this maneuver was done so Verdigris would fill
that hole when he got created, and Verdigris being first before the
teleporter would mean he would be drawn in front of the teleporter,
instead of being behind it. So ever since
b1b1474b7b got merged, there has actually
been a regression from 2.2 where Verdigris got drawn behind the
teleporter in Murdering Twinmaker, instead of properly being in front of
it like in 2.2 and previous.

This patch fixes that regression, but it actually properly fixes it
instead of hacking around with the `active` system.

Closes #426.

[1]: I'm going to go on a rant here, so hear me out. It's not explicitly
stated that the characters in VVVVVV are human. So, given this
information, what do we call them? Well, the VVVVVV community (at least
the custom levels one, I don't think the speedrunning community does
this or is preoccupied with lore in the first place) decided to call
them "villis", because of the roomname "The Villi People" - which is
only one blunder in a series of awful headcanons based off of the
assumption that the intent of Bennett Foddy (who named the roomnames)
was to decree some sort of lore to the game. Another one being
"Verdigris can't flip" because of "Green Dudes Can't Flip". Then an OC
(original character) got named based off of "The Voon Show" too. And so
on and so forth.
2020-11-03 13:31:56 -05:00
Misa
d05fbe8687 Unindent drawentity() from previous commit
This unindent is done in a separate commit to minimize diff noise.
2020-11-03 13:31:56 -05:00
Misa
e809cc0615 Factor out entity drawing to separate function
This makes it easy to re-use without duplicating code.
2020-11-03 13:31:56 -05:00
Misa
fd53278163 Add bounds check to drawgravityline()
I noticed that this function didn't have a bounds check, so I added one.
Just in case.
2020-11-03 13:31:56 -05:00
Misa
081030fb2f Make some variables const in drawentities()
I'm going to refactor drawing an entity out to a separate function, and
since I'm going to do that, I might as well make some things const to
clarify intent first and foremost and possibly improve performance or
compiler optimization.
2020-11-03 13:31:56 -05:00
Misa
688b23b85d Standardize on using reference to tilesvec/spritesvec instead of pointer
This cleans up the code readability a bit, as it's nicer to use
reference syntax when indexing an array instead of that ugly pointer
syntax.
2020-11-03 13:31:56 -05:00
Misa
bda92ad0bd Move horizontal/vertical warp backgrounds to separate buffers
Instead of using the same tower buffer that gets used for towers, use a
separate buffer instead so there's no risk of stepping on the tower
buffer's toes at the wrong point in time.

This commit combined with the previous one fixes #369.
2020-11-03 13:25:03 -05:00
Misa
70f3d457dd Move title usages of towerbg to titlebg
With the previous commit in place, we can now simply move some usages of
the previous towerbg to use a separate object instead. That way, we
don't have to mess with a monolithic state, or some better way to phrase
what I just said, and we instead have two separate objects that can
coexist side-by-side.
2020-11-03 13:25:03 -05:00
Misa
72c048d71e Refactor tower background to use a separate object instead
Previously, the tower background was controlled by a disparate set of
attributes on Graphics and mapclass, and wasn't really encapsulated. (If
that's what that word means, I don't particularly care about
object-oriented lingo.) But now, all relevant things that a tower
background has has been put into a TowerBG struct, so it will be easy to
make multiple copies without having to duplicate the code that handles
it.
2020-11-03 13:25:03 -05:00
Misa
20e02f014b Move temporary bcol/bcol2 off of Graphics
Looks like I had missed yet another two temporary variables that were
actually globals on the Graphics class. Glad I caught these ones.
2020-11-02 16:05:52 -05:00
Misa
25ae117f6a Remove unused attribute Graphics::tl
For some reason, this `tl` is a `point`? But the only other time the
name `tl` is used elsewhere in the code is a float on a `textboxclass`.
Regardless, this is unused.
2020-11-02 16:05:52 -05:00
Misa
f847ec7c59 Fix tower background interpolation when scrolling from top
On the deltaframes of the tower background, there would be "pixel bleed"
if the tower background would be scrolling from the top. This is because
there wouldn't be any more pixels from above the screen to grab, because
the background rendering functions didn't draw any pixels above the
screen. But they couldn't draw any pixels above the screen, because that
was simply the end of the buffer. But now that the buffer is expanded,
we can now draw above the screen, and fix this glitchy interpolation
rendering.
2020-11-02 14:02:00 -05:00
Misa
b98c99fd7a Add 8 pixels of padding above and left of towerbuffer[_lerp]
In order to fix the weird title screen pixels at the top on deltaframes,
we'll need to have a bit more space at the top. Also to the left, in
case we need a background to scroll from the left in the future.
2020-11-02 14:02:00 -05:00
Misa
c590c4b436 Reload window icon when mounting and unmounting assets
The window icon is simply another asset that can be customized by level
makers. And in fact, one of my levels changes the window icon. It's
simply named VVVVVV.png, but it doesn't sit in the graphics folder,
rather it sits in the root VVVVVV directory.

I noticed that this asset was missed when per-level assets loading was
added, so I decided to add it in.

There's a NULL check on screenbuffer because reloadresources() gets
called before screenbuffer's init() does.
2020-11-01 13:59:13 -05:00
Misa
b8a4b4dfe7 Restore previous oldxp/oldyp variables in favor of lerpoldxp/lerpoldyp
I was investigating a desync in my Nova TAS, and it turns out that
the gravity line collision functions check for the `oldxp` and `oldyp`
of the player, i.e. their position on the previous frame, along with
their position on the current frame. So, if the player either collided
with the gravity line last frame or this frame, then the player collided
with the gravity line this frame.

Except, that's not actually true. It turns out that `oldxp` and `oldyp`
don't necessarily always correspond to the `xp` and `yp` of the player
on the previous frame. It turns out that your `oldyp` will be updated if
you stand on a vertically moving platform, before the gravity line
collision function gets ran. So, if you were colliding with a gravity
line on the previous frame, but you got moved out of there by a
vertically moving platform, then you just don't collide with the gravity
line at all.

However, this behavior changed in 2.3 after my over-30-FPS patch got
merged (#220). That patch took advantage of the existing `oldxp` and
`oldyp` entity attributes, and uses them to interpolate their positions
during rendering to make everything look real smooth.

Previously, `oldxp` and `oldyp` would both be updated in
`entityclass::updateentitylogic()`. However, I moved it in that patch to
update right before `gameinput()` in `main.cpp`.

As a result, `oldyp` no longer gets updated whenever the player stands
on a vertically moving platform. This ends up desyncing my TAS.

As expected, updating `oldyp` in `entityclass::movingplatformfix()` (the
function responsible for moving the player whenever they stand on a
vertically moving platform) makes it so that my TAS syncs, but the
visuals are glitchy when standing on a vertically moving platform. And
as much as I'd like to get rid of gravity lines checking for whether
you've collided with them on the previous frame, doing that desyncs my
TAS, too.

In the end, it seems like I should just leave `oldxp` and `oldyp` alone,
and switch to using dedicated variables that are never used in the
physics of the game. So I'm introducing `lerpoldxp` and `lerpoldyp`, and
replacing all instances of using `oldxp` and `oldyp` that my over-30-FPS
patch added, with `lerpoldxp` and `lerpoldyp` instead.

After doing this, and applying #503 as well, my Nova TAS syncs after
some minor but acceptable fixes with Viridian's walkingframe.
2020-10-11 16:19:26 -04:00
Misa
cbceeccf78 Clean up and prevent unnecessary qualifiers to self
By "unnecessary qualifiers to self", I mean something like using the
'game.' qualifier for a variable on the Game class when you're inside a
function on the Game class itself. This patch is to enforce consistency
as most of the code doesn't have these unnecessary qualifiers.

To prevent further unnecessary qualifiers to self, I made it so the
extern in each header file can be omitted by using a define. That way,
if someone writes something referring to 'game.' on a Game function,
there will be a compile error.

However, if you really need to have a reference to the global name, and
you're within the same .cpp file as the implementation of that object,
you can just do the extern at the function-level. A good example of this
is editorinput()/editorrender()/editorlogic() in editor.cpp. In my
opinion, they should probably be split off into their own separate file
because editor.cpp is getting way too big, but this will do for now.
2020-09-28 01:34:40 -04:00
Misa
990ee63a6e Fix brace style in Graphics::Makebfont() and Graphics::bfontlen()
Seriously, Leo, why did you have to use braces like this...
2020-09-25 16:33:54 -04:00
Misa
2e78eab92f Clear font_positions if there is no font.txt
This fixes a bug where font_positions wouldn't get cleared after exiting
a custom level that had a font.txt if it didn't exist in the default
graphics, leading to messed-up-looking font rendering.

This bug was originally discovered by Ally.
2020-09-25 16:33:54 -04:00
Misa
140861a79d Add bounds checks to both versions of Graphics::drawsprite()
For some reason, I forgot to add bounds checks to these functions. Well,
I'm glad I caught it, anyways.
2020-09-25 13:51:47 -04:00
Misa
f02dcbfdad Don't manually write out INBOUNDS_ARR() checks
When this is done, there is potential for a mistake to occur when
writing out the bounds check, which is eliminated when using the macro
instead. Luckily, this doesn't seem to have happened, but what's even
worse is I hardcoded 400 instead of using SDL_arraysize(ed.level), so if
the size of ed.level the bounds checks would all be wrong, which
wouldn't be good. But that's fixed now, too.
2020-09-25 13:51:47 -04:00
Misa
7ed495c373 Rename INBOUNDS() macro to INBOUNDS_VEC()
Since there's an INBOUNDS_ARR() macro, it's much better to specify the
macro for the vector is a macro for the vector, to avoid confusion.

All usages of this macro have been renamed accordingly.
2020-09-25 13:51:47 -04:00
Misa
e01efbec89 Remove tzann's trailing whitespace from Graphics.cpp
This trailing whitespace was introduced by tzann in commit
8aac6a758d. It might be because he used
Visual Studio.
2020-09-25 13:30:59 -04:00
Misa
1a3577e196 Add kludge to fix rendering of gravity lines in a gotoroom
Due to #464, standing inside a gravity line during a gotoroom that
occurs every frame will end up with the gravity line being gray instead
of being white. To temporarily fix this (until #464 is properly fixed),
I decided to add some kludge that colors it white if its onentity is 1.
I tested this patch with gravity lines in both constant-gotoroom and
normal environments, and it seems to be fine for both.
2020-09-25 13:30:59 -04:00
Misa
42010f8f42 Fix default Graphics::setcol() value having no alpha
This patch fixes a regression caused by commit
6b1a7ebce6.

When you spawn a crewmate with an invalid color, by doing something like
`createentity(100,100,18,-1,0)` (here the color is -1, which is
invalid), a white crewmate with the color of solid white (255, 255, 255)
would appear.

That is, until AllyTally came along and committed commit
6b1a7ebce6 (Make "[Press ENTER to
return to editor]" fade out after a bit) (PR #158). Then after that
commit, it would seem like the crewmate didn't appear, but in reality
they were just invisible, because they had an invisible color.

As part of Ally's changes, to properly support drawing text with a
certain amount of alpha, she made BlitSurfaceColoured() account for the
alpha of the color given instead of only caring about the RGB of the
color, discarding the alpha, and using the alpha of the surface it was
drawing instead. This effectively made it so the alpha of whatever it
was drawing would be 255 all the time, except for if you had custom
textures and your custom textures had translucent pixels.

However, the default color set by Graphics::setcol() if you didn't
provide a valid color index was 0xFFFFFF. Which is only (255, 255, 255)
but ends up having an alpha value of 0 (because it's actually
0x00FFFFFF). And all colors drawn with alpha 0 end up being drawn with
alpha 0 after 6b1a7ebce6. So
invalid-colored entities will end up being invisible.

To fix this, I just decided to add alpha to the default value instead.
In addition, I used getRGB() to be consistent with all the other colors
in the function.
2020-09-17 10:13:46 -04:00
Misa
90150a9fad Use clamp() macro to clamp colors in Graphics::bigrprint()
All other graphics functions use this macro instead of writing out the
clamping manually, so this one should, too.
2020-09-08 16:15:50 -04:00
Misa
efc9d4ea80 Remove duplicate color-clamping code from Graphics::bigrprint()
For some reason, there's some color-clamping code in this function
directly after already-existing color-clamping code. This code dates
back to 2.2. And also, there's a smaller lower-bound of -1 for the red
channel, despite the fact that this smaller value doesn't matter because
the red would get clamped to 0 by the first code anyway.

So even if this was put here for some strange reason, it doesn't matter
because it doesn't do anything anyway.
2020-09-08 16:15:50 -04:00
Misa
43cf3c4f19 Remove allowspecial, replace with opaqueness check
When I added the over-30-FPS mode, I kept running into this problem
where the special images of text boxes would render during the
deltaframes of fade-in/fade-out animations, even though they shouldn't
be. So I simply added a flag to the text box that enables drawing these
special images.

However, this doesn't solve the problem fully, and there's still a small
chance that a special-image text box could draw another special image
during its deltaframes. It's really rare and you have to have your
deltaframe luck juuuuuust right (or you could use libTAS, probably), but
it helps to be in 40% slowmode and have a high refresh rate (which, if
it isn't a multiple of 30, you should disable VSync, too, in order to
not have a low framerate).

So instead, special images will only be drawn if the text box has fully
faded in completely. That solves the issue completely.
2020-08-06 22:12:15 -04:00
Misa
5f776faba7 Ax ScaleSurfaceSlow() in favor of ScaleSurface()
ScaleSurfaceSlow() uses DrawPixel() instead of SDL_FillRect() to scale a
given surface, which is slow and inefficient, and makes it less likely
that the game could be moved to SDL_Render.

Unfortunately, it has this weird -1,-1 offset, but that will be fixed in
the next commit.
2020-08-06 22:10:47 -04:00
Misa
57dca99a4e Ax OverlaySurfaceKeyed(), set proper foregroundBuffer blend mode
So, earlier in the development of 2.0, Simon Roth (I presume)
encountered a problem: Oh no, all my backgrounds aren't appearing! And
this is because my foregroundBuffer, which contains all the drawn tiles,
is drawing complete black over it!

So he had a solution that seems ingenius, but is actually really really
hacky and super 100% NOT the proper solution. Just, take the
foregroundBuffer, iterate over each pixel, and DON'T draw any pixel
that's 0xDEADBEEF. 0xDEADBEEF is a special signal meaning "don't draw
this pixel". It is called a 'key'.

Unfortunately, this causes a bug where translucent pixels on tiles
(pixels between 0% and 100% opacity) didn't get drawn correctly. They
would be drawn against this weird blue color.

Now, in #103, I came across this weird constant and decided "hey, this
looks awfully like that weird blue color I came across, maybe if I set
it to 0x00000000, i.e. complete and transparent black, the issue will be
fixed". And it DID appear to be fixed. However, I didn't look too
closely, nor did I test it that much, and all that ended up doing was
drawing the pixels against black, which more subtly disguised the
problem with translucent pixels.

So, after some investigation, I noticed that BlitSurfaceColoured() was
drawing translucent pixels just fine. And I thought at the time that
there was something wrong with BlitSurfaceStandard(), or something.
Further along later I realized that all drawn tiles were passing through
this weird OverlaySurfaceKeyed() function. And removing it in favor of a
straight SDL_BlitSurface() produced the bug I mentioned above: Oh no,
all the backgrounds don't show up, because my foregroundBuffer is
drawing pure black over them!

Well... just... set the proper blend mode for foregroundBuffer. It
should be SDL_BLENDMODE_BLEND instead of SDL_BLENDMODE_NONE.

Then you don't have to worry about your transparency at all. If you did
it right, you won't have to resort this hacky color-keying business.

*sigh*
2020-08-06 22:10:30 -04:00
Misa
5de6f22175 Use SDL_max/min instead of std::max/min in Graphics::Hitest()
In an effort to reduce STL usage, this should be done.
2020-08-04 15:59:21 -04:00
Misa
2d71881321 Clean up superfluous no-intersection return logic
It's not necessary to say 'return false' twice.
2020-08-04 15:59:21 -04:00
Misa
627e971e90 Remove unnecessary intersectRect() function
This function checked the intersection of rectangles, but it used floats
for some reason when its only caller used ints. There's already an
intersection function (UtilityClass::intersects()), so we should be
using that one instead in order to minimize code duplication.

Graphics::Hitest() is used for per-pixel collision detection, directly
checking the pixels of both entities' sprites. I checked with one of my
TASes and it still syncs, so I'm pretty sure this won't cause any
issues.
2020-08-04 15:59:21 -04:00
Misa
154e81292e Crop bottom tower spikes so they don't get drawn behind room name
If you have the translucent room name option enabled, you'd always be
seeing the spikes at the bottom of the screen hidden behind the room
name. This patch makes it so that the spikes get carefully cropped so
they only appear above the room name when the player gets close to the
bottom of the screen.
2020-08-04 00:06:45 -04:00
Misa
f544e95e85 Fix INBOUNDS() check for Graphics::drawtile3()
The function was not actually checking the number that would end up
being used to index the tiles3 vector, and as a result there could
potentially be out-of-bounds indexing. But this is fixed now.
2020-08-03 22:42:21 -04:00
Tynan Richards
8aac6a758d
Wrap entities (#408)
Make entities able to wrap both vertically and horizontally, also add a case for when entities are wrapping both directions at the same time
2020-07-29 12:17:28 -04:00
Misa
52f7a587fe Separate includes into sections and alphabetize them
Okay, so basically here's the include layout that this game now
consistently uses:

[The "main" header file, if any (e.g. Graphics.h for Graphics.cpp)]
[blank line]
[All system includes, such as tinyxml2/physfs/utfcpp/SDL]
[blank line]
[All project includes, such as Game.h/Entity.h/etc.]

And if applicable, another blank line, and then some special-case
include screwy stuff (take a look at editor.cpp or FileSystemUtils.cpp,
for example, they have ifdefs and defines with their includes).
2020-07-19 21:37:40 -04:00
Misa
b5ff65c84e Remove unnecessary includes from header files
Including a header file inside another header file means a bunch of
files are going to be unnecessarily recompiled whenever that inner
header file is changed. So I minimized the amount of header files
included in a header file, and only included the ones that were
necessary (system includes don't count, I'm only talking about includes
from within this project). Then the includes are only in the .cpp files
themselves.

This also minimizes problems such as a NO_CUSTOM_LEVELS build failing
because some file depended on an include that got included in editor.h,
which is another benefit of removing unnecessary includes from header
files.
2020-07-19 21:37:40 -04:00
Ethan Lee
b302e4dbbb Valgrind warning fix 2020-07-15 12:09:24 -04:00
Misa
3932c75acc Remove unnecessary stub destructors
It's a bit misleading to have these stub destructors when they don't do
anything special.
2020-07-08 19:14:21 -04:00
Misa
7703b2c1c2 Ensure that all member attributes are initialized
I ran the game through cppcheck and it spat out a bunch of member
attributes that weren't being initialized. So I initialized them.

In the previous version of this commit, I added constructors to
GraphicsResources, otherlevelclass, labclass, warpclass, and finalclass,
but flibit says this changes the code flow enough that it's risky to
merge before 2.4, so I got rid of those constructors, too.
2020-07-08 19:14:21 -04:00
Misa
fd0dafc16c De-duplicate Graphics::drawmenu() and Graphics::drawlevelmenu()
Graphics::drawmenu() no longer has copy-pasted code for each individual
case. Instead, the individual cases have their own adding on to common
code, which is far easier to maintain.

Also, the only difference Graphics::drawlevelmenu() does is in some
y-positioning stuff. There's no reason to make it a whole separate
function and duplicate everything AGAIN. So it's been consolidated into
Graphics::drawmenu() as well, and I've added a boolean to draw a menu
this way if it's the level menu.
2020-07-06 11:19:24 -04:00
Misa
8366e08fbe Remove usage of std::string from MenuOption
Instead, the string in MenuOption is just a buffer of 161 chars, which
is 40 chars (160 bytes if each were the largest possible UTF-8 character
size) plus a null terminator. This is because the maximum length of a
menu option that can be fit on the screen without going past is 40
chars.
2020-07-06 11:19:24 -04:00
Misa
5fb0b4396a Remove use of std::transform(), use SDL_toupper/lower
There's no need to use a template here. Just manually call SDL_tolower()
or SDL_toupper() as needed.

Oh yeah, and use SDL_tolower() and SDL_toupper() instead of libc
tolower() and toupper().
2020-07-06 11:19:24 -04:00
Misa
067fbc75f0 Turn fadebars into an array
There's always 15 of them, it doesn't need to be a vector.
2020-07-06 11:19:24 -04:00
Misa
450cf1a31e Turn star and backbox vectors into arrays
There's always 50 stars and always 18 backboxes, there's no reason to
have them be vectors.
2020-07-06 11:19:24 -04:00
Misa
4c6ab6e6b7 Remove unused vars from Graphics/GraphicsResources
These unused vars are:
 - Graphics::bfontmask_rect
 - Graphics::backgrounds
 - Graphics::bfontmask
 - GraphicsResources::im_bfontmask

While it seems that Graphics::backgrounds was indexed in
Graphics::drawbackground(), in reality there was never anything in that
vector and thus actually using it would cause a segfault.
2020-07-06 11:19:24 -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
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
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
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
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
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
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
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
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
8ed9ee1ca2 Fix Graphics::map_option() not uppercasing selected text
Forgot to do this earlier, whoops.
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
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
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
694e8f42ab Add VSync graphics option, off by default
This is if you want delta-timesteps to go as quickly as possible. Also
it seems like on Windows this only has an effect in exclusive fullscreen
mode.
2020-06-19 09:05:48 -04:00
Misa
49fbe18d34 Make sure sprite colors in the editor don't update more than 30 FPS
This adds Graphics::crewcolourreal(), which is like the
entityclass::crewcolour() that the editor already uses, except for the
real color instead of the color ID. Also, editorclass now has an
attribute `entcolreal` so enemy colors don't update more than 30 frames
a second.
2020-06-19 09:05:48 -04:00
Misa
349702c92c Fix flickering when holding down ACTION in credits scroll
The solution is to draw another row of incoming textures. And also just
draw another row of textures when the background needs to be redrawn,
otherwise it'll flicker when the color changes while you're holding down
ACTION.
2020-06-19 09:05:48 -04:00
Misa
1e81aef58a Fix flickering on bottom/right of screen with H/V warp BGs
To fix this, I draw another row/column of incoming textures. But of
course, I have to extend the size of the towerbuffer, otherwise the
incoming textures will just be gone.
2020-06-19 09:05:48 -04:00
Misa
45fecf71b2 Fix overdraw bug in tower background
This could happen if you held down ACTION in the credits, looks like the
background doesn't keep up for some reason. That's another bug to fix,
but at least I can fix this overdraw.
2020-06-19 09:05:48 -04:00
Misa
c289128693 Fix overdraw at bottom/right screen edges with H/V warp BGs
There's still a problem in that the flickering that would lead to this
overdraw in the first place still exists. But at least if it'll flicker,
it'll flicker black and not overdraw.
2020-06-19 09:05:48 -04:00
Misa
93d8220388 Fix off-by-one in interpolation of extending gravity line
Currently it interpolates it based on the current state of game.swngame,
but when game.swngame changes the interpolation doesn't know that it has
JUST changed or anything. So add a kludge variable to fix this
off-by-one.
2020-06-19 09:05:48 -04:00
Misa
4641b53603 Interpolate gravitron top line extending
Otherwise it'll extend at 30 FPS only which would be kind of jarring.
2020-06-19 09:05:48 -04:00
Misa
11803b0229 Fix colors updating too fast in TITLEMODE/MAPMODE/GAMECOMPLETEMODE
These colors were of the colors of each crewmate, the inactive crewmate
color, and the color of the trinket and clock on the quicksave/summary
screens.

These colors all used fRandom() and so kept updating too quickly because
they would be recalculated every time the delta-timestep render function
got called, which isn't ideal. Thus, I've had to add attributes onto the
Graphics class to store these colors and make sure they're only
recalculated in logic functions instead.

Thankfully, the color used for the sprites on the time trial results
screen doesn't use fRandom(), so I don't have to worry about those.

There's a new version of Graphics::drawsprite() that takes in a pre-made
color already, instead of a color ID. As well, I've also added
Graphics::updatetitlecolours() to update these colors on the title
screen.
2020-06-19 09:05:48 -04:00
Misa
3699adec82 Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.

To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.

So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.

At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.

Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.

However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-06-19 09:05:48 -04:00
Misa
4c2d219e45 Move big chunky pixel colors to separate function
Again, to make sure colors don't update more than 1000/34 frames a
second, we'll need to separate this color calculation from rendeirng
functions.
2020-06-19 09:05:48 -04:00
Misa
fce56fde09 Move setcol part of drawhuetile() to separate function
In order to make sure colors don't update more than 1000/34 frames per
second, I'll have to move the color-setting part of this function
somewhere else.
2020-06-19 09:05:48 -04:00
Misa
2e17e872e4 Interpolate spikeleveltop and spikelevelbottom
This doesn't have much effect, except for when the spikes quickly move,
because the spikes only usually move at 1 pixel per frame anyway.
2020-06-19 09:05:48 -04:00
Misa
92c0f93a6f Move finalstretch animation code to gamelogic()
Otherwise, the tile animations will go too fast. However, the overall
color cycling hasn't been going fast, since it was never in gamerender()
in the first place.
2020-06-19 09:05:48 -04:00
Misa
fe1045b515 Interpolate tower scrolling
Now tower scrolling will look smooth ayy-eff.
2020-06-19 09:05:48 -04:00
Misa
b3f7c174ea Fix special text box images sometimes flashing
These special images are the crewmates, Level Complete, and Game
Complete images. They flashed depending on if you were lucky and
happened to got your delta-timesteps just right when text boxes were
fading in and out.

Honestly, I'm surprised text box fading in/out hasn't ran into this
issue before. It's insane luck that this issue hasn't occurred before or
anything.

Well, anyways, to fix this, there's now an attribute `allowspecial` on
text boxes, and an optional parameter of the same name for
Graphics::createtextbox(). This attribute is the only thing that will
let these special text box images render. And any createtextbox()es that
utilize these special images have been updated accordingly.
2020-06-19 09:05:48 -04:00
Misa
dcc9520d8f Interpolate trophy text
Just to make sure it's extra smooth. Not that it will be noticeable, and
you can't access the Secret Lab in slowmode without modifying the game,
but it's nice to have this.
2020-06-19 09:05:48 -04:00
Misa
a69bb84eaf Interpolate all-sides warp BG
Again, it was only noticeable at 40% speed that it updated at 1000/34
FPS before.
2020-06-19 09:05:48 -04:00
Misa
66ac035576 Move all-sides warp background update code to logic functions
Otherwise it'll go by really fast and rapidly pulsate. To the point
where it seems like it would be an epilepsy trigger, although I
wouldn't know anything about epilepsy other than that it's bad.
2020-06-19 09:05:48 -04:00
Misa
8184a392eb Interpolate tower background
Ok, now THIS takes the cake for "only really noticeable in slowmode",
because it only ever moves at 1 pixel per second. And even then,
slowmode shouldn't apply on the title screen, so it won't even show up
there once I get around to doing that change.
2020-06-19 09:05:48 -04:00
Misa
118401f17e Move tower background update code to logic functions
Otherwise it'll go really really quickly, which is not good.
2020-06-19 09:05:48 -04:00
Misa
7810e99507 Interpolate vertical warp background
So it'll look very smooth. Again, only really noticeable in slowdown
(although I could kind of tell the difference at full speed).
2020-06-19 09:05:48 -04:00
Misa
921960d23a Move vertical warp background updating to Graphics::updatebackground()
Otherwise it will zoom by pretty quickly.
2020-06-19 09:05:48 -04:00
Misa
c7d3a684ea Interpolate horizontal warp BG
So that it's really, really smooth. Only noticeable in slowdown mode,
though.
2020-06-19 09:05:48 -04:00