This ensures that the game won't silently fail to start if it can't
initialize the filesystem. Instead, it will fail loudly by popping open
a message box (using SDL_ShowSimpleMessageBox).
The motivation for this comes from issue #1010 where this is likely to
occur if the user has Controlled Folder Access enabled on Windows, but I
didn't want to put in the work to specifically detect CFA (and not sure
if it's even possible if it turns out that the OS just gives a standard
"permission denied" in this case). At least any message box is better
than silently failing but printing to console when most users don't know
what a console is.
Fixes#1010.
This is the same as commit 70357a65bf
("Fix regression: Warp BG lerps in reverse direction"), but for the
tower background.
This bug is most visible when moving the camera in a tower using
invincibility, or holding down ACTION during the credits scroll.
This lets you hold down F to fast-forward the game if you have the level
debugger interface open (with Y) and the game isn't paused.
This is most useful for quickly skipping through cutscenes to test
something.
This code was introduced by Dav999 in
abf12632bb (PR #1077), but it contains a
memory error. I spotted this with Valgrind.
The problem comes from the fact that `max_codepoint` is calculated from
the width and height of the surface (which will have the same width and
height as the source `font.png` from the filesystem). Let's work through
an example using a typical 128 by 128 `font.png` and an 8 by 8 glyph.
`chars_per_line` is calculated by dividing the width of the image
(`temp_surface->w`, or 128) by `f->glyph_w` (8), yielding 16.
`max_codepoint` is calculated by first calculating the height of the
image divided by the height of the glyph - which here just happens to be
the same as `chars_per_line` (16) since we have a square `font.png` -
and then multiplying the result by `chars_per_line`. 16 times 16 is 256.
Now it is important to recognize here that this is the _amount_ of
glyphs in `font.png`. It is _not_ the last codepoint in the image. To
see why, consider the fact that codepoint 0 is contained in the image.
If we have codepoint 0, then we can't have codepoint 256, because that
would imply that we have 257 codepoints, but clearly, we don't. If we
try to read codepoint 256, then after working through the calculations
to read the glyphs, we would be trying to read from pixel columns 0
through 7 and pixel rows 128 through 135... in a 128 by 128 image...
which is clearly incorrect.
Therefore, it's incorrect to write the upper bound of the for-loop
iterating over every codepoint as `codepoint <= max_codepoint` instead
of `codepoint < max_codepoint`.
I was running the game through Valgrind and I noticed a memory error
where the game was attempting to read a pixel that was just outside the
image. Since this is an error that doesn't immediately result in a
segfault, I figured that it would be prudent to put in an assertion to
make it loud and clear that a memory error is, in fact, happening here.
Similarly, drawing to a pixel just outside the surface wouldn't result
in a crash, so I copy-pasted the check there too (with changes).
If you're in (5, 5) (1-indexed) and you resize the map to (4,5), the
editor stays in (5, 5). This has no real consequences, other than
possibly confusing the user, but it should probably be fixed anyway.
I just discovered this: whereas 2.3 and older versions make gravity
and warp lines - when placed in the editor - stick out one tile
offscreen, the latest version stops the lines at the room border.
This change restores the old behavior, and it's a simple fix: the
refactored code was written to let tiles outside the room block
gravity/warp lines. Instead of all offscreen tiles blocking lines, now
there's a 1-tile padding around the room that will let them through.
The new localization-related credits are placed 5 characters from
the left border in the rolling credits (at x=40), which means the
limit was 35 8x8 characters. Which was broken by several languages.
So instead, move the string leftward a bit if it would run offscreen
otherwise.
If you go into the middle of the list of translators in the main menu
credits, then press Escape, and then go into the credits again, the
first page of the list may start at the wrong place, because while
game.translator_credits_pagenum was reset to 0,
game.current_credits_list_index wasn't. This is fixed now.
The header "Translators", as well as the language names, were using
PR_FONT_8X8, even though it was translatable text. This is now fixed.
(Also, the CJK spacing for the language names is now higher because
that looked nicer)
VVVVVV 2.2 only supported displaying characters 00-7F with its font
system. VVVVVV 2.3 added support for unicode, by supplying a font.txt
with all the characters that are in the font image. But 2.3 made
another change that I didn't immediately realize, even after reading
the code: if font.txt is not present, then the font is not assumed to
have _only_ 00-7F, but _all_ of unicode, as far as the image dimensions
allow.
However, an inconsistency I _did_ notice is how unknown characters
would be rendered in 2.3. If a font had a font.txt, then any unknown
characters would be shown as a '?'. If a font had no font.txt however,
then suddenly any unknown characters would just come out as a space.
I fixed this behavior with the new font system; but what was actually
happening for characters to come out blank is that characters up to
U+00FF, which _were_ technically in the font image but as fully
transparent, would be shown as they were in the image, and characters
beyond U+00FF wouldn't be shown since they were outside of the image.
I don't really want to show blank characters for any character between
80-FF if it is technically inside the image, because pretty much every
single ASCII-only font.png in existence (including the one in data.zip)
contains a blank lower half, just because the font in the game had
always had this specific resolution. (We didn't want to do things that
might crash the game because something was different from what it
expected...)
We have had some confusing occasions before with the old behavior where
the fonts weren't correctly packaged or something (like when the
Catalan translator was sent the first version of the translator pack,
or when people customize their fonts wrong) and special characters were
just blank spaces.
So, instead, for characters beyond 7F, I decided to consider them part
of the font, as long as they are not blank. That means, if a character
beyond the ASCII range has any (non-alpha-0) pixels, then it will be
added, otherwise it won't be. This is just to handle legacy fonts, and
the case where all fonts are missing and the one from data.zip is used;
new fonts should just use .fontmeta or .txt to define their characters.
Two translators thus far have tried to populate initial language files
by creating a blank folder and then using the in-game sync option. For
example, see #1078.
That is not how the sync option was intended to be used, but it's
really close to getting everything, so I decided to just complete the
support by making sure numbers.xml is copied from English, and making
sure meta.xml is filled in with English text and not text from an
arbitrary language. Also, minor detail on plural form 1 being set to 1
by default if reset, so strings_plural.xml is fully consistent too.
Or well, lock yourself out if you don't have (easy) access to a
keyboard, like on Steam Deck.
In 2.3, this problem used to be much worse, since you could bind any
button to "menu" - which is actually also "return" in menus - and that
button could then no longer be bound to any other action, because
exiting the bindings menu had priority over assigning a different
binding. The result would be that people could have all their buttons
bound to "escape" with no way of undoing it or using their controllers
at all other than manually going into their config file to change it.
In 2.4, the most important bugs in the bindings menu are fixed, but
it's still possible to remove all your bindings from the "flip"
(confirm) action, meaning you can't navigate the menus anymore with a
controller to fix your bindings or even do anything.
There is one interesting part to all this: if an action has no buttons
bound to it at all when the game is started, then that action is
populated with the default button for that action. This is done for
each action separately, without accounting for the case where the
default button was already bound to another action which was not empty.
(This is something that the binding menu does try to prevent).
Therefore, having no buttons bound to "flip" while having A and B bound
to "menu", would result in A being bound to "flip" and A and B bound to
"menu".
That would still make you unable to enter the gamepad menu, since both
"confirm" and "return" are pressed in a row.
This commit fixes the specific situation where flip/confirm buttons are
also bound to menu/return, by removing all buttons that are in the flip
button list from the menu list. This means that, on Steam Deck, you can
still go to your bindings menu.
Seems like I made a mistake while originally writing the "make
autotiling base" code. This commit fixes the warp background turning
into solid tiles when you switch to a different tileset.
This commit adds translation credits to the game's end credits
screen. Note that this is not implemented into the menu credits
screen yet. The translator name list is subject to tweaks, and
additionally some localised strings ("Localisation Project Led by"
and "Pan-European Font Design by") run off the screen in some
languages (Catalan, Spanish, Irish, Italian, Dutch, European
Portuguese and Ukrainian) and will need to be addressed later.
Textboxes created with graphics.createtextboxflipme() use PR_FONT_LEVEL
by default, but can be overridden with graphics.textboxprintflags() to,
for example, set PR_FONT_INTERFACE. This happens for the textboxes on
the Game Complete screen, which use interface text. The textboxes are
centered by setting the X position to -1 though, which means they're
solely centered based on the width of the first line, in the level
font (because the font hasn't been changed to the interface font yet).
Normally, this isn't a problem, because in the main game (where the
Game Complete screen usually appears), the level font is always equal
to the interface font. However, in custom levels you can still get it
(by calling gamestate 3500) and in that case some of the text may be
misaligned. This change fixes that by adding graphics.textboxcenterx()
to these textboxes.
As far as I can tell, these are the only textboxes that are centered
by just x=-1 despite changing the font afterwards.
If you had a pink space station background, and switched to a different
tileset, some solid tiles would be placed instead. This commit fixes
that by transforming the room into the basic autotiling tiles before
changing the tileset itself. The reason why I chose this solution is
because it will help with a future change, being unhardcoding warp zone
backgrounds (which'll help with custom autotiling, if that becomes a
thing.)
Now that the language files are fairly stable, we should be able to do
this without any accidental reverts taking place (if any do happen, it
should be easy to see and prevent)
With the recent change to drawing overlays (images and sprites) from
PR #1058, it's starting to get a bit hairy. This names the conditionals
responsible for determining if the text box is transparent (checking
that all of its RGB is 0) and if overlays should be drawn or not (which
is now either when it's opaque or transparent).
Textsprites and textimages no longer wait for the opacity
value in order to display within transparent textboxes.
Text sprites in normal opaque textboxes are not affected
by this change.
Fixes#1057.
Based on Ethan's hunch, I simply removed the format comparison that
decides whether to halt and restart, or reuse the voice. Voices are
now always restarted when playing a new track.
This also simplifies the code somewhat: `MusicTrack::musicVoiceFormat`
was now no longer used, and an `if (!IsHalted())` was no longer
necessary because `Halt()` already does that. So those are now removed
as well.
At first my CJK changes also misaligned this sprite, and my solution
that time was to position the textbox higher depending on the height
of the textbox, so it would be centered around the crewmate sprite
(which stayed at a hardcoded place onscreen). Recently, #987 changed
these sprites to be relative to the position of the textbox instead of
relative to the screen, which is much more logical, but it stopped
centering these sprites again. But it's an easy fix: simply account for
the extra-added height when adding the sprite in.
This fixes a regression caused by PR #923 (the PR that moved rendering
to be GPU-based) where the interpolation of the horizontal and vertical
warp backgrounds (in over-30-FPS mode) was in the wrong direction, which
makes them look blurry.
This happens because the arguments to the `lerp` function were in the
wrong, reverse order.
On the VVVVVV Discord server, Ally raised the argument that they were in
the same order before she made the changes; therefore the previous code
was also incorrect and it wasn't her fault. However, this argument is
incorrect, because in that case, the reverse order _is_ the correct
order.
The reason that it's now the wrong order is because the output of `lerp`
is now being used as the argument to a source rectangle. Previously, the
output of `lerp` was being used as the offset argument to
`ScrollSurface`, which is analogous to being a destination rectangle.
Fixes#1038.
The main issue was mostly that we have to build C files as C++ in some
cases, and extern "C" wasn't being used everywhere, so linker errors
popped up. The rest is the usual tedious VS2010 stuff like casting void*
to other stuff, so this commit as a whole is pretty boring!
This commit adds new debug lines while you're NOT hovering over an
entity or a block. Additionally, coordinates are now displayed smaller,
to not take up as much vertical space.
The level debugger is toggleable in playtesting mode by pressing Y.
You can toggle whether or not the game is paused inside of the debugger
by pressing TAB. The debugger screen allows you to see entity and block
properties, and allows you to move them around.
The hardest room used to be stored as a room name in whatever language
it was in when you last died enough times to break the record (before
localization, that was always English). Even after localization became
a thing we could get away with this since we only had a single font,
but now we might have actual question marks appearing when the new font
doesn't support characters from the old language.
Therefore, this commit adds more info about the hardest room to save
files - everything that is needed to know in order to do the
translation at display time. These are hardestroom_x and hardestroom_y
for the room coordinates, as well as hardestroom_specialname to mark
special names, in addition to changing the stored room name back to
English. I've also added hardestroom_finalstretch in case we later
decide to drop the English name as a key and rely on just the
coordinates (even though I think that change itself would be more
complicated than any simplification it would accomplish, and I don't
think it's necessary, but better to have it if we do need it later)
As described in #1016, there used to be a bug that inflated
levelstats.vvv in 2.3, which was fixed in 2.4, but there was no way
for inflated files to get smaller yet.
This commit changes the storage of levelstats from a std::vector of
structs to a std::map, so that uniqueness is guaranteed and thus the
stats can be optimized automatically. And it also simplifies *and*
optimizes the code that handles the levelstats - no more big loops that
iterated over every element to find the matching level.
(Farewell to the "life optimisation and all that" comment, too)
I tested this with both my own levelstats.vvv, as well as some inflated
ones (including Balneor's 93 MB one) and saw this code correctly reduce
the filesize and speed up the levels list.
Fixes#1016.
The declarations of `std::vector<std::string> customlevelnames` and
`std::vector<int> customlevelscores` are made quite early in the
function, commented with "Old system", but the place where the old
system is processed is after a big chunk of code that processes the new
system (and indeed never uses these vectors). So for readability,
they're now closer to where they're used.