127 Commits
Author SHA1 Message Date
Valiantsin Dzerakh 873fc64b41 Merge pull request #1087 into task/pr1087 2026-11-11 13:20:43 +03:00
Valiantsin Dzerakh fc1cf24c42 Merge pull request #1097 into task/kbmwave
# Conflicts:
#	docs/controls.md
#	runtime/cfg.c
#	runtime/input.c
#	runtime/menu_cursor.c
#	runtime/ui/menu.cpp
#	runtime/ui_text.c
#	runtime/ui_text.h
#	totk.ini.example
2026-11-11 13:11:10 +03:00
Valiantsin Dzerakh 24bcc546e9 Merge pull request #1096 into task/kbmwave 2026-11-11 13:10:00 +03:00
Valiantsin DzerakhandClaude Opus 5.5 f23dc9ffb2 Merge pull request #1101: a mod's file named for another game version is served under its own name, so a sound mod that ships one plays (xellow78-lgtm)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 13:08:04 +03:00
Louis JusticeandClaude Opus 5.5 34ee6684a9 In dialogue the left mouse button presses B and the right one A instead of their bindings (dialogue_click, game 1.4.3).
By default the left button is Y, which opens the dialogue log in a dialogue box. While MessageDialog_00 is open the
left button now presses B, which advances the text and shows the rest of a scrolling line, and the right one A.
Dialogue choices keep the menu pointer, where a left click picks the choice under it, so clicking through a
conversation does not pick the choice the focus starts on. The setting is live and independent of menu_cursor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 19:38:43 -05:00
Louis JusticeandClaude Opus 5.5 1becabd8f6 The left mouse button presses A on the Purah Pad's map instead of its binding (map_click, game 1.4.3).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 16:27:03 -05:00
Claude 2cc0a4eaa6 Serve a mod's file named for another game version under its own name instead of leaving it out
A mod file whose name carries Product.<n> and which the RomFS lacks was counted as made for another game version and
never served. The game does ask for such names: on 1.4.3 with mods on, the file trace (trace = fs) shows it opening
Sound/Resource/Pack_MasterSword.Product.110.bars.zs, while its RomFS holds only the Product.140 and the unversioned
file. A sound mod that ships its pack under all those names was silent here and works on a console, where LayeredFS
shows the game every file of a mod. Such files are now added overlays like any other new file. Another version's
resource size table is still not served and still lends its entries; the files are still counted, and the Mods tab
and docs/mods.md now say they are read only when asked for by name.

tests/mods_romfs_check.py gets a case for it. Not run here: the test and --probe-fs need a build and the game's files.
runtime/romfs.c compiles with llvm-mingw.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TgQM2zwuVagwScByEJhT8V
2026-11-10 14:32:15 -05:00
itaskaev2andClaude Opus 5.5 9680b8e6ec Add grass_range: how far around the camera grass grows
The game grows grass blades only inside its near grass map, a 62.5 m square around the camera drawn into 256x256 and
128x128 textures, so on open meadows the grass appears a short way in front of the player. grass_range (percent, 50
to 400, default 100) scales the map's extent, step and both textures together through a new grass patch set (1.2.1
and 1.4.3) that loads them from patch page +128..+144, and grows the HeapDef grass heap and the application pool for
the larger textures. At 100 the set stays off and nothing changes. A row in the Display menu, text in all four menu
languages, and totk.ini.example describe it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 20:13:59 +01:00
Tears of the SteelTemple 3209ea4358 Implement Native NVIDIA Reflex Low Latency (VK_NV_low_latency2)
- Enable VK_NV_low_latency2 and VK_KHR_present_id with present ID features
- Add VkSwapchainLatencyCreateInfoNV to swapchain creation
- Link present and submission IDs with standard Vulkan latency types
- Insert latency markers: simulation start/end, input sample, render submit, and present
- Gate all extensions and latency chains on reflex != off (RESTART setting)
- Log graceful notice when Reflex is requested on unsupported hardware
- Add UI menu setting and translations for en, ru, pt-BR, zh-Hans
- Document reflex setting in totk.ini.example and docs/settings.md
2026-11-10 18:20:16 +01:00
Valiantsin DzerakhandClaude Opus 5.5 06811330e7 Extend the climb controller's frame-rate factor above 60 fps, so Link climbs walls and ladders at full speed (#35, #276, #1001)
The climb velocity step (1.4.3 main+0x1f49754, 1.2.1 main+0x1918220) multiplies the requested velocity by Nintendo's
factor for a movement loss that grows with the frame rate. 1.4.3 fits it at 30 and 60 fps and caps it at 2 from about
77 fps (63% climb speed at 120, 34% at 240); 1.2.1 has no 60 fps branch (78% at 60). Below a 1/60 s step the set climb
continues the factor with a curve fitted to a replayed ladder climb, taking the patch page's frame ratio without the
time scale, so 30 and 60 fps keep the shipping factor bit for bit, slow motion included. Only the player's climb
modules reach this code. Its own setting, climb_fix under [frame rate], with a menu toggle; off without the real-time
step. Ladder replay, 1.4.3: 1.665 / 1.663 / 1.669 / 1.681 m/s at 30 / 60 / 120 / 240 (shipping 120 1.046, 240 0.563).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:44:18 +03:00
itaskaev2 59eb026bd7 Merge branch 'dev' into carry/dynamic-res-100 2026-11-09 09:55:24 +01:00
ipavlin98 6b4d84ec50 Record large submissions in chunks on several threads
replay_workers = N (0, the default, keeps the sequential replay) records a submission of enough draws in chunks that start between passes, on N threads and in twice as many chunks, and submits them in order. In the town at 4K on an RTX 5070, 4 threads take the replay from 8.2 to 4.5 ms a frame and the frame rate from 71 to 79.

