Commit Graph
100 Commits
Author SHA1 Message Date
Misa b0d2a6a372 Add -std=c99 for C-Hashmap and FAudio
GCC on CentOS will default to C90, it seems. This means it needs C99
explicitly specified for C-Hashmap and FAudio, or it will fail on them
using C99 features (variable declaration in a `for`-loop and the
`restrict` keyword, respectively).
2024-07-12 21:33:47 -07:00
Misa ff611a56ff CMake: Scope C99/C++98 flags to VVVVVV only
Due to a confluence of weird factors, it turns out that PhysFS is
compiling with implicit function definitions due to function definitions
that get hidden with -std=c99, but not with -std=gnu99 (or the default
GCC value of -std=gnu17).

Also, due to a recent GCC update (GCC 14), implicit function
declarations are actually prohibited with -std=c99 as the C99 standard
proscribes.

This meant that people started getting build errors in PhysFS code on
default settings, which wasn't ideal.

To fix this, we will make our -std= flags apply only to VVVVVV source
files. In CMake 2.8.12, this can be done with
set_source_files_properties. Additionally the flags to disable
exceptions and RTTI are scoped down too.

Thanks to leo60228 for helping debug and solve this issue.

Fixes #1167.
2024-07-12 21:33:47 -07:00
Misa 7d01c6bdb0 Fix double error dialog if data.zip is missing
A minor gripe, but one thing I didn't notice with commit
b4579d88d3 is that it now results in two
dialogs if data.zip is missing: The first being the "data.zip is
missing" dialog, and the second is the generic "Unable to initialize
filesystem" dialog.

So just bail early if data.zip can't be found, it's going to take the
error path in main() and also bail regardless.
2024-07-11 11:47:59 -07:00
Misa a990f8d87d Fix wrong comment on disabling MSVC exceptions
`/EHsc` does not actually disable exceptions on MSVC, it only makes the
compiler assume that `extern "C"` functions never throw C++ exceptions.

We had a discussion on Discord about actually disabling exceptions, and
from research, that requires defining `_HAS_EXCEPTIONS=0`, but it's
unsupported and undocumented so we deemed the benefits not worth it.
Thus, we will stay with `/EHsc`. But the comment still has to be
updated.

[skip ci]
2024-07-11 11:44:49 -07:00
Misa 64c554261e Fix regression: Entities not moving
Commit 53d725f78a, intended to fix an
overzealous commit, was itself overzealous. This is because it applied
to all entities when it should only apply to entity-emitting entities.
To fix this, `entityclonefix` needs to no-op if the entity is not an
entity emitter.

Fixes #1176.
2024-06-09 19:41:48 -07:00
Misa 53d725f78a Fix regression: Overzealous emitter dupe fix
Commit 4f881b9e26 fixed a duplication bug
where enemy movement types 10 and 12 would keep duplicating itself on
every frame if it was spawned outside of the rooms they were supposed to
be used in the main game. The downside was that this was an overzealous
fix and unintentionally broke some cases that were working before.

As brought to my attention by Ally, you can no longer place an edentity
with a `p1` of 10 or 12 (translating to movement type 10 or 12) in the
proper rooms and have it spawn perfectly working entities (that don't
clone on themselves every frame), whereas you could in 2.2. This is
considered a regression from 2.3.

So the problem here is that the reason the two emitter entities were so
dangerous outside their respective rooms is because the entity they
spawned (`createentity` entry 1) checked if it was in the correct rooms,
and if so, it would call `setenemy`, and `setenemy` would set the
`behave` attribute (movement type) correctly, and so the new entity
would have a different `behave` that wouldn't be the exact same `behave`
as the previous one, so it wouldn't be a duplicate emitter entity.

The previous `entityclonefix` worked okay for entry 1, because it would
only be run if the room checks failed and `setenemy` wasn't called, but
it broke a previously-working case for entry 56, because it was always
run for entry 56.

So the best way to check if we have a dangerous entity is not by seeing
if it is still `behave` 10 or 12 at the end of entity creation - because
10 or 12 could be harmless under the right conditions - but by checking
if the right conditions were satisfied, and if not, then neutralize the
entity.

I considered making the emitter entities work everywhere - which would
be simpler - but I didn't want to go too far and add a new feature,
especially in a minor release.
2024-06-07 14:20:28 -07:00
Misa c20db02f15 Unload zips before loading zips
This fixes a minor issue where if you had a zip in the levels list, but
then removed it, it would still show up in the levels list after
reloading it (if you also had a .vvvvvv file named the same as in the
zip) even though it shouldn't.

Thankfully, this didn't lead to a memory leak or duplicate zip mounts or
anything like that, because PhysFS ignores mounting a zip if it's
already mounted.

This also didn't result in a level entry from a zip persisting after
removal after reloading the levels list, because the entry would be gone
due to the .vvvvvv file not being found.
2024-06-04 15:42:39 -07:00
Misa dd15d67e62 Fix info args not working with -console
The intention of the `-console` argument was to enable seeing console
output on Windows without having to use workarounds. However, this
didn't actually work for arguments like `-addresses` and `-version`,
because the program would exit first before it could get the chance to
create the console.

