1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-12-23 01:59:43 +01:00
Commit graph

2512 commits

Author SHA1 Message Date
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
TerryCavanagh
69684994be added translation category support to ending credits also 2024-02-02 18:24:49 +01:00
TerryCavanagh
62ab594976 added Ivan Lopes and Lucas Nunes to credits 2024-02-02 17:37:23 +01:00
TerryCavanagh
1db33d9cb8 added Guido Di Carlo and LocQuest to credits 2024-02-01 20:23:39 +01:00
TerryCavanagh
8b73a38ed2 don't apply linegap to certain special textboxes
level complete, game complete and "You have rescued a crew member!"
2024-02-01 20:03:17 +01:00
TerryCavanagh
cc1528aacc add a one pixel gap between each line in textboxes (main game only) 2024-02-01 20:03:17 +01: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
Alberto Mardegan
b5abc3956c Fix loading of PNG resources on big-endian machines
LodePNG always loads PNG in big-endian RGBA format. For this reason,
when loading PNG files VVVVVV was specifying the format as ABGR and the
conversion would then be performed by SDL. However, then running on
big-endian machines, this conversion should not be performed at all, and
the surface format should then be set to RGBA.
2024-01-22 10:48:38 -05: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
Dav999
60fd0bc0c2 Replace [Press {button} to toggle gameplay] by freeze/unfreeze
This is both easier for translators ("toggle" can be an annoying word)
and is useful in general because you can tell if gameplay is frozen
without having to have anything in the room that should normally be
moving but isn't.

I didn't follow the rule in lang/README-programmers.txt to keep the
original string around as ***OUTDATED*** in this case, since I know
only Arabic has it translated - we can just tell the Arabic translators
on Discord that this string was replaced.
2024-01-19 16:31:39 -08:00
Ethan Lee
afbcb3f867 Add support for GameCube glyphs.
It's kind of a bummer that L/R don't actually do anything... we should add ZL/ZR support at some point.

Also note that GameCube binds X to 'back' rather than B, this will be fixed by SDL_ActionSet for 2.5.
2024-01-18 00:10:20 -05:00
TerryCavanagh
ceaaea1597 fix Arabic credits
Eternal Dream Arabization team name was missing from the main credits page
2024-01-17 15:59:16 +01:00
TerryCavanagh
9c656fd5e1 Added SnDream to contributors
for this pull request: https://github.com/TerryCavanagh/VVVVVV/pull/1119
2024-01-16 12:05:45 +01:00
TerryCavanagh
4acc96e707 added Space-G to contributors
for this pull request: https://github.com/TerryCavanagh/VVVVVV/pull/1114
2024-01-13 15:47:09 +01:00
mothbeanie
7ff2e818cd Revert text image fading
This reverts the following commits:

- 29f05c41b1
- f1bf1f683c
- a7b22919ae
- 2ed1aac67d

Recently, text images were changed to fade in with textboxes, where
before they previously appeared after the fade. This created a charming
effect where the images would appear to "load in" once the textbox
finishes fading in. This behavior really complements the retro
aesthetic the game is going for. Changing it to a fade is a needless
change in direction, as it was not a bug in the first place and looked
good already.

Additionally, custom levels have used text images (levelcomplete and
gamecomplete) in creative ways by replacing them with something else
to show as 'foreground' or as a cutscene image. Changing text images
to fade has unintended consequences for levels that have utilized
them in this fashion.
2024-01-10 17:43:03 -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
AllyTally
23915e0d22 Fix typing pipes in save/load prompts in editor
13d6b2d64c adds a check where you can't
type a pipe in script/terminal input fields anymore. It does this
completely incorrectly, checking if certain variables are set instead
of checking what's actually trying to be done.

This commit fixes that, simplifying the check a lot in the process.
2024-01-10 08:23:20 -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
AllyTally
f1bf1f683c Fix text images not fading
While a7b22919ae makes text sprites
modulate their RGB values, text images continued using alpha,
despite alpha blending not even being enabled, so the initial
commit didn't work right either.
2024-01-10 07:57:54 -08:00
Dav999
ff25e18945 Move author face to the right for RTL languages
This is quite a last-minute thing that was almost getting called off by
me discovering a critical segfault just now in testing this (whew) but
this shouldn't hurt.
2024-01-10 07:57:40 -08:00
Dav999
95c5bd80e1 Revert "Disable typing pipes in script names"
This reverts commit a806b072bd.

