Phase 3 coverage slice. Player and staff notify paths that still used
T() (cast-only) now use M_() so they extract into the catalogue:
move arrive/leave, get/drop, teleport failures, home
walk destination, blocked, patrol
help missing topic, match list, file errors
guest busy/create errors, listing total
quota Quota/Used display templates
powers Power not found, @power echo, Powers: header
session Poll / Doing
Attribute names, flag/power registry keys, logs, HTML, and softcode
machine tokens stay T()/S_(). Regenerates pot (670 -> 704) and xx.po.
Replace ~900 typographic \xE2\x80\x.. escapes (curly quotes, en dashes)
and a few \xE2\x80\230 octal workarounds with real UTF-8 in message
strings under mux/modules and mux/src. Leave stringutil and convert
charset mapping tables as explicit byte sequences.
Five literals were marked M_() at one site and left T() at another, so the
same message was translatable in one context and not the other:
Dropped. Taken. You can't drop that.
You can't go that way. You can't leave.
rob.cpp had none of this; move.cpp had all five.
Taken. shows why it matters. The marked copy went to the OBJECT, while the
copy the PLAYER reads was still T():
notify(thing, M_("Taken.")); // to the thing
did_it(executor, thing, A_SUCC, T("Taken."), ...); // `def` -> the player
did_it's fourth argument is the default shown to the player when the object
has no @success, so with "Taken." in a catalog, mux_gettext returned the
translation while `take widget` printed English.
Half-marked is worse than unmarked. Unmarked is honestly untranslated;
half-marked means a translator translates the string and then sees it appear
in their language in one context and English in another, with nothing in the
catalog to distinguish them.
The five promoted sites are all player-facing defaults:
674 move_exit(..., "You can't go that way.")
781 did_it(..., A_SUCC, "Taken.")
888 did_it(..., A_DFAIL, "You can't drop that.")
911 did_it(..., A_DROP, "Dropped.")
1057 did_it(..., A_LFAIL, "You can't leave.")
The msgid set is unchanged -- these are the same strings already in the
catalog -- so only the reference comments in tinymux.pot move. Verified by
diffing the sorted msgid lists before and after: identical.
Verified with a catalog carrying the two confirmations plus an identifier and
an ABI token:
before take widget -> Taken. (untranslated)
after take widget -> [xx] Taken.
drop widget -> [xx] Dropped.
ABI=#-1 DIVIDE BY ZERO (intact)
FN=5 (abs() still resolves)
English smoke on the NLS build: 1505 passed, 0 failed, 316/316.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Next notify slice after create/quota: whole-sentence player messages in
rob.cpp (give/kill) and move.cpp (go/home/take/drop). Leave tprintf
formats and HTML/protocol fragments as T(). Regenerate pot and xx
pseudo-locale (~62 msgids catalog-wide).
Completes the sweep the issue called for. mux_atol returns long, which
is 32-bit on LLP64, so every caller silently truncated on Windows. Two
of those were real defects (the truthiness family and cf_size, fixed in
the preceding commits); the rest were latent, waiting for a value large
enough to matter.
Rather than audit 290 sites for whether each can reach 2^31 today, use
the 64-bit parser everywhere and remove the class. A dbref cannot
overflow now, but nothing stops a later caller passing that same site a
timestamp or a byte count.
Pure 1:1 substitution: 285 lines changed, and every removed line
contained mux_atol while every added line contains mux_atoi64. No
control flow, no types, no behaviour beyond the wider parse.
This is a NO-OP on LP64 -- long is already 64-bit on Linux and macOS, so
the generated code there is unchanged. It only widens the parse on
Windows. Narrowing destinations are unaffected either way: `int x =
mux_atoi64(s)` truncates exactly as `int x = mux_atol(s)` did, on both
models.
Left alone: mux_atol itself in mathutil, its declaration, and three
comments that name it. Callers that genuinely want 32-bit semantics can
still ask for them; none appear to.
Verified on Windows: full solution builds clean with no new warnings,
smoke is 1418 passed / 16 failed / 0 crashes / 306 of 306 dispatched --
identical to before the sweep, with the same 16 build-configuration
failures (exp3 module not loaded, hmac/digest behind UNIX_DIGEST).
Spot checks after the change: the boolean family returns 1 for multiples
of 2^32, cf_size round-trips 3000000000 and still reads -1 as unlimited,
and arithmetic, string and list functions are unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replace manual alloc_lbuf/free_lbuf pairs with LBuf RAII wrappers
in 12 engine source files: rob, walk, quota, wiz, session, object,
log, match, move, create, flags, boolexp. This eliminates ~40
explicit free_lbuf calls on error paths that are now handled by
destructors, removing leak risk in early-return and multi-exit
functions (boolexp alone had 13 exit-path frees across two
functions). Buffers returned by atr_get/atr_pget or to callers
are left manual since LBuf cannot adopt externally-allocated
buffers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Story 1a — cache_max_size with K/M/G suffixes, -1 for unlimited, default
raised from 1 MB to 256 MB. @list cache shows human-readable sizes.
Story 1b — cache_preload_depth controls BFS depth for preloading adjacent
rooms. Unlimited mode: GetAll for player/location, GetBuiltin across BFS
neighbors. Bounded mode: GetBuiltin for player/location only, no BFS.
Move path preloads destination synchronously, defers BFS neighbors via
scheduler to avoid latency on look_in().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>