The other issue is that the console closes too quickly before output can
be read by the user. So to fix that, we must hold it open and let the
user close it when they want to by waiting for an enter press from
STDIN.
2024-06-03 21:42:57 -07:00
Misa a9d43b543f Fix regression: Foreground redraw after G keybind
This fixes a regression from 2.4 where the foreground wouldn't update
after using the G keybind to go to a room, requiring the user to touch a
tile to update the rendering.
2024-06-03 20:58:52 -07:00
Misa 16d75d2da8 Disable state locking if inc'ing state w/ ACTION
This fixes a bug report from Elomavi that you could still softlock from
warping to ship and incrementing the gamestate by pressing ACTION, which
is diverging behavior from how it was in 2.3. Warping to ship and
incrementing by pressing ACTION is useful behavior for a couple niche
speedrun categories.

I had already fixed this earlier by ignoring state locking if
glitchrunner 2.2 or 2.0 was enabled, but softlocks could still happen
because having glitchrunner mode off still enabled you to increment the
gamestate when otherwise unintended. Softlocks shouldn't happen.

But without removing state locking entirely, I've chosen a middle ground
where it will only be disabled if you press ACTION. That signifies
intent that you still want to perform state incrementing glitches even
with glitchrunner mode off (but in the future it could be considered a
2.3/2.4 glitch that could be patched and made re-enable-able). That way,
casual players can't interrupt the warp to ship by accident (unless they
accidentally press ACTION) while softlocks will be removed.
2024-05-25 23:34:03 -07:00
Misa ff6bb68f3a Fix "Thanks for playing!" reversed in Flip Mode
For localization, the "Thanks for playing!" text was split into two
lines, when it was originally one line. Unfortunately, it was not
updated to account for Flip Mode, so in Flip Mode, it looked like
"playing! Thanks for".

This has been fixed.
2024-05-25 23:33:45 -07:00
Misa ff785aaa8a Bump version to 2.4.2
We still need to fix a couple bugs from 2.4.0.
2024-03-29 21:18:39 -07:00
Misa 217996b134 Fix UB from out-of-range <stretch>
If there was a scaling mode value (serialized in the XML as <stretch>
for legacy reasons) that was not 0 or 1 or 2, then the rectangle with
the stretch information would not be initialized by get_stretch_info,
which would lead to a crash, either from dividing by zero (most likely)
or from reading an uninitialized value.

To fix this, when reading <stretch>, normalize it to a sane default if
the value is otherwise bogus. And for good measure, an assertion is
added in get_stretch_info() if the value is still somehow bogus.

Fixes #1155.
2024-03-29 20:22:00 -07:00
Misa 8640ead937 Fix copy-paste error in customposition
This would otherwise result in text boxes for custom crewmates being
improperly positioned.
2024-03-29 19:55:41 -07:00
Misa 365ee963eb Fix resize-to-nearest could be larger than desktop
This fixes the possibility of the "resize to nearest" graphics option
resizing the game window to be bigger than the resolution of the user's
desktop monitor.

To fix this, just subtract multiples of 320x240 until the chosen
multiple is smaller than the dimensions of the desktop.

Discord user Dzhake discovered this issue.
2024-02-05 18:03:32 -08:00
Misa 935db27d39 Revert "Translate editor notes on-the-fly"
This reverts commit ec3de52970.

The complexity is not worth it for something that only lasts less than
two seconds anyway. *shrug*
2024-02-02 19:13:59 -08:00
Misa ec3de52970 Translate editor notes on-the-fly
This is so they will be updated when switching language with CTRL+F8.

Most of the editor notes are simple text that don't use any string
formatting. For the ones that aren't, some (saving and loading, changing
map size) reference variables that wouldn't change without initiating a
new note anyway. For the others, i.e. the ones that _do_ reference
variables that could easily be changed (tileset name, speed) by
switching the current room, we cache their values and use the cached
values when drawing the note. Unfortunately, this requires adding a
couple of ugly attributes to editorclass, but it'll be fine.
2024-02-02 18:57:24 -08:00
Misa 67f41a780c Translate editor prompt text on-the-fly
These are simple strings (no vformat), so we can just un-bake them to
make sure that cycling languages with one of them onscreen updates them
accordingly.
2024-02-02 18:57:24 -08:00
Misa a7acf4e177 Fix cycling menus in editor not updating
While there's a check to recreate the menu if you cycle the language
while in a menu, editor menus are a special case and need specific
handling.
2024-02-02 18:57:24 -08:00
Misa 53ed33039f Translate level title and creator on-the-fly
These weren't getting updated when cycling language with CTRL+F8. This
is because they would be already baked. Luckily, at least the bool
keeping track of whether or not to translate them in the first place
already exists, so we can just rely on that.
2024-02-02 18:57:24 -08:00
Misa 0aea27f237 Fix limits check not updating with CTRL+F8
This makes it work pretty well. It basically just resets the state of
the limits check and starts from the first limit broken (if any), which
is behavior that makes sense to me.

Otherwise, without this, it seems to invalidate pointers and, on my
machine, start pulling strings from the language XML, which is
horrifying.
2024-02-02 18:57:24 -08:00
Misa ad6e31aa12 Disable switching languages during cutscene tests
Not gonna lie, I am a bit disappointed at having to do this, because it
actually worked pretty well despite a few bugs depending on which
language you entered with. But that's only because I'm working with
the official translation files, which are in sync with each other.

With translation files that are completely arbitrary, it would be
apparent that switching languages during the cutscene test doesn't
really make sense. Like, at all. That's because the list of cutscenes is
populated entirely from language-specific XML and the cutscenes in them
are also from language-specific XML. So keeping the same position in the
menu doesn't really make sense, and keeping the same position in a
cutscene definitely doesn't make sense.
2024-02-02 18:57:24 -08:00
Misa 3d61f9067b Translate NDM hardest room on-the-fly
Otherwise, cycling languages through CTRL+F8 would result in mismatched
languages.
2024-02-02 18:57:24 -08:00
Misa 531b151d12 Translate menu options on-the-fly
I saw that the only problem with cycling languages in a title screen
menu is that the menu options don't get updated. So I was like, we can
just recreate the menu, and then I was like "Sure, why not." So that's
what I did.