A sequential scan on the submitting thread applies only what is queue state (fixed-function and bind ops, render targets, render enable and conditions, samples-passed counting) and keeps a copy of it where each chunk starts, with how far its lists got: inline uniform updates, RENDER_COND results, contact shadow marches and the ops that drop uniform copies. A chunk takes those from the lists instead of from the chunks before it, starts with every image in GENERAL and ends with a full barrier, so its recording depends only on the copy and the lists.

Each thread records with a context of its own: the replay's memos, descriptor state, occlusion query segments and per-command-buffer state moved from file statics into VkExec and VkExecDraw, and the tables the contexts share (stand-ins, depth twins, views, mirrors, timestamps, completion callbacks, crumbs) take locks or atomics. The scan makes render targets live in replay order and notes the op (vk_texture_revive), since a chunk can sample a storage before the chunk that renders it got there or after the scan went past a later target there: a chunk's texture slots resolve as of its own op, and the chunks after a texture with no entry yet wait for the chunk that makes it. Uniform copies are dropped at the op that writes them (vk_usnap_drop_at).

Contact shadows plan their march in replay order (vk_contact_plan) and the chunk that holds its op records it; the HDR source keeps the copy that comes last in replay order. DLSS and fxaa = 0 act on the frame draw by draw and keep the replay sequential. TOTK_REPLAY_STATE_CHECK=1 compares the state after the last chunk with the scan's.

A draw or dispatch whose shaders write storage buffers drops the uniform copies they cover from its own op on, as the other GPU writes do (scan_writes). The scan still translates no shader: it reads the shaders the recording contexts translated from a table shared with them (vk_exec_draw_writes), and an op whose shader no context translated yet holds the chunks after it until it is recorded. Before, the chunk that recorded such a write dropped the copies for every position at that moment, so a later chunk recorded first bound the copy taken at the submit call: on an RX 7800 XT on RADV the grass near the camera came out dark or unshaded in some runs with 4 threads.

TOTK_TRACE=perf counts the chunks held per submission by reason and logs when each chunk of the last submission began. The settings menu has the thread count under Advanced, Scheduling, with the count this run uses under it.

The recorder thread begins, ends and submits the submission's open part (vk_rec.c rec_end_cb), so a chunk's mirror prologue stays off it: vk_sync_part waits until the recorder is idle, as the part pool allows one thread at a time, then records, ends and submits the prologue itself. Through the recorder the prologue could reach the queue before it was ended, and the GPU lost the device at the title screen.

(cherry picked from commit b94e2e9642)
2026-11-08 19:39:17 +03:00
ProSepandClaude Opus 5.5 a6c33b072c Hold the game's dynamic resolution at 100 % and let the scene grow past 4096 wide
The game picks a scene tier of 100, 90 or 80 % mostly from a fixed cost model made for the Switch that grows with the
scene width squared, so on a wide output it drops to 80 % on any GPU: at 5120x1440 every frame drew 80 % of the scene.
Patch set fixres replaces the one instruction that moves the tier's scale into the controller's result (1.2.1
main+0xcc2c00, 1.4.3 main+0x5848a8 as MacNativeGames patches it) with 1.0. The new setting dynamic_res (menu toggle,
live) brings the game's stepping back and is on by default in the Steam Deck profile.