It causes an instant segfault if there's no entities or if you're not
editing terminals/script boxes or something, whatever it's not
crucial as a last-minute fix.
2024-01-10 16:42:01 +01:00
Ethan Lee
b619f38086 Fix Switch button glyphs being double swapped 2024-01-10 09:02:09 -05: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
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
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
Dav999
060fe6938d Add support for right-aligned roomtext
This is mostly so people making levels in an RTL language have a more
pleasant and logical experience. If roomtext is placed in a level set
to RTL, it will get p1=1, which makes that roomtext right-aligned.
Because, imagine for English you click to place roomtext, and the text
runs left of where you clicked, which wouldn't be logical.

Since it's an entity-bound property, switching RTL on and off either in
the editor or via a script does not affect existing entities.
2024-01-09 13:13:04 -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
Dav999
f846ba5d59 Inverse centered text screen border for RTL
If text is set to be centered, but is so long that it starts running
offscreen on both sides, the print function instead makes the text
start no further left than the left border of the screen (x=0).
This is because text running offscreen at the end only is more readable
and looks less sloppy than running offscreen at both sides.

For RTL, the opposite applies, so it now also works oppositely for RTL
prints, where centered strings will only run offscreen on the left side
of the screen.
2024-01-08 19:17:44 -08:00
Dav999
d78338f9ef XFLIP prompts in the editor 2024-01-08 19:17:44 -08:00
Dav999
1b55c6501c Swap definitions of left and right textbox padding
Spaces on the left and right would end up on the other side in RTL,
which made the "You have rescued a crewmate!" text overlap with the
crewmate sprite, and makes the [C[C[C[C[Captain!] dialogs have spaces
on the left instead of on the right. So, best thing is to just swap
the directions so that they match.
2024-01-08 19:17:44 -08:00
Dav999
945f0edaae Ignore directional control chars in font::len()
They're invisible in font::print(), but they were still considered
characters with widths in the width function. This change made the
levels screen look better in RTL too - I was wondering why the level
options were too far left.
2024-01-08 19:17:44 -08:00
Dav999
18dfcff985 XFLIP cursor in roomname translator mode 2024-01-08 19:17:44 -08:00
Dav999
fd0aefe0ee XFLIP LOADING... screen 2024-01-08 19:17:44 -08:00
Dav999
96fa932a8a Don't pass newline characters to bidi algorithm
If you copy-paste a newline character where it's not interpreted, such
as in a level title, the print function wouldn't treat it any special.
font::print_wrap() would, but that's not used here.

However, now that bidi is involved, the newline is passed straight to
SheenBidi which interprets it as a new line (which would need a new
SBLine to be created, or maybe even a new SBParagraph if there's two).
All while we're still treating it as a single line. This means the text
would just stop being displayed after the first newline. This is now
fixed by treating all newlines as spaces.
2024-01-08 19:17:44 -08:00
Dav999
c8dbdc890e Flip Game Complete screen
Obvious "Key: value" things here, this one was easy.
2024-01-08 19:17:44 -08:00
Dav999
3d04d0acbc Mirror time trial results screen
This has a lot of reading-orientation stuff on it like "Key: value",
so easiest is to just flip the whole design of the screen rather than
trying to flip individual strings.
2024-01-08 19:17:44 -08:00
Dav999
79a0ad8493 XFLIP analog stick sensitivity slider properly
The slider itself was getting mirrored, but not the labels
(Low/Medium/High). This fixes that.
2024-01-08 19:17:44 -08:00
Dav999
5620edeb6b Fix orientation of levels list
I forgot to add the PR_RTL_XFLIP flag to these menu options, so they
were always left-aligned, no matter what.

What actually took me a bit to figure out was how to make the level
completion stars work regardless of the contents of the title - the
stars should always be to the left of the title in an LTR language, and
always to the right of the title in an RTL language. Level titles can
contain bidi characters regardless of the level's rtl flag being set,
so I just let bidi handle all the level menu options, with some control
characters to make sure everything always appears in the correct order.
2024-01-08 19:17:44 -08:00
Dav999
3f8333400f Base text box padding/centering on font width instead of codepoints
Stuff like centertext="1" and padtowidth="264" in cutscene translations
looked wrong in RTL mode, both with Arabic and English text. For Arabic
text, I could easily fix the problem by not counting the number of
codepoints (and assuming they all have the same glyph width), but by
instead taking the width of the string as reported for the font, and
dividing it by the glyph width. This leaves English text still looking
weird in RTL mode. But this shouldn't be a problem either: the Arabic
translations will probably be in Arabic (where the problem doesn't
happen), and I can get English text to show up fine by wrapping it in
U+2066 LEFT-TO-RIGHT ISOLATE and U+2069 POP DIRECTIONAL ISOLATE. So it
looks like an inherent quirk of bidi, that translators familiar with
bidi can easily grasp and fix.

This is main-game only functionality, so it shouldn't break existing
custom levels. We should just make sure textboxes in other languages
aren't broken, but from my testing, it's completely fine - in fact, it
should've improved if it was broken.
2024-01-08 19:17:44 -08:00
Dav999
25bdf0866a Make left/right key input correct for RTL menus
Instead of just up/down, you can also control menus with left/right.
Which is illogical in Arabic... No big deal, I imagined this code
to become much worse than it did. (And action sets is probably gonna
refactor the whole thing anyway)
2024-01-08 19:17:44 -08:00
Dav999
2b22f7cda2 Add PR_RTL_XFLIP to some important places
Okay, the "Font:" thing needed some local code after all, because both
the interface font as well as the level font are used there. But it's
good enough - all the other places can just use the flag.

Notably, I also used this for the menus, since the existing ones are
kinda LTR-oriented, and it's something that we don't *really* have to
do, but I think it shows we care!
2024-01-08 19:17:44 -08:00
Dav999
eac612c309 Add PR_RTL_XFLIP print flag
This lets you mirror the X axis specifically in RTL languages, so the
left border is 320 and the right border is 0, and invert the meaning of
PR_LEFT (0) and PR_RIGHT. Most of the time this is not necessary,
it's just for stuff where a label is followed by a different print,
like "Font: " followed by the font name, time trial time displays, etc
2024-01-08 19:17:44 -08:00
Dav999
3588168c4d Right-align textboxes in RTL languages
Most of this diff is just moving some existing code around, and
changing inline things to variables that could be changed more easily.
2024-01-08 19:17:44 -08:00
Dav999
27e83b6008 Add font::is_rtl(uint32_t flags)
This will return if the given flags indicate RTL properties
(such as textboxes being right-aligned).
2024-01-08 19:17:44 -08:00
Dav999
ed0c9b6b1f Add setrtl(on/off) scripting command
With the <font> tag (which doesn't indicate RTL-ness as explained),
we've had a setfont(font) scripting command. Now we have an <rtl>
tag, so we need a setrtl(on/off) command too to control that.
2024-01-08 19:17:44 -08:00
Dav999
29e2b19698 Add RTL level property and print flag
Again, the RTL property controls whether textboxes will be
right-aligned, and that kind of stuff. It can't be font-bound, since
Space Station supports Hebrew characters and we want to be able to
support, say, a Hebrew translation or Hebrew levels in the future
without having to make a dedicated (or duplicated) font for it.
Therefore it's a property of both the language pack as well as custom
levels - like custom levels already had a <font> tag, they now also
have an <rtl> tag that sets this property.

Right now, we'll have to hardcode it so the menu option for the Arabic
font sets the <rtl> property to 1, and all the other options set it to
0. But it's future-proof in that we can later decide to split the
option for Space Station into an LTR option and an RTL option (so both
"english/..." and "עברית" would select Space Station, but one sets the
RTL property to 0 and the other sets it to 1).
2024-01-08 19:17:44 -08:00
Dav999
37c4f76988 Add RTL language property
This doesn't have an effect yet, but it'll do things like
right-alignment in textboxes and other design-flipping.
2024-01-08 19:17:44 -08:00
Dav999
2003eed2a5 Hide unicode directional control characters
They shouldn't be looked up in the font and displayed under any
circumstances.
2024-01-08 19:17:44 -08:00
Dav999
45ec77973b Implement bidi_should_transform()
This now returns true if any of the characters in the text belong to
the Arabic or Hebrew alphabet, or are one of the Unicode directional
formatting characters. This is just so the bidi machinery doesn't have
to run 100% of the time for 100% of the languages. I will also make it
so the Arabic language pack, as well as custom levels, have an RTL
attribute that always enables bidi (and does things like
right-alignment in textboxes and other design-flipping)
2024-01-08 19:17:44 -08:00
Dav999
822755a75f Add Arabic ligature support
Montassar prepared a list of all the ligatures that needed to be
supported, which was a simple A+B->C table, so that one was not too
difficult either!
2024-01-08 19:17:44 -08:00
Dav999
ef712f9f0c Add support for Arabic reshaping
This code can probably be polished a bit more, but the hard part is
over!

This part was written with guidance of this code:
https://github.com/TerryCavanagh/hx_arabic_shaper
2024-01-08 19:17:44 -08:00
Dav999
e011273eb3 Add Arabic reshaping lookup table
This adds the lookup table and an accompanying hashmap that will be
used for reshaping Arabic - it's not yet used though.
2024-01-08 19:17:44 -08:00
Dav999
59ccdbea00 Implement bidi reordering at display time
I'm now using SheenBidi to reorder RTL and bidirectional text properly
at text rendering time! For Arabic this is still missing reshaping, but
everything's looking really promising now!

The code changes are really non-invasive. The changes to Font.cpp are
absolutely minimal:

     1305+    if (bidi_should_transform(text))
     1306+    {
     1307+        text = bidi_transform(text);
     1308+    }

There's now a FontBidi.cpp, which implements these two functions,
notably bidi_transform(), which takes a UTF-8 encoded string and
returns another UTF-8 encoded string that has bidi reorderings and
reshapings applied.

In that function, SheenBidi gives us information about where in the
input string runs start and end, and on a basic level, all we need to
do there is to concatenate the parts together in the order that we're
given them, and to reverse the RTL runs (recognizable by odd levels).

As this is a proof-of-concept, bidi_should_transform() still always
returns true, applying the bidi algorithm to all languages and all
strings. I'm thinking of enabling bidi only when the language/font
metadata enables RTL (which could be for the interface or for a custom
level), or outside of that, at least when RTL characters are detected
(such as Arabic or Hebrew Unicode blocks).
2024-01-08 19:17:44 -08:00
AllyTally
8af57a072a Fix another incorrect autotile 2024-01-08 13:17:59 -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
Dav999
f4bdea7d6d Add a system for selecting between wordy/wordy2
Some languages have different spellings of wordy numbers based on the
gender of the things they're counting (uno crewmate versus una trinket)
or what a number's role is in the sentence (e.g. twenta out of twentu).
We've always had the idea we couldn't support such complex differences
though, because the game can't be adapted to know what gender each
object will have and what word classes might exist in other languages,
so translators would in those cases just have to forgo the wordy
numbers and just let the game use "20 out of 20".

A solution we came up semi-recently though (after all translations were
finished except for Arabic), was to allow the translator to define
however many classes of wordy numbers they need, and fill them all out.
This would not need the game to be *adapted* for every language's
specific grammar and word genders/classes. Instead, the translator
would just choose their correct self-defined class at the time they use
`wordy` in the VFormat placeholder. Something like
{n|wordy|class=feminine}, or {n|wordy_feminine}.

So this would benefit several languages, but we came up with the
solution a little late for all languages to benefit from it. The Arabic
translators asked for two separate classes of wordy numbers though, so
my plan is to first just have a second list of wordy numbers
(translation2 in numbers.xml), which can be accessed by passing the
`wordy2` flag to VFormat, instead of `wordy`.

Once 2.4 is released, we can take our time to do it properly. This
would involve the ability for translators to define however many
classes they need, to name them what they want, and this name would
then be useable in VFormat placeholders. We can convert all existing
translations to have one class defined by default, such as "wordy", or
"translation" depending on implementation, but there's not so much
concern for maintaining backwards compatibility here, so we can do a
mass-switchover for all language files. That said, it wouldn't be too
hard to add a special case for "translation" being "wordy" either.
We can then ask translators if they would like to change anything with
the new system in place.

For now, we can use this system for Arabic, maybe Spanish since there
were complaints about uno/una, and *maybe* Dutch (it has a thing where
the number "one" is often capitalized differently, but it's not
mandatory per se)
2024-01-06 14:11:40 -08:00
Dav999
ce1327f37a Enable SDL_HINT_IME_SHOW_UI to make typing CJK not guesswork
For some reason, the default behavior of SDL and/or Windows(?) (I only
tested this on Windows) seems to result in the fact that if any SDL app
doesn't account for it, there is no way for Japanese and Chinese
speakers to know what they're typing in.

How IMEs are supposed to work is that you can type words as sort of
WIP versions, and then select out of a list of candidates what the
final result should be. The app may display the WIP text and tell the
IME where the text field is so that the IME's menu can be displayed
around it. But if the app doesn't say where the text field is, then the
candidate list can also be displayed at the corner of the screen, which
is done in Minecraft.

By default, however, SDL apps don't get a candidate list at all, which
means you're basically flying blind as to what you're typing in, and
you would have to basically open notepad and copy-paste everything from
there - unless I'm missing something.

This commit sets the SDL_HINT_IME_SHOW_UI hint (added in SDL 2.0.18
apparently), so that the candidate list is at least shown in the corner.
We can probably deal with positioning and uncommitted text later.
2024-01-05 15:24:27 -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
Terry Cavanagh
7bd281ee3d updated credits to include the Eternal Dream Arabization team 2024-01-04 16:29:01 +01: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