To accommodate the CTRL+F8 keybind in the language menu, it
automatically updates the menu option when you cycle it. This is because
otherwise using the keybind in the language menu wouldn't visibly update
the language, but it still actually does change your language, and that
can be seen by pressing Escape.

Also, the menucountdown needs to be preserved because otherwise
createmenu() resets it, even if it's the "same" menu (this behavior is
needed so that the menu that is shown during the countdown isn't added
as a stack frame which would make it a menu that could be returned to).
2024-02-02 18:57:24 -08:00
Misa c173dec8f9 Reset textcase in speak/speak_active
Originally, textcase was reset in scriptclass::translate_dialogue(),
which is called inside the `text` script command. However, this didn't
really work with the new on-the-fly text box translation system, and
that function is gone now, so I removed that and kind of forgot about
it.

Of course, this now causes a regression. Namely, that the text boxes
after the VVVVVV-Man sequence in the Secret Lab entrance cutscene are
not translated.

I can't reset the text case in `text`, as the scripts assume that they
can set the text case before `text`. So the next best thing is to reset
it in speak/speak_active.
2024-02-02 18:57:24 -08:00
Misa 861f724d90 Recompute textboxes on active input device change
This fixes a bug where some text boxes wouldn't update the displayed
button if the active input device changed from a keyboard to controller,
or vice versa. Namely, the "Press ACTION to continue" text boxes.
2024-02-02 18:57:24 -08:00
Misa 505956ae83 Remove textboxwrap() and wrap() return value
This removes Graphics::textboxwrap(), as it is now an unused function.
Additionally, this removes the return value of textboxclass::wrap(), as
it is also now unused.
2024-02-02 18:57:24 -08:00
Misa c50da88ad4 Store original position of text box
This stores the original x-position and y-position of the text box, and
when a text box gets repositioned, it will use those unless a crewmate
position overrides it.

This is the original position of the text box, before centering or
crewmate position is considered.

This fixes a bug where a cutscene text box can be "shifted" from its
normal position via CTRL+F8 cycling if there is a translation that is
too long for the screen and thus gets pushed by adjust(). I tested this
with the text box in the Comms Relay cutscene that starts with "If YOU
can find a teleporter".

This is not applicable to function-based translations
(TEXTTRANSLATE_FUNCTION), because the responsibility of correctly
positioning the text box resides with the function.
2024-02-02 18:57:24 -08:00
Misa 9b56a53d98 Add debug keybind CTRL+(SHIFT)+F8 to cycle lang
This adds a debug keybind to cycle the current language forwards,
CTRL+F8. It also adds a debug keybind to cycle it backwards,
CTRL+SHIFT+F8.

This is only active if the translator menu is active (and so if the
regular F8 keybind is also active).

This is useful for quickly catching errors in translations and/or
inconsistencies between translations. In fact, I've already caught
several translation mistakes using this keybind which made me mildly
panic that I screwed something up in my own code, only to realize that
no, actually, it was the translation that was at fault.

For now, this is only meant to be used in-game, as text boxes get
retranslated instantly, whereas things like menu options don't. But menu
options will be retranslated on-the-fly in a later commit.
2024-02-02 18:57:24 -08:00
Misa 84daa8fbc2 Call resize() before formatting text in cutscene
This fixes a problem where it would incorrectly format the text because
the width of the text box hadn't updated yet.

This fixes a bug where the jukebox informational terminal would
initially be created with too much padding in CJK languages, pushing the
text box offscreen, even though switching languages while the text box
is already open fixes it.
2024-02-02 18:57:24 -08:00
Misa 3de2c543a5 Move all other text boxes to new system
These include the room name translator text boxes (which aren't
translated) and the foundlab and foundlab2 text boxes.
2024-02-02 18:57:24 -08:00
Misa b14ca5e366 Move Game Complete sequence to new text box system
In order to be able to retranslate the game time text box in particular,
I had to create new variables to bake the saved time, since the existing
savetime variable is just an std::string. From there, the saved time can
be retranslated on-the-fly.
2024-02-02 18:57:24 -08:00
Misa 7088858957 Add textbox indexes, update trinket/crew textboxes
This adds an attribute to textboxclass to allow a text box to keep an
index that references another text box inside the graphics.textboxes
std::vector.

This is needed because the second text box of a "You have found a
shiny trinket!" or "You have found a lost crewmate!" pair of text boxes
explicitly relies on the height of the first text box. With this, I have
moved those text boxes over to the new text box translation system.

Since the update order now matters, I added a comment to
recomputetextboxes() that clarifies that the text boxes must be updated
in linear order, starting from 0.
2024-02-02 18:57:24 -08:00
Misa 668d0c744d Add assert for giving func if it won't be used
This adds an assert to Graphics::textboxtranslate() to make sure that
callers don't accidentally provide a function when specifying a
translation type that isn't TEXTTRANSLATE_FUNCTION, because in that case
the function won't be used, and then it will make them scratch their
heads wondering why their function won't work.

And yes, I am stupid enough to blindly type TEXTTRANSLATE_CUTSCENE when
I meant to type TEXTTRANSLATE_FUNCTION. This assert has already caught
one of my mistakes. :)
2024-02-02 18:57:24 -08:00
Misa 76483f96ef Move Comms Relay text boxes to new system
These seemed annoying to do without copy-pasting, because I didn't want
to make a separate function for every single dialogue, and I didn't know
how to pass through the English text, until I realized that I can just
use the existing original.lines vector in the text box to store the
English text. After that, getting it translated on-the-fly isn't too
bad.
2024-02-02 18:57:24 -08:00
Misa 82150fd3a9 Remove unnecessary calls to resize()
Just a small optimization.

For example, consider the calls in adjust(). After the first resize(),
the lines after only change the x-position and y-position of the text
box and depend on the x-position, y-position, width, and height.
However, resize() only changes the width and height if the contents of
the text box change, which after the first call, they don't. So remove
the second call to resize(), because it's completely unnecessary.

By similar reasoning, the second calls to resize() in centerx() and
centery() are unnecessary too.
2024-02-02 18:57:24 -08:00
Misa 28df0148b1 Transfer adjust call to applyposition
This transfers the responsibility of the adjust() call to
applyposition().

This is because cutscene text boxes (TEXTTRANSLATE_CUTSCENE) will have
adjust() called, but all other text boxes won't. And I can't place the
adjust() call inside applyposition(), because adjust() also calls
applyposition(), and that leads to an infinite loop which leads to a
stack overflow, so I had to remove the applyposition() call from
adjust(), and replace the other existing call to
Graphics::textboxadjust() with Graphics::textboxapplyposition(), and
then remove Graphics::textboxadjust() function because it's no longer
used.
2024-02-02 18:57:24 -08:00
Misa 3ef089ed3d Save context of untranslated text boxes
Several text boxes in the gamestate system are unused and are
untranslated. To prevent them from becoming empty when retranslating
text boxes, we need to save their original context by calling
graphics.textboxoriginalcontextauto() (which is just
graphics.textboxoriginalcontext() but automatically saving whatever is
already in the text box at the time).
2024-02-02 18:57:24 -08:00
Misa d989c232af Recompute text boxes in Flip Mode
With the new system of retranslating text boxes on-the-fly, this also
enables us to retranslate them whenever the player toggles Flip Mode.
This is relevant because the Intermission 1 instructional text boxes
refer to a floor when Flip Mode is off, but when it is on, it talks
about the ceiling.
2024-02-02 18:57:24 -08:00
Misa 94b9722b7b Split textwraps, move more textboxes to new system
This splits the text wrapping functionality of Graphics::textboxwrap to
a new function textboxclass::wrap, and with this new function, some more
text boxes can be moved to the new TEXTTRANSLATE_FUNCTION system.
Namely, Game Saved (specifically the game failing to save text box),
instructional text boxes in Space Station 1, and the Intermission 1
instructional text boxes.
2024-02-02 18:57:24 -08:00
Misa de00dd4031 Save special text box state using functions
This adds a way to save the text box state of the crew remaining, ACTION
prompt, etc. text boxes by just letting there be a function that is
called to retranslate the text box when needed.

It also adds a way to ignore translating a text box and to leave it
alone, in case there's actually no text in the text box, which is the
case with Level Complete and Game Complete.

Both ways are now in an enum, TextboxTranslate. The former is
TEXTTRANSLATE_FUNCTION and the latter is TEXTTRANSLATE_NONE. The
existing way of translating text boxes became TEXTTRANSLATE_CUTSCENE,
since it's only used for cutscene scripts.

Here's a quick guide to the three ways of creating a text box now.

- TEXTTRANSLATE_NONE: You must call
  graphics.textboxoriginalcontextauto() to save the existing text to the
  original context of the text box, as that will be copied back to the
  text box after the text of the text box is updated due to not having a
  translation.
- TEXTTRANSLATE_CUTSCENE: Translates the text from cutscenes.xml, and
  overrides the spacing (padding and text centering). Shouldn't need to
  be used outside of scriptclass.
- TEXTTRANSLATE_FUNCTION: You must pass in a function that takes in a
  single parameter, a pointer to the textboxclass object to be modified.
  General advice when retranslating text is to clear the `lines` vector
  and then push_back the retranslated text. The function is also solely
  responsible for spacing.

In most cases, you will also need to call
graphics.textboxapplyposition() or graphics.textboxadjust() afterwards.
(Some text boxes shouldn't use graphics.textboxadjust() as they are
within the 10-pixel inner border around the screen that
textboxclass::adjust tries to push the text box out of.)

This commit doesn't fix every text box just yet, though. But it fixes
the Level Complete, Game Complete, crew remaining, and ACTION prompt
text boxes, for a start.
2024-02-02 18:57:24 -08:00
Misa 0ea0b8e00b Save text box centering state
This is another piece of state that needs to be kept and re-played when
switching language, because a different language could change the
dimensions of the text box, which affects how it's centered.

Also, to make sure that crewmate positions override any text centering,
the scriptclass variables textx and texty should be reset in the
position and customposition commands.
2024-02-02 18:57:24 -08:00
Misa e8a231f2e2 Fix translating text box ignoring line limit
Originally I did a straight deep copy of the original lines, but this
ignores the limit of either 12 or 26 lines in a text box. So we defer to
addline() which will enforce the limit accordingly, just like it would
do with the original text box.
2024-02-02 18:57:24 -08:00
Misa 8b03fbd9f4 Save textbox state, allow lang switches w/ textbox
This allows switching languages while a text box is on screen by saving
the necessary state for a text box to be retranslated when the language
is switched.

