Ninetears

✅ 可玩

ninetears

更新 fdf581a 2026-09-12 源码 下载 ZIP 上游 unleashed/ninetears

▶ 开始游玩 · Play Now

A Spanish-language LPMud, also known as Driade / FFICMUD, run by "Alex" ("Tyrael") in the early 2000s, built on a Final Realms mudlib base with substantial custom changes. A real, substantial multi-year archive with dozens of wizard-built home areas and a large domain tree covering Urghak, Faeleen, Keroon, Asgard, Ishtar, Serkesh, and more, alongside several guild systems including trolls, khurgars, chaos barbarians, and jade knights. New characters register (name confirmation, password, gender) and are born into "Plano Inmaterial" (the Immaterial Plane), a soul-formation antechamber room framing character creation as a literal act of spiritual birth before the soul enters the physical world. Player and staff rank in this world carries its own in-game titling lineage -- ordinary mortals, then ascending ranks named after demigods (semidioses), lords, thanes, patrons, regents, and finally the gods (dioses) themselves. The archive also ships an in-game FTP-like file-transfer feature via a listening network service.

README

A Spanish-language LPMud (also known as Driade / FFICMUD), run by "Alex" ("Tyrael") in the early 2000s, built on a heavily-modified FR (Final Realms) mudlib 3.4 base with pieces of the Spanish Calandria-CLIB derivative. Source cloned from git clone https://github.com/unleashed/ninetears. Slug ninetears, number 939, port 40241.

Despite the target's original framing as an "English-language" archive, the actual in-game content -- room descriptions, commands, help text, system messages -- is entirely in Spanish; only the upstream repo's own README.md (a personal note from the author) is in English. See NOTES.md for the full porting log.

A real, substantial archive: ~27,000 files / 933K lines under the mudlib root, dozens of real wizard home directories, a large multi-domain world (Urghak, Faeleen, Keroon, Asgard, Ishtar, Serkesh, and more), several guild systems, and archived player save data from the mud's active years.

Registration flow

name -> "Tu nombre [name] es correcto (s/n) ?" -> password -> confirm password -> gender (h/m) -> lands in "Plano Inmaterial" (a soul-formation antechamber room).

Admin account

Verified live: special immortal welcome banner on login, [Dios de la Administracion]-style title, listed under "Inmortales" in who.

Status

Boots clean, zero fatal errors. Master, simul_efun, and every core base class (std/object, std/room, std/living/living, global/player) compile with only harmless warnings. A brand-new character registers all the way into the game world through the real menu-driven flow, and look/score/who/quit all produce correct output. See NOTES.md for the full compile-sweep breakdown and the encoding-detection story.

Note: /secure/ftpd is preloaded and opens a real listening socket on a hardcoded port (4001) a couple of seconds after boot, for an in-game FTP-style file transfer feature -- see NOTES.md before adding this lib to any automated high-frequency reboot loop.

WASM status: playable. A uptime() < 10 startup-grace gate in secure/login.lpc destructed every connection during the WASM harness's instant-connect window; bypassed for local/loopback connections only. The preloaded FTP daemon simply fails to compile without the sockets package (a graceful, non-fatal preload skip). Full registration/mirar/score/salir verified clean after the fix. See NOTES.md \S12.

Local run

cd libs/ninetears
~/src/fluffos/build-debug/src/driver config.fluffos

Game port: 40241.

NOTES · 移植与修复记录

Ninetears -- porting notes

Source: git clone https://github.com/unleashed/ninetears (commit 4edd22c75e3fa99be4b5820300491c6b62e06085, cloned 2026-08-26). The repo's own README.md is a short first-person note from "Alex" (in-game "Tyrael", "Driade's Supreme Deity"), releasing his backup of a mud he ran "in early 2000's for a couple of years", based on "FR 3.4, with a few changes from a Spanish mudlib named Calandria" -- "over 1.25 million lines added and about 125k removed in about 28,000 files" per his own changeset description. Confirmed genuine and worth the full pipeline: 28,092 files in the raw clone (27,123 under the actual mudlib root once the bundled driver source and top-level stray files are excluded), 148MB, real multi-year wizard-authored content, and archived player save data for real accounts. Slug ninetears, number 939, port 40241.

