feat(runecrafting): twelve altars, and the half of the map no name scan can see #132
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/runecrafting"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 2's sixth skill, end to end. Twelve altars air through death plus astral, each with its rune, level, experience and multiple-rune divisor; entry by talisman or by a worn tiara and the ruins' own
Enter; the portal back out; tiara binding at every altar with a talisman; both directions of all six combination pairs with the binding necklace and its sixteen charges; essence pouches with fill, empty, check, degrade and repair; essence mining, which is the resource the whole skill runs on; and the Ourania altar, already walkable through a ladder pair the transport table carried.Contract.Runecraftingholds the rules,World.Runecraftingthe table,World.Content.Runecraftthe altar,World.Content.Ruinsthe doors,World.Content.Pouchthe pouches andWorld.Content.Tiarathe eleven varbits.The finding: a loc that is placed nowhere may still be in the world under another id
Not one
Mysterious ruinsis placed anywhere, and this cache carries twenty-two definitions of one.The ruins are a multiloc. What the landscape places is a base —
14989,14990, …15612— whose name isnulland whose action list is empty. The client transforms it when it builds the menu, into14398(no options) or14399(Enter), and which one it picks is a varbit:607..617, one per tiara, all eleven bits 0..10 of varp 491.So a scan for "ruins with an
Enteroption" finds eleven definitions and zero placements, and a scan of the altar sites findsRuined Pillarand nothing else. Both are true, and both read exactly like the content being absent from this cache.The transform lives in loc opcodes
77and92, whichCache.Locdecodes the length of and throws away — correctly, for collision. Recovering the map meant re-walking config group 2/6 with a parser that keeps them.The same fact settles the protocol half. The client's scene stores the base id and applies the transform only for the menu text, so an
Enterclick arrives at the server as loc14989and nothing in this engine ever sees14399. Wiring the transform ids would have produced a door that is drawn, clickable and dead.Numbers, and where two of them are corrected
Multiple runes are a divisor, one number per altar rather than a threshold list:
runes = 1 + div(level, multiple). Two era-adjacent tables state29for earth against the published26, and200for law and death where the values are95and99. A divisor is what makes that checkable — 26 and 29 agree at level 1 and at 99 and disagree at four thresholds in between, which is the shape of an error that survives review in two independent codebases.Contract.RunecraftingTestwalks all twelve divisors against every published threshold.A tiara is worth
xp * 5at every altar. One factor reproduces eleven published values (air 25, mind 27.5, … death 50); eleven transcribed numbers would be eleven chances to be wrong.The combination rate is a flat 50% per essence and does not scale with level. It was a placeholder until the last commit here: the placeholder had it rising to certainty at 99, which is the shape anybody would guess, and the shape is what gives it away — a rate reaching certainty makes the binding necklace worthless above about 80, and the necklace is worn at 99. An item that stays valuable is evidence about the mechanic it insures against. So
levelreaches the plan only as a refusal.The roll is per essence rather than per batch, which the client's own message pair proves: "You partially succeed to bind the temple's power into mud runes." is only expressible if each essence is rolled separately. Two choices around it are deliberate — a failed bind consumes both the essence and the catalyst, and experience is paid per rune that survives rather than per attempt, which is the reading that cannot be exploited by deliberately failing.
The cache drew two boundaries for free
The Arceuus Blood and Soul altars are both placed in this cache. Neither carries
Craft-rune; both answerBind. Blood and soul runecrafting is 2019 content and the cache refused it without being asked — the scenery shipped years before the skill did. When era is in doubt, ask what the loc lets you do rather than whether the loc exists.The second boundary is the game's own. Two
Portaldefinitions sit beside the essence rock —7472(Use) and7473(Exit) — and neither is placed anywhere. The mine is a one-way trip until Magic has teleports. Filed as #128, and recorded in the data file at the row that causes it.Per-item state, and a Dialyzer report that named none of it
A pouch is not a container — no slots, one kind of item, never drawn — so it is three numbers per pouch id: which essence, how many, and how many fills it has survived. It could not go on
World.Player, which is at the 32-key cliff, soWorld.Inventorycarries it and two new columns persist it. The fill count is persisted deliberately: a wear counter that reset at logout would make world hopping the cheapest pouch repair in the game.Widening
hydrate_inventory/1from a three-tuple to a four-tuple leftDatabase.Players.loaded()declaring the old shape, and Dialyzer answered with four unrelated "will never be called" warnings inNetwork.Session.Gameplus an unmatchable{:error, :world_full}— naming none of the cause. One stale field in one type, four warnings in another module. Third recorded sighting of the closed-map-type invariant and the first outside a struct; measured by stashing the tree and re-running rather than guessed.Ids, and what they say about porting
This is 2004 content and its altar, ruins, portal, talisman, tiara and rune ids are all identical here and in an era-adjacent table — a counterexample to recency predicts whether an id ports, and not to the measurement behind it. Renumbering happened in ranges rather than globally:
7453–7495, the ore rocks here, is Agility obstacles there, while14897+ and5527+ are untouched in both. The narrower rule: an id that ports is not evidence that its neighbours do. Every id inpriv/data/runecrafting.exsis re-checked on every suite run byWorld.RunecraftingTest, which is the generator this hand-written table does not have.Verification
mix revenant.ci --no-postgreson the SQLite leg: 1407 doctests, 55 properties, 3279 tests. The only failure across two full runs wasWorld.Content.LightTest's seed-deterministic one (#119), which passed on the other seed.Format, Credo, Dialyzer and
check_doc_comments.shall match cleanorigin/mainexactly — measured by stashing every working change and re-running, not inferred. Three gates are red on that baseline and this branch adds nothing to them; filed as #131.The Postgres leg has not been run against this branch on this machine, and it matters because of the migration. It was green on the machine the work started on.
What is left, all filed
#126 the Ourania yield table (its distribution is recovered and cross-verified; the experience is what blocks it), #127 the Abyss obstacle ring, #128 the one-way essence mine, #129 Magic Imbue, #130 pouches and the astral tiara having no in-game source until quests.
The mine was recorded as one-way, gated on Magic teleports that do not exist. That was wrong, and wrong in a way this file had already described three sections earlier. The two `Portal` definitions beside the essence rock — 7472 `Use` and 7473 `Exit` — really are placed nowhere. They are transforms. The landscape places the nameless base `7479` four times, one per corner, and opcode 77 on varbit 2313 turns it into [7472, 7473, nil, 7472, 7473, nil, nil, 7472] so slots 1 and 4 draw `Exit`, slots 0, 3 and 7 draw `Use`, and the loc is clickable at every value the varbit can hold. A working exit needs no varbit management at all; it just reads `Use`. The scan that found it carried a known-positive control — base 14989 -> [14398, 14399] on varbit 607, reproducing the ruins — because a walk that decodes nothing finds nothing everywhere, and that is indistinguishable from an absence. Wired the way the ruins already are: the dispatch matches the base, since the base is the only id a client ever sends, and guards on standing at one of the four listed tiles rather than on the id alone — a nameless base with no action of its own is a weak claim, and anything else placed under it would otherwise teleport people. `destination` is the one invented value and is flagged `sourced: :placeholder` at its row. In era each portal returns the player to the wizard who sent them, which needs somewhere to remember the origin, and `World.Player` is at the 32-key cliff. Wizard Cromperty's tile is on the surface, beside a bank, and one of the three wizards this world actually spawns — Aubury carries the `Teleport` option and has no spawn anywhere. Tests pin the half that was got wrong: that the base is placed four times inside the mine, that it is nameless with no actions while the two portals are named with actions, that only the base answers the dispatch, and that the destination is neither blocked nor back inside the mine.`Bot.Goals.Runecraft` plus a `:runecrafter` kind. Nine phases, and the loop closes on itself because the mine's exit lands the bot beside the wizard who sends it back in — `mine.destination` names Cromperty's tile and Cromperty carries the `Teleport` option the cache states. Two things about clicking that are not obvious. `Act.object_action/4` takes a menu slot 1..5, not a verb, so every click resolves its verb against `Cache.Loc.actions/1` at the call site rather than hardcoding a slot a reworked definition would move. And a **nameless multiloc base has no action list to search**, so those fall back to op 1 — the option a player sees belongs to the transform, and both the mine's portals and both ruins definitions put theirs first. `in_mine?/1` is derived from the table rather than typed. It began as the bounds of the *scan window* that found the portals, which is a rectangle nobody measured — it would call a bot that had walked out of an invented box "out of the mine" and send it to craft with nothing. It is now "the same map square as a listed portal", which cannot drift. The world test asserts the portal leg and stops there, because the legs past it are blocked and the trace says why: 10s {0, 2886, 4850} in the mine, at the portal 12s {0, 2683, 3326} out, on the surface, as designed 16s {0, 2686, 3324} three tiles toward the ruins, 297 to go 20s-68s stationary — the long leg, #123 70s {0, 2797, 5171} recovery fires and teleports it underground The second half is #138 and was not predicted. The failure ladder calls `Bot.Travel.recover/2`, which relocates to the bank nearest the bot's anchor, and a runecrafter naturally anchors at an essence rock. `nearest_bank/1` filters by plane, and caves are plane 0 at high y, so the nearest bank to a tile in the mine is an underground one 1878 tiles away with no walked route out — a recovery strictly worse than the failure it answers. This kind now anchors at the mine's exit rather than at the rock, which makes it safe and leaves the general hazard filed rather than papered over.