This saves the state of the position and direction of the crewmate that
the text box position is based off of (if applicable), and the text
case of the text box, the script name of the script, and the original
(English) lines of the text box. I did not explicitly label the original
lines as English lines except in a main game context, because
technically, custom levels could have original lines in a different
language.

Unfortunately, this doesn't work for every text box in the game.
Notably, the Level Complete, Game Complete, number of crewmates
remaining, trinket collection, Intermission 1 guides, etc. text boxes
are special and require further fixes, but that will be coming in later
commits.
2024-02-02 18:57:24 -08:00
Misa 3b0757bd82 Add bounds check to setlinegap
This is for consistency with all other functions dealing with the latest
created text box. There are several cases in custom levels where these
functions can be called even though there are no text boxes on screen.
2024-02-02 15:00:44 -08:00
Misa 2b476bb4c1 Remove trailing whitespace on getlinegap decl 2024-02-02 14:59:52 -08:00
Misa 1c6cfcd2a5 Remove 'all' argument from setrtl
It doesn't make sense to change the alignment of all existing text boxes
when you're not otherwise able to mutate the text. Whereas the point of
the 'all' argument in setfont is to be able to animate text boxes using
fonts.
2024-01-23 16:53:01 -08:00
Misa a9f0d81804 Properly fix setfont/setrtl in between text boxes
There used to be a problem with the setfont and setrtl script commands.
Namely, if you used them in between text boxes naïvely, without any
careful thought, then the fading out text box would suddenly gain the
font of the new one. A kludge solution to this was implemented by simply
blocking the script until the existing text box faded out before
switching the font or RTL, and shipped for 2.4.0.

However, a better solution is to simply bake the font flags in to the
text box, so that way, if the level font switches, then the text box
keeps its font.

This is only for custom levels, because in the main game, the font in a
text box needs to be able to change depending on language. But it seems
like custom level translations weren't much on the roadmap, and so even
the existing hack didn't support changing the font based on translation
(even though translation of custom level cutscenes is supported). So
baking the font flags into the text box here doesn't make things any
worse.

It also makes things better, arguably, by allowing multiple text boxes
to exist on screen at once with different fonts.

Maybe in the future we'll need a flag that specifies that the font
should change depending on language if a translation in said language
exists for the text box, or something like that.

For people that want to override the fonts of every existing text box on
screen, you can specify "all" as the second parameter of setfont or
setrtl to do so.
2024-01-23 15:33:38 -08:00
Misa ea8633514d Fix using int for mode indicator flags
For consistency. Print flags are supposed to be uint32_t.
2024-01-23 14:29:03 -08:00
Misa 8d2a0c2457 Allow overriding state lock in glitchrunner <= 2.2
This fixes a regression where attempting to warp to ship with a trinket
text box open in glitchrunner 2.0, and then incrementing the gamestate
afterwards, would result in a softlock. This is a speedrunning strat
that speedrunners use.

The state lock wasn't ever intended to remove any strats or anything,
just fix warping to ship under normal circumstances. So it's okay to
re-enable interrupting the state by having glitchrunner enabled.

This bug was reported by mohoc in the VVVVVV Speedrunning Discord
server.
2024-01-23 13:55:21 -08:00
Misa 67f56985eb PR template: Clarify compensation
Translators have been getting compensated for localization. Sometimes
they submit pull requests for their changes, but just because they do
doesn't mean that they won't get compensated.

The intent of this line was to make sure that any random contributor
wouldn't expect any compensation for their changes, so adding another
clause here still keeps that expectation while making it clear that it's
not like Terry _never_ compensates people. Even if, as a Swedish man
once sung, "Terry is a monster, I think we all know that".
2024-01-22 20:11:42 +01:00
Misa 32e6ab6ecd README: Add step for compiling
We recently had a user come in the VVVVVV Discord not knowing that,
after running CMake, you then need to compile the game in a separate
step. This clarifies the instructions.
2024-01-22 00:18:20 -08:00
Misa 2f217dad56 Fix segfault: unwordwrap string w/ 2 start \ns
This fixes a segmentation fault caused by an out-of-bounds indexing
caused by an attempt to unwordwrap a string that starts with two
newlines.

The problem here is that in the branch of the function
string_unwordwrap() where `consecutive_newlines == 1`, the function does
not check that the string `result` isn't empty before attempting to
index `result.size()-1`. If `result` is empty, then `result.size()` is
0, and `result.size()-1` becomes -1, and indexing a string at position
-1 is always undefined behavior.

Funnily enough, a similar indexing happens just a few lines down, but
this time, there is a check to make sure that the string isn't empty
first. I'm unsure of how Dav999 forgot that check a few lines earlier.

This situation can happen in practice, with custom level localizations.
I made a level with a filename of testloc.vvvvvv and created a file at
lang/fr/levels/testloc/custom_cutscenes.xml with the following content:

    <?xml version="1.0" encoding="UTF-8"?>
    <cutscenes>
        <cutscene id="test" explanation="">
            <dialogue speaker="cyan" english="This is text..." translation="blarg"/>
        </cutscene>
    </cutscenes>

Then I switched to French, created a script named `test`, and created a
text box that started with two newlines (so in total, the text box must
be at least 3 lines in length). Running the script triggers the segfault
when the text box is created. (Well, technically, on my machine, it
triggers an assertion fail in libstdc++ and aborts, but that's basically
the same thing.)

To fix this while still preserving the exact amount of newlines, if
`result` is empty, we add a newline instead of attempting to index the
string.
2024-01-20 17:52:17 -08:00
Misa c0faa856e8 Japanese: Fix wrong abbreviation period in credit
"Nicalis. Inc" is incorrect, and it should be "Nicalis Inc.". The "Inc."
stands for "Incorporated".
2024-01-12 01:06:24 -08:00
Misa 84322755f2 Remove number translations that are numerals
This removes every single translation of a wordy number that just
replaces it with the numeral.

This is because the documentation in README-translators.txt specifically
says

    It's also possible to leave the translations for all the numbers
    empty. In that case, numeric forms will always be used.

However, the translators for Japanese, Korean, and European Portuguese
clearly either didn't read this, or forgot to do so.

There is a very good reason to leave them alone if you want numerals;
namely that if you fill them in, you are prone to making errors. Like,
say, Japanese translating "Twelve" as "23", which is exactly what
happened. By blanking every translation, that error is fixed.
2024-01-12 01:02:55 -08:00
Misa 5e1a1f80ac Bump version to 2.4.1
The plan is for 2.4 development to continue a bit with some minor new
features. 2.4.0 was the grand release containing most of the new stuff.
2024-01-10 17:40:39 -08:00
Misa 29f05c41b1 Fix warnings when calculating image color
This fixes warnings about narrowing and missing a component of the
struct.
2024-01-10 08:27:34 -08:00
Misa 13d6b2d64c Disable typing pipes in script names
This disables typing the pipe character in the data fields of terminals
and script boxes. Care has been taken to make sure that it's still
possible to type pipes in room text.

This is because pipes are the line separator in the big XML tag that
stores every single script line, and thus a script name with pipes would
end up being split up after the level file has been saved and loaded
again.
2024-01-10 07:59:49 -08:00
Misa 5948168a40 Fix delayed notification of NDM unlock
No Death Mode is intended to be unlocked by getting at least S-rank in
at least 4 time trials. Before 2.3, completing a time trial put you at
the main menu, so you would always be notified of having unlocked No
Death Mode once you went to the play menu again. But since 2.3,
completing a time trial puts you back at the Time Trial selection
screen, which isn't the play menu, so you would need to back all the way
out first in order to get the notification. And since you don't actually
unlock No Death Mode until you see the notification, this would be
required to be able to play No Death Mode.

To fix this, I decided to do something a bit kludge-y and just re-use
the code to check and unlock No Death Mode when the player presses
ACTION on the Time Trial complete screen (and there's also another path
by pressing Escape). At least I put it in a function, so it's not a pure
copy-paste, although it might as well be. I don't have time to think of
a proper solution, but it would probably involve disentangling unlock
notifications from Menu::play, for starters. But that's for later.
2024-01-10 01:33:10 -08:00
Misa a806b072bd Disable typing pipes in script names
This disables typing the pipe character in the data fields of terminals
and script boxes. Care has been taken to make sure that it's still
possible to type pipes in room text.

This is because pipes are the line separator in the big XML tag that
stores every single script line, and thus a script name with pipes would
end up being split up after the level file has been saved and loaded
again.
2024-01-10 00:33:39 -08:00
Misa a1c7291bc4 Don't draw mode indicator text if there is none
This makes it so that the boolean to draw mode indicator text is false
if there aren't any modes active.

Otherwise, when loading in, the in-game timer would only come in after a
few seconds instead of appearing when the fade-in finishes.
2024-01-10 00:23:40 -08:00
Misa 5e28567009 Fix pressing ESC in some menus not playing music
This fixes a bug where pressing Escape in the following menus would not
play Presenting VVVVVV (the title screen music) and would instead leave
you with silence: Game Complete, Time Trial complete, Game Over, and No
Death Mode complete.
2024-01-10 00:19:16 -08:00
Misa 67df8a9679 Add bounds check to textcase() command
This makes it so that only inputs between 1 and 255 inclusive will be
accepted. Otherwise, the command has no effect.

This is because the text case is stored as one byte in a string, and a
value of zero would be the null terminator.

We also want to minimize potential weirdness with integer wrapping if we
accept inputs from outside those bounds. While the textcase variable as
used throughout the codebase is plain unqualified `char` (which, unlike
other integers, exists in a quantum superposition of being signed and
unsigned depending on compiler, machine, and various other stuff) and so
there still might be issues there, we definitely don't want anything
higher than 255.
2024-01-09 23:57:14 -08:00
Misa 34e7b1af61 Update FAudio to 24.01
FAudio is usually very stable, after all, our very own Ethan Lee
maintains it. This should be safe to bump.
2024-01-09 23:15:57 -08:00
Misa 9bb463ab0e Add third_party/ to CI workflow paths
This adds the third_party/ directory to the list of paths that will
trigger a CI workflow when changed.

Not all updates to third-party dependencies will necessarily change
code, but we bump dependencies infrequently so there's not much of a
problem with triggering CI on every change to third_party/.
2024-01-09 23:13:39 -08:00
Misa 2a9003ae45 Reverse left & right nav keys in editor for RTL
If the language is RTL, then the left and right menu navigation keys
should be reversed, because the menu layout goes from right to left.

This is to be consistent with the other menus in the game. The editor is
just a special case so it was overlooked.
2024-01-09 21:05:26 -08:00
Misa 163f3a0fde Allow using W and S in editor menus
There was an inconsistency where W and S couldn't be used in place of
the Up and Down arrow keys, but this has been fixed.

This only applies where W and S otherwise are not bound to anything
else. E.g. not the main editor (where W changes the warp direction and S
saves the level) and not the script editor (where W and S can be typed
inside a script), but the script list is fine.
2024-01-09 20:54:11 -08:00
Misa 0e40892eb0 Arabic: Fix translation for Vertigo roomname
By Montassar.

Just adds a U+200F (RTL mark).
2024-01-09 20:25:15 -08:00
Misa a7b22919ae Modulate text sprite RGB instead of using alpha
Using actual alpha is prone to bugs with doubling alpha, etc. if there
are multiple sprites on top of each other.
2024-01-09 19:22:40 -08:00
Misa 2ed1aac67d Fade text box overlays with text box
Currently, it's a bit jarring that text box overlays (which are text box
images, e.g. Level Complete and Game Complete, and sprites, e.g. the
crewmates) will suddenly appear when their text box has fully faded in
and suddenly disappear once it starts fading out.

This makes it so that text box overlays will be faded in and out
smoothly along with the rest of the text box fading in and out.

Transparent text boxes are not affected, as they do not fade in and out
at all. Thus, text box overlays in transparent text boxes will still
suddenly appear and disappear as usual.
2024-01-09 18:38:40 -08:00
Misa 40b0f9ec36 Account for position of prompt in mode text
I forgot that the position of the activity zone can vary based on
setactivityposition() in custom levels. So account for that.
Additionally, if the activity zone prompt is far down enough, then we
don't need to move the mode text at all.
2024-01-09 17:48:53 -08:00
Misa 18730b465e Allow taking multiple screenshots in same second
Dav999 notified me that if multiple screenshots are taken in the same
second, the second screenshot has `_2` appended to it and so on. We do
the same here by storing the current timestamp and a counter.

This doesn't prevent overwriting files if you have system time that
changes, or have multiple instances of VVVVVV running at the same time,
but my position on those cases is as follows: Don't do that.
2024-01-09 17:21:18 -08:00
Misa d8b97db6a8 Make sure mode text is visible above act prompts
This makes the mode indicator text be visible even if there is an
activity zone prompt on screen, by making it so that it gets moved if an
activity prompt is being rendered.

This is to make sure that it's visible no matter what, even if e.g. a
custom level starts the player on an activity zone.
2024-01-09 17:06:33 -08:00
Misa 9676bf0006 Fix visual clash between timer and trophy text
Trophy text can overlap with the timer. How bad it is depends on the
localization but in English some text definitely overlaps.

Simple fix is to disable rendering the timer if we are rendering any
trophy text.
2024-01-09 16:56:38 -08:00
Misa b3b001c2a8 Place GraphicsResources functions in header file
These are functions used in other files that are not on the
GraphicsResources class but are implemented inside the
GraphicsResources.cpp file. For some reason they were never put in the
GraphicsResources.h file until now, even though it's a perfectly good
header file to put them in.
2024-01-09 16:03:05 -08:00
Misa 10030a4340 Save screenshots with proper filenames
Filenames are timestamped now, down to the second. If you take multiple
screenshots in the same second, then the last one will overwrite the
others. This seems to be how other screenshot programs operate so I
don't think it matters if you can't take more than one per second.

Additionally, 1x screenshots (320x240) will go in the 1x/ subdirectory,
and 2x screenshots (640x480) will go in the 2x/ subdirectory.
2024-01-09 15:48:41 -08:00
Misa 40f6f83328 Add border to indicate taking screenshot
Originally, I was thinking of adding a notification text that you took a
screenshot, but this is better because it is language-agnostic and it
doesn't contribute to potential UI clutter/clashing.

It flashes yellow if the screenshot successfully saved, and red if it
didn't.
2024-01-09 15:48:41 -08:00
Misa 93ec2c6cca Upscale screenshots 2x
The plan is to have Steam screenshots always be 2x, but in the VVVVVV
screenshots directory (for F6 keybind) save both 1x and 2x.

Again, just for now, the 2x screenshot is being saved to a temporary
location for testing and will get proper timestamps later.
2024-01-09 15:48:41 -08:00
Misa 20f0fafa5e Fix screenshots in Flip Mode
One problem with internal screenshot capture is that we rely on SDL's
render subsystem to flip the screen in Flip Mode, while leaving our
actual screen untouched. Since we source the screenshot from the screen
and not what SDL renders, we need to flip the screenshot ourselves when
saving an internal capture.

To do this, we need to support 24-bit colors in DrawPixel() and
ReadPixel(). Luckily, this isn't too hard to do. A 24-bit color is just
a tuple of three bytes, and we just need to do a small amount of bitwise
math to pack/unpack them to a single integer for SDL_GetRGB() and
SDL_MapRGB().
2024-01-09 15:48:41 -08:00
Misa ae5ef9753c Hook Steam screenshots and send internal capture
Using the Steamworks API, we can hook the screenshot function and listen
for a screenshot request callback to send in our own screenshot. This
applies the screenshot improvements to Steam screenshots as well.

Doing this requires adding some C wrapper functions, as our interface
with the Steam API is only conducted through C.
2024-01-09 15:48:41 -08:00
Misa f05827f268 Add support for internal screenshots
"But people already have screenshot tools", you might protest. The
rationale is simple: If you play with any video setting other than 1x
windowed (no stretching and no letterbox), then your screenshot will be
too big if you want the internal resolution of 320x240, and downscaling
will be an inconvenience.

The point is to make screenshots based off of internal resolution so
they are always pixel perfect and ideally never have to be altered once
taken.

I've added the keybind of F6 to do this.

Right now it saves to a temporary test location with the same filename;
future commits will save to properly-timestamped filenames.
2024-01-09 15:48:41 -08:00
Misa fe21be87a2 Remap lang reload keybind from F12 to F8
This remaps the keybind to reload language files from F12 to F8.