The scene cap goes from 4096 to 8192 a side, so render_scale above 80 works on a 32:9 output, and the scene also stays
within a DynamicTextureAllocatorMem under 2 GiB; the log says when it was made smaller. The memory selftest now maps
past the real pool size instead of a fixed 4 GiB, which a larger scene grows past.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 10:55:54 +01:00
itaskaev2andClaude Opus 5.5 d850c2116d Count play time across runs and show it on the Game tab
A host thread adds each second in which the window has the focus and the game presents frames, keeps the total in
<profile>/playtime.txt (every 30 s and at exit) and the Game tab of the settings menu shows it with this run's share.
Texts in English, Russian, Brazilian Portuguese and Simplified Chinese. Closes #720.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 10:52:28 +03:00
Valiantsin DzerakhandClaude Opus 5.5 7f04a104a3 Merge PR #625: a frame queue that frees a window image at its display time, off by default (ipavlin98)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 19:54:21 +03:00
Valiantsin Dzerakh 0d5719858e Merge PR #650: keep the shape of the pre-rendered movies on outputs that are not 16:9 (ProSep)
# Conflicts:
#	runtime/cfg.c
2026-11-05 19:32:18 +03:00
Wintego cb628b08b7 Add keyboard and mouse button prompts (prompts = pc)
The Button prompts row gets a third choice, PC: every button glyph of the game's button font and every image of the
button guide is drawn as the key or mouse button the keyboard defaults press it with (E, Shift, Space, left click, Q,
R, right click, F, Tab, M, 1 to 4, W A S D, Ctrl, C) and the right stick as the mouse, whatever the pad layout. The
setup writes romfs-patches-pc next to the Xbox folders (make_romfs_patches.py --prompts pc, button_icons.py pc_icons);
--binds <totk.ini> draws the keys of its bind_ lines instead. At a game resolution of another shape the game takes
romfs-patches-pc-<w>x<h> (--prompts pc --aspect) in place of romfs-patches-<w>x<h> when it is there.

(cherry picked from commit 3f81cf02be664100bd9c569c53588d620d90b527)
2026-11-04 08:36:28 +03:00
Valiantsin DzerakhandClaude Opus 5.5 56b3cd1246 Drop the keyboard prompts of #483 in favour of #585
#483 draws the stick glyphs on the wrong code points: U+E056 and U+E057 (the stick presses) get WASD and the mouse,
U+E05E and U+E05F (the sticks) get Ctrl and C, and both left-stick HUD images show Ctrl. #585 maps them by the game's
font and keeps each glyph's advance.

This reverts commit cd35ffa.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 08:35:35 +03:00
Valiantsin DzerakhandClaude Opus 5.5 3676e299c5 Add a shake key that detaches a fused part held with Ultrahand
G (bind_SHAKE, keys only) swings the right stick left and right for 0.8 s, longer while held, so a part comes off
without shaking the arrow keys by hand. The pad keeps shaking its own stick. Remappable in the Controls tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 08:35:12 +03:00
Valiantsin DzerakhandClaude Opus 5.5 d0579731c5 Make the direct mouse camera the default and add a Controls row for the menu pointer
mouse_mode now defaults to direct: on 1.4.3 the camera turns by the raw mouse motion; 1.1.0 and 1.2.1 have no hooks
and keep stick emulation, and no setting changes the gamepad. The Controls tab gets a "Mouse in the game's menus" row
for menu_cursor, and the mouse rows are in all four catalogs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 08:18:29 +03:00
0xEmz cd35ffaf36 Show keyboard and mouse icons in the prompts when prompts = keyboard
Add keyboard and mouse button icons to tools/button_icons.py and
tools/make_romfs_patches.py --prompts keyboard, with a third 'Keyboard
and mouse' choice under Controls > Button prompts (prompts = keyboard).

Keycaps cut their labels out of the game's own text fonts, mouse clicks
and right-stick camera look draw clean mouse silhouettes, and
make_romfs_patches.py --ini reads any bind_ overrides from totk.ini.
2026-11-04 08:11:06 +03:00
walterwhite69420 050563687b Add experimental direct mouse camera input for game 1.4.3 2026-11-04 07:55:49 +03:00
ProSepandClaude Opus 5.5 8a8ef05241 Keep the shape of the pre-rendered movies on outputs that are not 16:9
The game stretches each decoded movie frame over the whole canvas, so the 16:9 movies were stretched on 32:9, 21:9 and
16:10 outputs. The host decoder now shrinks the picture inside the frame with a box filter and fills the rest with
black, so that the game's stretch gives the picture its own shape back. The new setting movie_aspect (TOTK_MOVIE_ASPECT,
keep or stretch, read when a movie starts) turns it off, and the menu has a row for it next to the picture shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 23:27:39 +01:00
ipavlin98 6ac2da7e8f Add a frame queue that frees a window image at its display time
nvnWindowAcquireTexture holds the game until the image is free, which was one period after its present's display time, when the next frame reaches the display. The present is a copy queued by then, so with frame_queue = 1 the image is free from that time: the game draws the next frame while the previous one waits for its turn, and a frame that takes up to one period more still makes its slot. In the town at 4K at 60 fps on an RTX 5070, frames over 17.5 ms fell from 25-33 to 1-8 per 30 s, for up to one frame more input delay. Off by default; the menu switches it at once.
2026-11-03 23:13:41 +03:00
Valiantsin DzerakhandClaude Opus 5.5 a732c16ce6 Merge pull request #438: 5.1 surround output (Specht2010)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 20:35:41 +03:00
Valiantsin DzerakhandClaude Opus 5.5 69e7bef868 Merge dev into task/discord
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 20:11:51 +03:00
Valiantsin DzerakhandClaude Opus 5.5 13e9ffec38 Merge pull request #455: Discord Rich Presence, off by default (avrahambenaram)
Conflicts in cfg.c (the key list) and main.c (the usage line) resolved by keeping dev's lines and adding the
Discord keys and --probe-discord.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 20:11:12 +03:00
Valiantsin Dzerakh 85123016c2 Merge task/smallfixes: game languages in the F1 menu (#580), versions and lows in the overlay (#587, #588), no console and a raised window at start (#208, #521)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	runtime/cfg.c
2026-11-03 20:10:23 +03:00
Valiantsin DzerakhandClaude Opus 5.5 3422952e85 Show the versions, 1% low and 0.1% low in the full performance overlay (#587, #588)
The panel opens with the port version and the game update, so a screenshot in a bug report carries both. Under RAM,
after a gap, two rows on the same grid: FPS with the 1% and 0.1% lows, and the frame times. perfmon.c keeps a
histogram of frame times in 0.25 ms bins, one slice per second over the last ten seconds, and reads the lows from it
twice a second.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 20:09:22 +03:00
Valiantsin DzerakhandClaude Opus 5.5 beb93276eb Offer every game language the build ships in the F1 menu (#580)
The game language row listed eleven languages. 1.4.3 also ships Brazilian Portuguese (Mals USpt), and every build
ships British English, Canadian French and Latin American Spanish (EUen, USfr, USes), which ov_language already
accepted. ui_text_game_langs lists them per game build: pt-BR from 1.4.3 on, since 1.2.1 has no USpt. A row selects
only its own code, so en-GB and es-419 no longer show as English and Spanish.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 20:09:22 +03:00
Valiantsin DzerakhandClaude Opus 5.5 5024daf40d Merge pull request #534: DLSS / DLAA on Linux, a DLSS model choice, the real frame time and a character-trail mask (SchulzCode)
Merged on top of #566 and #594, by hand in vk_dlaa.c:
- One dlss_preset key: default keeps #594's model per mode (K for DLAA, Quality and Balanced, M for Performance, L
  for Ultra Performance); k, j or any other letter a..m takes that model in every mode, live, recreating the features
  as #534 does. The menu texts say so, with pt-BR and zh-Hans added.
- The mask pass stays on #594's camera motion (the identity and the CPU-made reprojection in dlaa_mv.comp's two
  blocks) and adds #534's outputs; it runs before the per-object pass. Where the reactive mask test
  (TOTK_DLSS_REACTIVE) ran, DLSS gets that mask instead of the characters'.
- #566 dropped the scaler_skipped/scaler_missed report, so #534's reset of it goes too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 19:46:27 +03:00
Valiantsin DzerakhandClaude Opus 5.5 80349df1a6 Merge pull request #594: per-object motion vectors for DLSS, Ultra Performance, live DLSS modes and per-mode presets (DizzyMan1337)
Merged on top of #566. The camera motion is #594's: its blocks in camb also feed the per-object pass, and
dlaa_mv.comp stays as on main, fed the identity and the reprojection made on the CPU in double. #566's
vk_usnap_host goes, vk_usnap_bytes serves the same. #566's scaling-draw swap, camera rune guard and output-size
scaling pass stay in vk_dlaa.c. Translator patch 0012 becomes 0015 after dev's 0012-0014.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 19:27:04 +03:00
Valiantsin Dzerakh 18160ef379 Merge branch 'pr/442' into task/hdrhue 2026-11-03 16:18:40 +03:00
DizzyMan1337andClaude Opus 5.5 ad3ecd8f3c Per-object motion vectors for DLSS, camera motion in double precision, Ultra Performance and DLSS presets.
Solid scene draws whose position reads an object's own uniform blocks (bones c5, place c7, c6) are drawn a second time
with a vertex shader variant (translator patch 0012) that computes last frame's position from last frame's blocks; the
game writes those into two copies that take turns, and the uniform snapshot keeps both (vk_mvprev.c). The draws are
listed during the replay and recorded through the recorder thread with repeated state skipped. Blocks whose last-frame
copies measured wrong (c9 and c11 of walls and cliffs) keep this frame's; positions without an object block (terrain,
grass) keep the camera's motion, which measured as good.

The camera motion is reprojected in double precision on the CPU: the float inverse made noise on far surfaces and a
still camera that DLSS followed into a wobble. DLSS gets Ultra Performance (a third of the output, also in the F1 menu)
and NVIDIA's recommended preset per mode (K, M for Performance, L for Ultra Performance; TOTK_DLSS_PRESET overrides).

Test switches: TOTK_MV_CHECK measures the motion vectors and DLSS's output against the picture, TOTK_DLAA_TIMES times
DLSS and the motion passes on the GPU. A reactive mask pass for transparents is included but off (TOTK_DLSS_REACTIVE):
its mask covers sky and fog too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 17:31:58 +08:00
SchulzCode 1d49f64f34 Reduce DLSS trails behind moving characters with a bias mask
The motion vectors follow the camera only, so a character, animal or held item that moves on its own drags a faint
copy of itself through DLSS's history. TotK's G-buffer target 0 carries an object class in green: above 64/255 for
characters, creatures and held items (Link 253, others 125, held items 160), 0 for terrain and 32 for foliage, checked
in the field, in Goron City and on horseback. The motion-vector pass now also writes DLSS's bias mask
(DLSS.Input.Bias.Current.Color.Mask) where such an object is now or was the frame before, read through the motion
vector from the previous frame's class mask, so the history that holds the moving object is weighed down there.
dlss_char_mask (0, 35, 65 or 100 percent, default 65; F1 > Screen > "DLSS character trails", live) sets the strength.
A 640x360 pass of the G-buffer's shape, seen while loading, no longer replaces the scene's class buffer in a frame.
The status line also prints after 300 frames, with the frames that had the mask.
2026-11-02 19:21:56 +01:00
SchulzCode bd54e701a8 Choose the DLSS model and pass DLSS the real frame time
dlss_preset (default, k or j; F1 > Screen > "DLSS model", live) sets the render preset hints when a DLSS feature is
created. default leaves the choice to NGX (preset K for DLAA, Quality and Balanced in the 310 releases); j is the
transformer model NVIDIA describes as slightly less ghosting at the cost of more flicker. A change recreates the
features at the next DLAA run. FrameTimeDeltaInMsec now carries the time since the previous evaluation instead of a
fixed 16.67 ms. The menu and totk.ini.example name the DLSS model file of the platform in use.
2026-11-02 19:21:56 +01:00
Avraham ab32d00cc9 Merge remote-tracking branch 'origin/dev' into discord-rich-presence 2026-11-02 13:11:39 -03:00
Specht2010andClaude Opus 5.5 5d254e462c Merge dev into the 5.1 surround output
The device sink loop now writes every output channel; upstream's TOTK_AUDIO_DUMP gets the front pair before clipping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 11:44:25 -04:00
Valiantsin DzerakhandClaude Opus 5.5 710b7f5dd0 The device-lost report names the pass or dispatch the GPU was running
The replay marks the start and the end of every render pass and dispatch
(vk_exec.c vk_exec_pass_begin and vk_exec_pass_end, vk_exec_draw.c
op_dispatch and op_dispatch_ind), outside the pass so no pass is broken.
With VK_AMD_buffer_marker the GPU writes the last started and finished mark
into words 2 and 3 of the breadcrumb buffer; with
VK_NV_device_diagnostic_checkpoints the same points are checkpoints, read
with vkGetQueueCheckpointData2NV after the loss. A ring of 4096 records maps
a mark to its submission, index, target formats and size, draw count and the
input ids of the first and last draw's shaders. vk_device_fault_report logs
both marks with their records. The calls go through the recorder thread.

TOTK_PASS_CRUMBS (menu: GPU pass marks): unset, AMD buffer marks only; 1,
also NVIDIA checkpoints, whose extension is enabled only then; 0, none.
The design follows Savage Wind Recomp 3fae40c; the code is ours.

--probe-vkexec gets a pass marks part: pass, dispatch, pass in one
submission; the marks read back after the fence name the last pass and the
report text says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 09:50:30 +03:00
Avraham 664ee03759 Add Discord Rich Presence, off by default.
A host thread speaks Discord's documented IPC protocol to a running client
through platform.h's new plat_ipc_* (a named pipe on Windows, a Unix socket
in $DISCORD_IPC_PATH, $XDG_RUNTIME_DIR, $TMPDIR or /tmp on Linux) and shows
the game update and the elapsed play time as the status of a configurable
application. It never holds a virtual core, picks up settings changes within
half a second of the menu writing them, re-sends the activity once a minute
as its keep-alive, answers the client's Ping frames and reconnects 15 s
after a break; Discord clears the status when the process ends.

The Menu tab of the settings menu switches discord_rpc, and discord_app_id
and discord_image in totk.ini name the application and its art asset (a
player can register their own). The default app id is the one this was
developed against; the maintainer may want to register a project-owned one
and swap it. --probe-discord runs the exchange without the game: it caught
the opcode numbering (Handshake is 0, not 1) against a live client.

Tested on 1.4.3, Linux: probe passed end to end against Vesktop's arRPC
bridge, an invalid app id falls back to the default, selftest clean.
2026-11-01 22:12:58 -03:00
Specht2010andClaude Opus 5.5 a6b56288d5 Add a highlight hue correction to the HDR tonemap
The game's SDR clamp turns bright saturated colours towards white: a torch flame clips red, then green, and reads
yellow-white, the colour its emitted light was tuned to. The extended HDR curve keeps the channel ratios, so the same
flame stays deep orange next to the yellow light it casts. hdr_hue (0 to 100, default 80, live) moves colours from the
picture's white upwards towards the game's own SDR result at the HDR luminance, as RenoDX's TotK mod does. It rides in
the support buffer's HDR vector (z), unused until now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 18:11:25 -04:00
Specht2010andClaude Opus 5.5 963901cc12 Add 5.1 surround output
The mixer folded the game's 5.1 device sink down to stereo and IAudioDevice told the game it had two channels.
audio_channels (auto, stereo, 5.1; Sound tab, Speakers) now opens the SDL stream with six channels in the device sink's
order (FL FR C LFE RL RR) and reports six to the game, which then mixes for 5.1. auto picks 5.1 when the default
playback device has six or more channels (a 5.1 or 7.1 speaker setup in Windows) and stereo otherwise; stereo keeps
the existing downmix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 17:50:30 -04:00
Wellington Dias 2215c3fc2f Merge branch 'dev' into stick-deadzones
# Conflicts:
#	docs/controls.md
#	runtime/cfg.c
#	runtime/input.c
#	runtime/ui/menu.cpp
#	runtime/ui_text.c
#	runtime/ui_text.h
#	totk.ini.example
2026-11-01 13:42:21 -03:00
Valiantsin DzerakhandClaude Opus 5.5 c3dae879cb Build the mods' ExeFS patches into the game and switch them with their mod
A mod that patched the game code (.ips, .pchtxt) stayed off as a whole.
tools/exefs_patches.py now reads IPS, IPS32 and IPSwitch files from each
mod's exefs folder and from atmosphere/exefs_patches/<name>/. It keeps the
ones whose build id is main's and turns their writes into main's code into
one patch set per file. The writes go through the same rules as the code
cheats (tools/cheats.py convert). A file that writes main's data, or that the
rules cannot express, is unsupported as a whole. The setup's lift runs it
after cheats.py and writes build-cache/exefs.status.

runtime/mods.c checks each patch file against that status:

- a built file's set is switched on with its mod;
- a file the build lacks keeps the mod off and starts the rebuild at the next
  start, like a code cheat does;
- an unsupported file keeps the mod off, and the Mods tab shows the reason;
- a file for another version is counted and left out.

A mod patch on a site of one of the port's own sets turns that set off while
the mod is on, and the Mods tab names it. The Mods tab also gets the "Rebuild
the game now" row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:29:40 +03:00
Valiantsin DzerakhandClaude Opus 5.5 1bebcfd9ef Rebuild the game at start when an enabled mod has unbuilt code cheats
Code cheats need the game lifted and compiled with them. Running the setup
again did that, but it lifted and compiled everything and prepared the
shaders again.

- The setup keeps the generated C and the objects in its temp folder (about
  1.3 GB). gen.py rewrites only the chunks whose C changed, so Ninja
  recompiles only those. One new code cheat on 1.4.3 took a 47 s lift and
  19 s of compile and link on 24 cores.
- Prepare's key no longer follows the compile key, only the runtime, the
  translator and the game version, so a rebuild keeps the prepared shaders.
- The cleanup writes build-cache/rebuild.txt, the command that opens the
  setup window in a new --rebuild mode on the install folder. That mode runs
  at once and starts the game again when it succeeds.
- At start, runtime/cheats.c runs that command and exits when an enabled
  mod has code cheats the build lacks (plat_spawn, new for Windows and
  Linux). build-cache/rebuild.skip keeps a failed or cancelled rebuild from
  starting again for the same cheats. "Rebuild the game now" on the Cheats
  tab tries again, and [mods] mods_rebuild = off turns the rebuild off.
  Scripted runs never start it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:16:53 +03:00
Valiantsin DzerakhandClaude Opus 5.5 ac69f39529 Read cheat files from the mods folder instead of shipping them
A cheat file is now part of a mod: mods/<mod>/cheats/<build id>.txt, or the
Atmosphere places inside the mod folder, the file name in any case. The port
ships no cheat files any more (the MyNXCheats files and their notice row are
gone).

- tools/cheats.py --mods builds the code cheats of every mod folder; a
  cheat's key hashes "<mod folder>/<name>", so two mods' cheats of one name
  keep their own switches.
- The setup reads the cheats from <install>/mods and writes the status to
  build-cache/cheats.status.
- runtime/cheats.c reads the files of the enabled mods the port can use, in
  the Mods tab order, and the status from build-cache.
- A mod with only cheats is usable. The Cheats tab groups the cheats by mod,
  and the Mods tab says how many cheats a mod brought.
- The cheat texts are in all four menu languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:05:31 +03:00
Valiantsin DzerakhandClaude Opus 5.5 5e584ea966 Merge pull request #51: Load Atmosphere cheat files and switch their cheats from a Cheats tab in the menu (conongnang)
Merged onto the mods folder (task/mods1); the Cheats tab sits after Mods. The cheats' menu text and the cheat file's
place are reworked for the mods folder in the commits that follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:31:17 +03:00
Valiantsin DzerakhandClaude Opus 5.5 acf2e10bc5 Mark a mod the port cannot use as not used under its switch
Its row said On like a working mod, and only the description pane told why nothing happened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:17:48 +03:00
Valiantsin DzerakhandClaude Opus 5.5 fa59758f63 Add a Mods tab: the mods folder with switches and load order, and the port's own patches
Each mod is a row with its switch, the files it serves and why it is unused when it is; the top and left face buttons,
Ctrl+Up and Ctrl+Down or the drawn arrows move it. The real-time step, cloth and high-fps fix switches move here from
the Game tab under the port's own patches. The text is in the catalog in English, Russian, Brazilian Portuguese and
Simplified Chinese. The tester guide says where mods go and how TKMM's merged output fits in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 13:14:37 +03:00
Valiantsin DzerakhandClaude Opus 5.5 8a2e52b929 Merge task/prgfx: sun shadow cascades, PCSS, contact shadows and DLSS/DLAA from #89 and #113
runtime/cfg.c: the known names take both sides, the per-stick dead zones beside the shadow and
DLSS switches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 12:35:42 +03:00