0. Language mismatch with the task brief -- worth flagging explicitly

The task that produced this port described the target as "confirmed definitively ... English-language" from an earlier research pass. That turned out to be wrong on direct inspection: the upstream repo's own README.md (a personal note from the author) is in English, but every piece of actual in-game content -- room descriptions, help text, system messages, comments in the source -- is in Spanish. LEEME (Spanish for "read me") and LICENCE.fr (also Spanish) sit right next to the English README.md at the repo root. This wasn't a blocker -- this project already hosts plenty of non-English archives -- but it did matter for the encoding-detection step below, since the "pure ASCII English archive" assumption from AGENTS.md's usual fast path doesn't apply here; the archive turned out to be a Spanish text encoded in a Latin-1-family single-byte encoding, not ASCII, not GB18030/Chinese.

1. Root layout: only mudlib/ is the mudlib

The repo root has mudlib/ (the actual mudlib root, matches mudos/bin/config.fficmud's mudlib directory : /devel/mud/fficmud/mudlib), mudos/ (bundled MudOS v21/v22 driver source + a prebuilt Windows binary -- excluded, this project uses its own FluffOS build), and a few top-level stray files (LEEME, LICENCE.fr, README.1ST, RUN-HOWTO, and a lone lord.c -- an orphaned wizard-sandbox object that lives outside the mudlib root and is not referenced from within it, confirmed by grep). Only mudlib/ was copied into raw/.

2. Encoding: Windows-1252 (Latin-1 family), NOT the default GB18030 --

caught only after a first, silently-wrong conversion pass

The very first convert_lib.sh run used this project's default GB18030 source encoding (the overwhelming majority of this corpus is mainland-China GBK/GB18030 wuxia content). GB18030 is permissive enough that it doesn't error on Latin-1 Spanish-accent bytes -- it just decodes them as the WRONG (but valid-looking) codepoints, producing silent mojibake with no error/warning anywhere in the conversion log. Caught this by manually diffing a converted file's Spanish text against the raw bytes: room/raceroom.c's "\n\n\xbfQu\xe9 eliges?" (Spanish "¿Qué eliges?", "What do you choose?") came out of the GB18030 pass as "\n\n\xe7\xbc\x8cueliges?" -- a real but wrong CJK character sequence, not an error. iconv -f WINDOWS-1252 (and, equivalently here, -f ISO-8859-1) on the same bytes produces the correct "¿Qué eliges?".

A pre-check with a naive grep -rlP '[\x80-\xFF]' initially (and wrongly) reported zero non-ASCII files -- this turned out to be a grep -P/locale quirk on this environment (the same command under LC_ALL=C still reported zero even on a file confirmed by xxd/Python to contain the exact bytes in question). A direct Python byte-level scan (any(b >= 0x80 for b in data)) is the reliable check and found 970 files with high-byte content, consistent with the converter's own tally after the corrected run (633 clean-decoded + 307 lossy under the wrong encoding, ~940 total -- the small gap is files whose non-ASCII bytes happened to already be valid, if coincidental, UTF-8 sequences). Lesson for future archives: don't trust a grep -P byte-range non-ASCII check on this environment without cross-checking a positive hit with a direct Python byte scan first -- verify the tool before trusting a "zero" result, especially before picking a default source encoding.

Re-ran convert_lib.sh libs/ninetears/raw/mudlib libs/ninetears/work WINDOWS-1252 (the script deletes and recreates work/ from raw/, so this was a clean re-run, not a patch over the wrong one). Confirmed correct post-conversion: room/raceroom.c's line above now reads "¿Qué eliges?" verbatim, and a live boot's welcome banner renders "© Vilat 2002" with a correct copyright glyph. A handful of directories in the archive are historically double-saved under both an accented and an ASCII-transliterated name (e.g. d/faeleen/rooms/rongrond/viñedos_sur/ alongside a separate, independently-existing vinyedos_sur/ with "ny" substituted for "ñ") -- pre-existing archive content, not touched.

30 files remain non-UTF-8 after conversion, all confirmed genuine binary media (.jpg/.gif/.bmp/.wav/.tar.gz/.tar.bz2), vim swap files (.c.swp), or leftover original-server tmp/MudOS_swapfile.* runtime files -- none of them LPC source, all correctly left untouched.

3. .c -> .lpc rename and reference fixups

22,259 .lpc files after rename. 47,673 literal .c" reference fixups applied cleanly (0 remaining). 0 angle-bracket #include <...c> references needed fixing. 9 local angle-bracket includes converted to quotes (the <local.h>-next-to-includer pattern from AGENTS.md §6.1), harmless/additive since this archive's headers all resolve through the single global /include/ directory in the vast majority of cases anyway -- no master::get_include_path() override was needed; every #include <foo.h> seen resolves against /include/foo.h directly.

4. static -> nosave sweep

173 files touched. No #define nosave static/#define protected static compatibility-shim collision found (AGENTS.md §4.3's second class). No "static string-literal collision found either (the first class) -- checked via grep '"static' post-sweep, zero hits.

5. Compile verification -- clean on the first attempt

Before running any batch sweep, compiled the small set of widely-shared base classes individually with lpcc (single-file mode, which also loads master + simul_efun + preload as a side effect of booting the compile VM), per this project's RAM-safety discipline:

Given this clean baseline, ran the full lpcc_check.sh batch sweep with RSS watched every ~15s throughout (peaked around 2.9GB, well under the 10GB danger threshold this session's other libs were warned about). The first pass came back at 8172/22259 (36.7%) -- see §5a below for a real, fixable shared-root-cause found by triaging the failure log before accepting that number, and §5b for the corpus's actual composition (genuine archive gaps, not a driver-compat bug) behind most of the rest.

5a. One real shared-root-cause bug found and fixed: a textually

#included file's global variable landing before an inherit

Per AGENTS.md §6.4 ("one shared root cause, not N bugs"), grepped the first-pass failure log's error messages by frequency before treating 14,087 failures as unfixable archive noise. error: Illegal to inherit after defining global variables. (419 raw occurrences) traced back to exactly two real bugs, both a variant of the classic §6.1 "inherit after globals" dialect issue that this project's catalog hadn't previously seen via a textual #include rather than a literal same-file declaration:

1. /d/gremios/hechizos/base.lpc (the base class every guild spell in the live spell system inherits) does #include ".../bases/patch.lpc" -- which declares mapping environment_mods; -- textually *before* its own inherit ".../bases/tipos.lpc";. Since #include is a textual paste, the compiler sees a global variable declaration ahead of the inherit statement, identically to the same-file case, just one indirection removed. This single file is the base for the guild spell system covered by d/gremios/hechizos/ (spells, items, wizard spells) -- fixing it alone recovered ~340 cascading failures across that whole subtree, this port's version of mortremains's std/monster.lpc win. Fixed by swapping the two lines (inherit first, then the #include) -- inherit order is otherwise unaffected since patch.lpc doesn't need anything from tipos.lpc before it loads. 2. Eight more d/gremios/hechizos/ files (items/fang.lpc, wizard/areabas.lpc, wizard/shield_s.lpc, combined/{acid_arr,burnhand,conecold,det_magi,horrid_w}.lpc) had the same shape directly (their own global variables -- spell name/ cost/damage-type constants -- declared before their own inherit ".../base.lpc" or .../patch.lpc" line). Fixed each by moving the inherit line above the file's own variable declarations. (A ninth, near-identical file, combined/old/acid_arr.lpc, was left alone -- confirmed genuinely dead/orphaned: nothing references the old/ subdirectory, and it inherits a second, entirely nonexistent /std/spells/patch.lpc regardless of inherit order.) 3. ~46 room files under /d/ss/daggerford/ (a real city zone, not an antiguo-labeled dead one) all shared: #include "path.h" / #include "/std/outside.lpc" / inherit CITYROOM;, with /std/outside.lpc itself declaring nosave string night_long; / nosave string dark_long; before the room's own inherit CITYROOM -- the identical bug shape via a different textually-included file. Reordering alone (moving inherit CITYROOM; above the #include) traded this error for a second, previously-latent one: error: Illegal to redefine 'nomask' function 'query_dest_dir'. -- because /d/ss/daggerford/cityroom.lpc (the file CITYROOM points at) *already* does inherit "/std/outside"; itself, so the room's own separate #include "/std/outside.lpc" was a redundant second copy of the exact same functionality, diamond-inheriting /std/room's nomask functions a second time once the fatal ordering error stopped masking it. This driver rejects that redefinition even though it's a genuine diamond (both paths lead to the same ultimate file), unlike drivers that silently deduplicate identical multiple-inherit closures. Root-caused by reading cityroom.lpc directly rather than patching around the second error -- it already provides everything /std/outside.lpc does, so the textual #include in each room file was pure leftover redundancy (very plausibly predating cityroom.lpc growing its own inherit "/std/outside" in the original archive's history). Fixed by deleting the redundant #include "/std/outside.lpc" line entirely from all 46 files instead of just reordering -- verified clean on wall1/tim/duke1/delfen individually before trusting the pattern generally.

Re-ran the full batch sweep after these fixes: 8522/22259 pass (38.3%), up from the first pass's 8172/22259 (36.7%) -- a net +350 files recovered (fail count 14,087 -> 13,737), consistent with the combined base.lpc cascade (~340) and the eight direct spell-file fixes, with the daggerford fix's own recoveries appearing separately since those 46 files were already broken by the *first* pass's ordering bug before their diamond-inherit issue was even reachable. No new failures appeared anywhere outside d/gremios/hechizos/ and d/ss/daggerford/.

5b. The rest of the gap is a genuine messy-archive content

composition, not a driver-compat bug -- spot-checked, not bulk-fixed

Per AGENTS.md's own discipline ("fix the *shared* causes, don't blindly bulk-fix scattered per-file instances in a large archive"), spot-checked the highest-failure-count directories after the fix above rather than chasing the remaining ~13,700 failures file-by-file:

6. Live boot and full registration -- verified end to end

Booted the real driver (~/src/fluffos/build-debug/src/driver config.fluffos, cd'd into libs/ninetears first per AGENTS.md §5.2) and drove it with raw Python socket scripts (not mudclient.py for the very first probe -- see the test-harness gotcha below).

Test-harness gotcha worth recording: this lib's secure/login.lpc logon1(str) treats an empty-string first response (str == "") as TIME_SHORT -- it writes a message and immediately destruct()s the connection object. This project's usual smoke-test habit of opening with a blank --send "" (a "press enter to continue past the MOTD" warm-up, harmless on most libs in this corpus) is genuinely fatal here: it gets interpreted as a timed-out name prompt and the connection is dropped right after the banner, with no error anywhere (a real, intentional destruct(), not a bug) -- confirmed via ss showing the driver-side socket actively transition to FIN-WAIT-1/local CLOSE-WAIT immediately after sending a bare newline. This is legitimate original design (a "did you fall asleep at the name prompt" guard), not a driver-compat defect, and needed no mudlib fix -- just skip the blank warm-up line for this lib's own test scripts (start straight with the character name).

Full flow verified with the blank line removed: fluffos -> s (name confirm) -> Mud@2026 -> Mud@2026 (password + confirm) -> h (male) -> lands in "Plano Inmaterial" ("Tu alma se encuentra flotando en la inmensa oscuridad del Plano Material... una palabra resuena en tu conciencia: 'nacer'" -- a birth/soul-formation antechamber, matching a FR-lineage mudlib's traditional pre-character-sheet room). look (shown automatically on arrival and again on request, consistent both times), score (HP/Mana/Energy/Social/XP bars, all rendering correctly), and quit ("Un rayo divino impacta sobre ti..." / "Gracias por jugar, hasta la proxima.", clean disconnect) all verified. players/f/fluffos.o save file confirmed created on disk. Zero new fatal errors in debug.log across the whole session -- only the same six pre-existing global/player.lpc redeclaration warnings, logged (correctly) to log/root.log via master.lpc's own log_error()-routing (Root being global/player.lpc's domain owner per creator_file()).

7. Admin account seeding -- TWO independently-gated mechanisms, both

needed (a new bug-class shape for this project's §1.5 catalog)

This codebase's admin system is unusual among this corpus: rank is not a flag read at runtime, it's which player-body base class gets cloned at login. secure/bastards.lpc's query_player_ob(name) decides between /global/player, /global/creator, /global/lord, /global/god, etc., and each of those classes hardcodes its own query_creator()/query_lord()/query_god() to unconditionally return 1 (e.g. global/god.lpc: nomask int query_god() {return 1;} int query_lord() {return 1;} int query_creator() {return 1;}). There is no single "is this account an admin" boolean to flip -- getting fluffos recognized as a god required edits in three separate places, and missing any one of them leaves the account only partially privileged:

1. secure/rango.o (a real, restorable save-data file, not hardcoded source): added "fluffos":" la Administracion" to the dioses mapping (the same mapping that already lists jade, barthleby, tyrael). This makes secure/gods.lpc's query_boo() (which just delegates to secure/rango.lpc's dame_dios()) return a truthy title string for fluffos. 2. players/f/fluffos.o (the just-registered player's own save file, real data): changed creator 0 -> creator 1 and app_creator 0 -> app_creator 1. This step is load-bearing and easy to miss: query_player_ob()'s entire god/lord/thane/patron lookup block is gated behind previous_object()->query_creator() being true *at login time* (if(previous_object()->query_creator() ||flag) { if ("/secure/gods"->query_boo(name)) return "global/god"; ... }) -- and previous_object() there is the login object, whose own creator field only becomes true via restore_object("/players/.../fluffos",1) picking up a creator 1 line from the player's OWN save file (same-named-variable restore, not a dedicated admin flag). Without this edit, step 1 alone is silently ineffective -- the god-table lookup is never even reached. 3. secure/master.o (master's own restorable save data): added "Fluffos":2 (capitalized, HIGH_LORD) to the positions mapping, alongside the archive's own pre-existing "sharka":2 entry. This is a completely separate ACL system from steps 1-2 -- it drives master.lpc's high_programmer()/query_lord() (positions[ CAP(str)] == HIGH_LORD || HighLords[CAP(str)]), which gates valid_read()/valid_write()'s top-level "is this euid privileged" check, i.e. actual file read/write ACL, independent of the in-game player-body-class rank from steps 1-2. Once fluffos is cloned as a /global/god instance, move_player_to_start()'s if (this_player()->query_creator()) seteuid(name); else seteuid("PLAYER"); gives it the runtime euid "fluffos" (its own raw registered name, lowercase) -- CAP("fluffos") = "Fluffos", matching the capitalized key this step seeds.

All three edits were made directly to the .o save-data files (plain MudOS/FluffOS text-format saves, confirmed safe to edit as text -- no raw-control-byte encoding in this lineage's save format, unlike AGENTS.md §7.57's warning class) rather than to source, per this project's "prefer editing data over code" convention -- none of the three files needed a code change.

Verified on the NEXT login (a fresh connection, not the same session that registered the account): a special immortal welcome banner ("Bienvenido, inmortal. Hay mucho trabajo por hacer...") appears immediately after password entry, replacing the ordinary connect message; who lists the account under "Inmortales" as Fluffos el Dios de la Administracion (matching the exact title string seeded in step 1); score/quit continue to work normally. Did not additionally verify a file-write-requiring wizard command (e.g. load/update) this pass -- the who-listed god title plus master.o's seeded high_programmer status are the two independent signals this project's own catalog says to check, and both are confirmed; a deeper wizard-ACL smoke test can be done in a future pass if this lib gets picked up for further work.

8. A live port collision with a concurrent onboarding session --

resolved before final commit

The originally-assigned port (40240, picked from the highest committed meta.json port at the time) turned out to be already in live use by a different, concurrently-running onboarding session's driver (libs/dreamofseven, a Chinese-language 夢幻七域 lib, not yet committed at the time and therefore invisible to the usual grep meta.json collision check). Discovered this the confusing way: a fresh test connection to port 40240 returned a completely different mud's (dreamofseven's) Chinese-language banner instead of Ninetears's own -- traced to ss//proc/<pid>/cwd showing a second live driver process whose CWD was libs/dreamofseven/work, bound to the same port. Reassigned to port 40241 (confirmed free against every config. fluffos file on disk, not just committed meta.json entries, at the time of reassignment) and re-verified the full boot + registration + admin-login flow again on the new port before proceeding -- this file's number/port pair was re-checked against the corpus-wide collision query one more time immediately before the final commit, per this session's standing multi-agent coordination protocol.

9. Preloaded FTP daemon opens a real listening socket at boot

/secure/ftpd is the sole entry in secure/master.o's preload list and is loaded automatically at boot. Its create() schedules setup_ftp(FR_FTP_PORT) via a 2-second call_out, which does a real socket_create()/socket_bind()/socket_listen() on a hardcoded port (#define FR_FTP_PORT 4001 in include/ftp.h) for an in-game FTP-style file-transfer feature (upload/download to a player's own directory over a real FTP-protocol connection, judging by the surrounding PASV/PORT-mode socket_connect() calls elsewhere in the same file). This is a genuine additional network side effect at every boot -- an inbound-listening socket, not an outbound connection like imud/mortremains's Intermud-3 daemon elsewhere in this collection, but still a real extra open port (4001, independent of whatever main game port this lib is assigned) that a future automated high-frequency reboot loop should be aware of, since a stale/colliding process still holding port 4001 would make this specific feature (not the mud itself) fail to initialize, and running many copies of this lib's driver concurrently would only let one of them actually claim port 4001.

10. Outbound network check

No outbound socket_connect()/resolve() call fires unconditionally at boot or during the compile sweep -- secure/master.o's preload list has exactly one entry (/secure/ftpd, an inbound listener only, see \S9 above) and call_out_preload is empty. The Intermud-3 client (net/intermud3/), gopher daemon, and other net/daemon/ files exist in the archive but are not preloaded or referenced from any preloaded file, so they never load unless a wizard manually does so in-game.

11. Verification performed

深度功能测试(§10.7 round two, 2026-08-27)

Full one-continuous-session playthrough per AGENTS.md §10.7, on top of the onboarding-time smoke test in §11 above. Booted ~/src/fluffos/build-debug/src/driver config.fluffos from libs/ninetears/, drove it with raw Python socket scripts (the blank warm-up line is still fatal here per the onboarding note -- start straight with the character name).

What was tested

The seven standing cross-cutting bug patterns -- checked explicitly

New bug found outside the seven standing patterns

Fixes applied (summary, file:line)

1. global/player.lpc, ajustar_xp_necesaria(): return (int)xp; -> return to_int(xp); (§7.121). 2. std/tienda.lpc, vender(): ajuste=ajuste/(int)ajuste2; -> ajuste=to_int(ajuste/ajuste2); (§7.121). 3. global/player.lpc, heart_beat(): last_command = time() - query_idle(TO); -> if (interactive(TO)) last_command = time() - query_idle(TO); (new AGENTS.md §7.130). 4. global/player.lpc, refresh2(): dropped private (kept nomask) (§8.3a). 5. global/guild-race.lpc: added strip_stale_c_ext()/ normalizar_referencias_ob(), called from global/player.lpc's move_player_to_start() right after restore_object() (§7.126).

All five changes verified via lpcc single-file compile (clean, only the same pre-existing harmless global/player.lpc redeclaration warnings) both before and after running the §9 LPC formatter on the three touched files (global/player.lpc, global/guild-race.lpc, std/tienda.lpc) -- checked all three of §9's known formatter blind spots (::-split, case+//-comment merge, unbalanced-quote re-spacing) with zero hits -- and via a full live reboot + re-test of every fix (score, refresh me, the abrupt-disconnect repro) after formatting.

Test character cleanup

testespa (Humano Guerrero, the character used for the birth-flow, combat/death, and quit/reconnect tests) was removed (players/t/testespa.o deleted) before committing, per this project's throwaway-test-character policy. Only the seeded admin account remains in players/ (see below for the rest of this file).

12. WASM status audit (2026-09-01)

playable. secure/login.lpc's logon() had a classic AGENTS.md §1.3(e) startup-grace gate: if(uptime() < 10) { write(JUST_REBOOTED); dest_me(); return; }, unconditionally destructing every connection during the first 10 seconds after boot. The WASM harness connects instantly after boot, so this fired deterministically on every run. Bypassed for local/WASM connections only (the same loopback-exemption pattern used elsewhere in this collection):

if(query_ip_number(this_object()) != "127.0.0.1" && uptime() < 10) {

The preloaded /secure/ftpd (real listening socket on port 4001, see §9 above) fails to *compile* under WASM without the sockets package (Undefined function socket_create etc.) -- but this is a normal, gracefully-skipped preload failure (the driver just logs it and moves on to the next preload file), not fatal to boot, so no fix was needed there: the FTP feature is simply absent under WASM, matching its absence in any other sandboxed/no-sockets deployment. After the uptime() fix, a full WASM session verified clean: registration (name, s confirm, password + confirm, gender h/m), landing in "Plano Inmaterial", mirar (look), score, and salir (quit).

商店付费购买(2026-09-04 librarian shop slice)

Round-two §10.7 (2026-08-27) only touched std/tienda.lpc for the vender() float/to_int fix. This pass exercised a live shop.

Booted ~/src/fluffos/build-debug/src/driver config.fluffos from libs/ninetears/ on port 40241. Do not send a blank warmup line -- logon1("") destructs the connection. Admin fluffos / Mud@2026 logged in straight to /room/raceroom (Plano Inmaterial). No live clock on the prompt; mudclient.py --idle 6 was only to wait out the shop clerk call_out("add_dependiente", 5).

config.fluffos still has log directory : /log (absolute). This boot's debug.log is dead, not clean -- rely on the live transcript.

fluffos save had rp 50 (query_rp()/5 = 10, past the 0–2 "No es bien recibido" refuse) and an empty purse. Wizard call adjust_money(20,oro) me returned 2000 and i showed 20 monedas de oro.

goto /room/plaza/tienda_discordia landed in Tano's shop. Night cycle was on: after five seconds, El dependiente sale de la trastienda murmurando algo sobre los indeseables que le despiertan a estas horas. look then showed Tano esta aqui.

listar printed a live stock table (capa / armadura de cuero / brazaletes / guantes plus leftover persisted inventory). Two paid buys, both with a spoken receipt:

i after both: Cargando : Armadura de cuero y guantes. Purse 11 monedas de oro, 1 moneda de plata y 2 monedas de cobre (2000 − 333 − 555 = 1112). No programming bug on this path. ajustar_precio reputation refuse for a 0–2 rp newbie is design, not a bug -- measure query_rp() before inventing money.