This is because the F12 keybind conflicts with the default Steam keybind
to take a Steam screenshot.

I chose F8 because it is next to another keybind that reloads stuff, F9
(which reloads assets in the editor).

Fixes #1089.
2024-01-09 11:14:11 -08:00
Misa b077f24a50 CWrappers.cpp: Extern "C"
While working on adding a screenshots keybind, I encountered a link
error with these functions. Wrapping them in `extern "C"` fixed it. It's
most likely due to the fact that they were `extern "C"` in the header,
but not in the `.cpp` file. They should be both `extern "C"`'d
regardless.
2024-01-09 11:11:15 -08:00
Misa 858c2cb081 Indicate modes when loading in to gameplay
If you load in to gameplay with invincibility mode, glitchrunner mode,
Flip Mode, or slowdown enabled, then there will be text displayed on
screen for a few seconds that says so.

This is to serve as a useful reminder. A common pitfall with using
invincibility is forgetting to turn it off when you don't want it
anymore. What usually happens is that players forget that they have it
on until they encounter a hazard. Now, they can realize it as soon as
they load in.

See #1091.
2024-01-08 20:01:27 -08:00
Misa 47eb7acb44 Only trigger CI workflows for code or CI changes
This makes it so that the main CI workflow will only trigger if a change
is made to a code file in desktop_version/ (as the CI is only for
desktop_version/), or if the CI file itself is changed.

The CI workflow for Android will only trigger if Android-specific code
_could have_ changed. This includes all code that is definitely
Android-specific (e.g. Java files), but also C/C++ files that have
__ANDROID__ ifdefs.

Unfortunately, it's not possible to reuse the same list of paths across
two different event trigger types[1]. So we have to copy-paste here.

[1]: https://github.com/orgs/community/discussions/37645
2024-01-07 17:27:37 -08:00
Misa 4922fa4599 Disable debugger logic when not active
This fixes a bug where you could still drag an entity around with the
debugger inactive if you were holding the entity while disabling the
debugger with Y. Furthermore, you couldn't even drop the entity even if
you wanted to.
2024-01-06 20:51:59 -08:00
Misa 9e2d6e921c Fix clash between Gravitron start text and timer
There is a clash between the timer text and the "Survive for 60
seconds!" text. It's minor in English but it can be worse in other
languages (e.g. Polish).

So make the timer go away when that text is onscreen.
2024-01-06 20:38:25 -08:00
Misa 44fb76ba90 Fix clash between timer and return editor text
The "[Press {button} to return to editor]" and the "TIME:" text
overlapped, which resulted in an ugly clash.

To fix this, make the return editor text take priority over the timer
text. This involves a minor refactor to first calculate whether or not
we should draw the return editor text before we check if we should draw
the timer text.
2024-01-06 15:45:40 -08:00
Misa 95c6dc58d3 Fix TAB bind conflict with translator & debugger
The TAB bind is used in both roomname translator mode and the level
debugger. To fix this, the TAB keybind will prioritize roomname
translator mode, unless the debugger text is enabled (with the Y
keybind), in which case the debugger takes priority. Additionally, the
roomname translator text will not render when the debugger text is
shown.

Fixes #1094.
2024-01-05 11:42:10 -08:00
Misa fc51c2219d README: Reword to "Viki", wordwrap line 2024-01-02 15:33:35 -08:00
Misa b4579d88d3 Add SimpleMessageBox for early filesystem bail
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.
2023-12-31 16:54:53 -08:00
Misa e318d6f176 Fix regression: Tower BG lerps in reverse direction
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.
2023-12-29 14:11:08 -08:00
Misa e6b1b54214 Add a fast-forward keybind to level debugger
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.
2023-12-29 13:56:30 -08:00
Misa b8fdbe53b9 Fix loading plain font.png Unicode indexing out of bounds
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`.
2023-12-29 11:55:09 -08:00
Misa 6f435661e7 Add inbounds pixel assertion to DrawPixel/ReadPixel
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).
2023-12-29 11:54:19 -08:00
Misa af35be5bb6 Name conditionals in text box loop
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).
2023-11-28 19:07:49 -08:00
Misa c9fd9e7924 README: Delete section on compiler quirks
This hasn't been relevant for years now. Even in 2.3, this wasn't
relevant, but we added a disclaimer saying that it only applies to 2.2.

But now issue #1052 has been opened specifically pointing to this
section as something that should be removed. Therefore, I'm removing it.
2023-11-27 13:43:23 -08:00
Misa 70357a65bf Fix regression: Warp BG lerps in reverse direction
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.
2023-11-27 13:29:06 -08:00
Misa 0a72cc6614 Android: Update README.md for Maven package
Since #1047 was merged, we now make the user build the SDL prefab
themselves (as SDL does not publish Maven packages yet). Here are some
instructions for doing that.
2023-11-14 17:29:34 -08:00
Misa 1e5a737089 CMake: Silence deprecation warning
Recent versions of CMake emit the following:

    CMake Deprecation Warning at CMakeLists.txt:4 (cmake_minimum_required):
      Compatibility with CMake < 3.5 will be removed from a future version of
      CMake.

      Update the VERSION argument <min> value or use a ...<max> suffix to tell
      CMake that the project does not need compatibility with older versions.

Reading the documentation further, adding a max refers to the max
version compatibility of CMake _policies_. Adding a max of 3.5 makes the
warning go away, so it seems that the warning is more about policies
than anything else.

This will still work on 2.8.12 as the extra dots will be seen as a
version component separator, ignoring the max version.
2023-10-31 22:36:11 -07:00