mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 17:09:57 -04:00
The patch set text_speed scales the typewriter speed of a message the game lets the player skip (fast, three times as fast, its scripted waits as long) or runs the game's own skip on the first frame of each page (instant). Messages the game marks unskippable, such as those that turn their page on a timer, keep the game's speed. The setting is live and has a row on the Game tab in all four menu languages; with it at normal the set is off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
64 lines
2.9 KiB
C
64 lines
2.9 KiB
C
// Text speed for Ocarina of Time 1.1.1 (the patch set text_speed, recomp/patches-v111.txt). The message window shows
|
|
// its text through a typewriter whose speed and waits the message's own tags set, and a press of the decide button
|
|
// while it types shows the page at once, unless the window marked the message unskippable (a message that turns its
|
|
// page by itself on a timer, and some window types). The set's two sites read the patch page words this file writes:
|
|
//
|
|
// +0x200 the typewriter of the message window while its message may be skipped, 0 otherwise (written by the game's
|
|
// code at the first site, read at the second)
|
|
// +0x208 the fast factor less one, as a float: 0 leaves the speed as it is
|
|
// +0x20c 1 for instant: the window's skip runs on the first frame of each page, as if the button were pressed
|
|
//
|
|
// Setting text_speed (live): normal (the game's, and the set off), fast (the skippable messages type
|
|
// TEXT_SPEED_FAST_FACTOR times as fast, their scripted waits as long as before) or instant (the skippable messages
|
|
// show each page at once, as the game's skip does). Unskippable messages keep the game's speed under both.
|
|
#include <stdatomic.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "cfg.h"
|
|
#include "host.h"
|
|
#include "text_speed.h"
|
|
|
|
enum { SPEED_NORMAL, SPEED_FAST, SPEED_INSTANT };
|
|
static const char *const speed_names[] = {"normal", "fast", "instant"};
|
|
|
|
#define PAGE_FACTOR 0x208
|
|
#define PAGE_INSTANT 0x20c
|
|
|
|
static int setting_speed(void) {
|
|
const char *v = cfg_value("NX2NAVI_TEXT_SPEED");
|
|
for (int i = 0; i < (int)(sizeof speed_names / sizeof *speed_names); i++)
|
|
if (v && !strcmp(v, speed_names[i])) return i;
|
|
return SPEED_NORMAL;
|
|
}
|
|
|
|
// Whether the set may run at all is read once, after the start: NX2NAVI_TEXT_SPEED_PATCH=0, or a mod whose code
|
|
// patches the same sites (mods.c mods_exefs_switch), leaves it off then, and switching it on later must not undo that.
|
|
static _Atomic int allowed = -1;
|
|
static int speed_set(void) { return rt_patch_set("text_speed"); }
|
|
int text_speed_available(void) {
|
|
int a = atomic_load(&allowed);
|
|
if (a < 0) {
|
|
a = rt_patch_enabled(speed_set()) && rt_patch_page() != NULL;
|
|
atomic_store(&allowed, a);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
void text_speed_poll(void) {
|
|
if (!text_speed_available()) return;
|
|
int s = setting_speed(), set = speed_set();
|
|
uint8_t *page = rt_patch_page();
|
|
float factor = s == SPEED_FAST ? TEXT_SPEED_FAST_FACTOR - 1.0f : 0.0f;
|
|
uint32_t bits;
|
|
memcpy(&bits, &factor, sizeof bits);
|
|
__atomic_store_n((uint32_t *)(page + PAGE_FACTOR), bits, __ATOMIC_RELAXED);
|
|
__atomic_store_n(page + PAGE_INSTANT, (uint8_t)(s == SPEED_INSTANT), __ATOMIC_RELAXED);
|
|
static int logged = -1;
|
|
if (s != logged) {
|
|
logged = s;
|
|
rt_log("text speed: %s", speed_names[s]);
|
|
}
|
|
if (rt_patch_enabled(set) != (s != SPEED_NORMAL)) rt_patch_switch(set, s != SPEED_NORMAL);
|
|
}
|