Skip to content

feat(menu): a Text size row for dialogue, Navi and signs - #1579

Merged
hckrman101 merged 1 commit into
NotRexed:mainfrom
getzabelz:feat/text-size
Nov 10, 2026
Merged

hckrman101 merged 1 commit into
NotRexed:mainfrom
getzabelz:feat/text-size

Conversation

@getzabelz

@getzabelz getzabelz commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Adds a Text size row to the Insert menu's Gameplay tab, under Text speed: Original, 110%, 125%, 150%, 175%. It scales the text of dialogue, Navi and signs, for players who find the game's text small: on a TV across the room, or with low vision.

I have low vision myself, and the game's dialogue text is hard for me to read at its own size. That is why I made this row.

What changed

  • host/oot_text_size.c (new): hos_oot_text_pane gets a LetterAnimControl and scales its pane wrapper's 2D scale (+0x28 x, +0x38 y; 0.8 for dialogue) by the menu's choice. It always works from the game's own value: never scaled twice, taken again whenever the game writes it, and given back at Original. A field never scaled is not touched at Original, so the default changes nothing. HOS_TEXT_SIZE=<0..4> stands over the menu, as HOS_TEXT_SPEED does.
  • nx2/oot_patches.py: the letters' block of f_80b1e140 (already patched for Text speed) also calls hos_oot_text_pane(c, c->x[19]). Same anchor as Text speed, so a game version whose code differs keeps its own code, as today.
  • gpu/vk/vk_menu.*, vk_replay.cpp, vk_api.h: the row, its hints, opts.text_size (saved in hookshot_options.ini as text_size) and option id HOS_OPT_TEXT_SIZE (10).
  • readme.md: the row in the options table.

Tests

  • tests/test_text_size.py (new; declares its own RUN_ALL_ARGS): compiles host/oot_text_size.c against a fake guest memory and checks Original, each size, the game writing its value again, a different size after another, back to Original, a missing control/wrapper/pane, and more panes than the host's table keeps. It also checks the menu row, the option id and the patch's call.
  • tests/test_text_speed.py: the patched block passes x19 to the hook.
  • tests/test_rumble_menu.py and tests/test_audio_volume.py (feat: Audio tab in the Insert menu with Volume and Mute in background #1270): their option-id tables now also read one-name HOS_OPT_* enums (as HOS_OPT_TEXT_SIZE), so they still check that no option id is answered twice.
  • python -I -B tests/run_all.py on Windows, rebased on current main: 272 passed, 6 failed. The 6 fail the same way on unmodified main on this PC (local environment); none of them touch these files.

Played

On Windows, with this change applied to a v2.0.13 build's source:

  • character dialogue, Navi and signs grow at each size and go back to the game's size at Original;
  • the choice is kept after a restart (text_size in hookshot_options.ini).

The new size applies from the next conversation: a text box already on screen, or the rest of the conversation it belongs to, keeps the size it was drawn at. Not yet played on a build of current main, or on Linux.

In game

The same line at three sizes (Hyrule Market, 3440x1440):

Original 125% 150%
Original 125% 150%

Other lines, at 110% and 175%:

110% 175%
110% 175%

Measured on these screenshots, against Original:

  • the same line ("Mmm... A ver cómo puedo explicárselo") is 125% as wide at 125%, and 153% at 150%;
  • the lowercase letters are 113% as tall at 110%, 126% at 125%, 149% at 150% and 177% at 175%.

At 175% a long line of text can reach slightly past the edges of the dialogue box. I have seen it while playing: it is only a little, and the text stays fully readable. I would keep this size anyway. As a player with low vision, it is the size that helps me the most, and it will be the same for others.

The row in the v2.0.11 builder's Insert menu (one help line; on current main each value has its own hint):

Text size row in the Insert menu, at 175%

The Insert menu's Gameplay tab gets a Text size row (Original, 110%, 125%, 150%,
175%), under Text speed. It scales the text of dialogue, Navi and signs.

nx2/oot_patches.py's letters' block of f_80b1e140 (a LetterAnimControl's step,
already patched for Text speed) now also calls hos_oot_text_pane with the control
(x19). host/oot_text_size.c scales the diagonal of the pane wrapper's 2D scale
(+0x28, +0x38; 0.8 for dialogue) from the game's own value: never twice, again
from the game's value whenever the game writes it, and back to it at Original. A
field never scaled is not touched at Original. HOS_TEXT_SIZE=<0..4> stands over
the menu, as HOS_TEXT_SPEED does.

The option id is HOS_OPT_TEXT_SIZE (10). tests/test_rumble_menu.py's id table
now reads one-name HOS_OPT_* enums too, so it still checks that no option id is
answered twice. tests/test_audio_volume.py (NotRexed#1270) reads them the same way now.

Tests: tests/test_text_size.py compiles host/oot_text_size.c against a fake guest
memory (Original, each size, the game writing its value again, back to Original,
missing control/wrapper/pane, more panes than the table keeps).
tests/test_text_speed.py checks the hook gets x19. Played on Windows (this change
applied to the v2.0.11 builder's source): dialogue
and signs grow at each size and go back at Original; the choice is kept in
hookshot_options.ini.

Assisted-by: Claude Code (Claude Opus 5.5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@getzabelz

Copy link
Copy Markdown
Contributor Author

@hckrman101 Thanks for the review!

  • Rebased on current main (1392ea3). The conflicts came from feat: Audio tab in the Insert menu with Volume and Mute in background #1270's Audio tab: Text size stays on Gameplay under Text speed, and Audio output stays on the Audio tab. tests/test_audio_volume.py's option-id table now also reads one-name HOS_OPT_* enums, as test_rumble_menu.py already does here, so HOS_OPT_TEXT_SIZE doesn't break it.
  • Screenshots are in the description now: the same line at Original, 125% and 150%, plus other lines at 110% and 175%, measured against Original.
  • On the lock nit, it is taken: host/oot_text_size.c line 57, while (__sync_lock_test_and_set(&lock, 1)) {}, before the table is searched, and released at line 75 (__sync_lock_release). If it reads as unused, I can make it more explicit.
  • Played on a v2.0.13 build with this change: every size, back to Original, and the choice kept after a restart. Not yet on a build of current main or on Linux.

@getzabelz

Copy link
Copy Markdown
Contributor Author

One more note, also added to the description: at 175% a long line of text can reach slightly past the edges of the dialogue box. It is only a little, and the text stays fully readable, so I would keep this size anyway: it is the one that helps players with low vision the most.

@hckrman101
hckrman101 merged commit 4d0645f into NotRexed:main Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant