Diablo II, days five and six
Day four stopped at 20:50 on 14 October. This post covers the rest of that evening, all of the 15th and most of the 16th. On day four the research map had 28 rows and 12 of them were reviewed specs. Now it has 29 rows and 28 are reviewed, and the one that is not is the newest, combat, because on the morning of the 16th game simulation entered the project’s scope, and it is the first thing on this blog about Diablo II that is not about creating something.
The other thing that changed is who did the work. Until the 15th every plan had a phase with me in it: a run I played, a question I answered. On the morning of the 15th I approved nine plans at once to run without me, and the lanes, each an agent with its own copy of the repository, ran them through the day and the night on the harness, the game under a debugger with a logger attached. The record says what came of that, and it also says where the agents could not get and I had to play: seven sessions, on the 16th, to kill the bosses the scripted play kept dying on the way to. The post stops at 17:53 on the 16th, when the record of those sessions merged.
The map of the work
The research map at each cut-off
- not started
- planned
- findings
- draft spec
- reviewed spec
3 reviewed spec 1 findings 1 planned 23 not started of 28
Core
- rng reviewed spec
- items/tc findings
- items/quality not started
- items/affixes not started
- items/uniques-sets not started
- items/properties not started
- monsters/pool not started
- monsters/spawn not started
- monsters/special not started
- drlg/overview planned
- drlg/preset not started
- drlg/maze not started
- drlg/outdoor not started
- drlg/warps not started
- objects not started
Enablers
- data/excel reviewed spec
- data/calc not started
- data/strings not started
- rng/seeds reviewed spec
- drlg/collision not started
- save/d2s not started
Creation paths
- items/vendors not started
- items/cube not started
- items/sockets-runewords not started
- items/quest-drops not started
- monsters/stats not started
- hirelings not started
- player/creation not started
7 reviewed spec 1 draft spec 3 findings 17 not started of 28
Core
- rng reviewed spec
- items/tc reviewed spec ↑
- items/quality findings ↑
- items/affixes not started
- items/uniques-sets not started
- items/properties not started
- monsters/pool reviewed spec ↑
- monsters/spawn findings ↑
- monsters/special not started
- drlg/overview reviewed spec ↑
- drlg/preset reviewed spec ↑
- drlg/maze not started
- drlg/outdoor not started
- drlg/warps not started
- objects not started
Enablers
- data/excel reviewed spec
- data/calc not started
- data/strings findings ↑
- rng/seeds reviewed spec
- drlg/collision not started
- save/d2s draft spec ↑
Creation paths
- items/vendors not started
- items/cube not started
- items/sockets-runewords not started
- items/quest-drops not started
- monsters/stats not started
- hirelings not started
- player/creation not started
12 reviewed spec 1 draft spec 6 findings 2 planned 7 not started of 28
Core
- rng reviewed spec
- items/tc reviewed spec
- items/quality reviewed spec ↑
- items/affixes findings ↑
- items/uniques-sets reviewed spec ↑
- items/properties findings ↑
- monsters/pool reviewed spec
- monsters/spawn reviewed spec ↑
- monsters/special reviewed spec ↑
- drlg/overview reviewed spec
- drlg/preset reviewed spec
- drlg/maze findings ↑
- drlg/outdoor findings ↑
- drlg/warps findings ↑
- objects planned ↑
Enablers
- data/excel reviewed spec
- data/calc not started
- data/strings findings
- rng/seeds reviewed spec
- drlg/collision reviewed spec ↑
- save/d2s draft spec
Creation paths
- items/vendors not started
- items/cube not started
- items/sockets-runewords not started
- items/quest-drops not started
- monsters/stats planned ↑
- hirelings not started
- player/creation not started
28 reviewed spec 1 planned of 29
Core
- rng reviewed spec
- items/tc reviewed spec
- items/quality reviewed spec
- items/affixes reviewed spec ↑
- items/uniques-sets reviewed spec
- items/properties reviewed spec ↑
- monsters/pool reviewed spec
- monsters/spawn reviewed spec
- monsters/special reviewed spec
- drlg/overview reviewed spec
- drlg/preset reviewed spec
- drlg/maze reviewed spec ↑
- drlg/outdoor reviewed spec ↑
- drlg/warps reviewed spec ↑
- objects reviewed spec ↑
Enablers
- data/excel reviewed spec
- data/calc reviewed spec ↑
- data/strings reviewed spec ↑
- rng/seeds reviewed spec
- drlg/collision reviewed spec
- save/d2s reviewed spec ↑
Creation paths
- items/vendors reviewed spec ↑
- items/cube reviewed spec ↑
- items/sockets-runewords reviewed spec ↑
- items/quest-drops reviewed spec ↑
- monsters/stats reviewed spec ↑
- hirelings reviewed spec ↑
- player/creation reviewed spec ↑
Simulation
- combat/formulas planned ↑
The arrow marks a row that moved since the previous snapshot. Source: docs/specs/README.md at commits 8faba4f2, c8753c82, 2c8eb42 and 33dc648. The Simulation band was added on 16 October by ADR-0014.
Show as a table
| Subsystem | Day 1 | Day 3 | Day 4 | Day 6 |
|---|---|---|---|---|
rng | reviewed spec | reviewed spec | reviewed spec | reviewed spec |
items/tc | findings | reviewed spec | reviewed spec | reviewed spec |
items/quality | not started | findings | reviewed spec | reviewed spec |
items/affixes | not started | not started | findings | reviewed spec |
items/uniques-sets | not started | not started | reviewed spec | reviewed spec |
items/properties | not started | not started | findings | reviewed spec |
monsters/pool | not started | reviewed spec | reviewed spec | reviewed spec |
monsters/spawn | not started | findings | reviewed spec | reviewed spec |
monsters/special | not started | not started | reviewed spec | reviewed spec |
drlg/overview | planned | reviewed spec | reviewed spec | reviewed spec |
drlg/preset | not started | reviewed spec | reviewed spec | reviewed spec |
drlg/maze | not started | not started | findings | reviewed spec |
drlg/outdoor | not started | not started | findings | reviewed spec |
drlg/warps | not started | not started | findings | reviewed spec |
objects | not started | not started | planned | reviewed spec |
data/excel | reviewed spec | reviewed spec | reviewed spec | reviewed spec |
data/calc | not started | not started | not started | reviewed spec |
data/strings | not started | findings | findings | reviewed spec |
rng/seeds | reviewed spec | reviewed spec | reviewed spec | reviewed spec |
drlg/collision | not started | not started | reviewed spec | reviewed spec |
save/d2s | not started | draft spec | draft spec | reviewed spec |
items/vendors | not started | not started | not started | reviewed spec |
items/cube | not started | not started | not started | reviewed spec |
items/sockets-runewords | not started | not started | not started | reviewed spec |
items/quest-drops | not started | not started | not started | reviewed spec |
monsters/stats | not started | not started | planned | reviewed spec |
hirelings | not started | not started | not started | reviewed spec |
player/creation | not started | not started | not started | reviewed spec |
combat/formulas | not started | not started | not started | planned |
Sixteen rows moved to reviewed in two days. The last six core rows: affixes, properties, the maze generator, the outdoor generator, warps and objects. The last three enablers: the formula bytecode, the string tables, the save file. And all seven creation paths, the band that on day four I wrote “waits for the core”: vendors, the Horadric Cube, sockets and runewords, quest drops, monster stats, hirelings and player creation. Once the core was reviewed, the paths went in two days.
Each row went the same way as before, the pipeline the day one post describes: findings read from the code and tagged [I], a harness run that raises them to [C] where a model reproduces the game, a spec, a review by an agent that did not write it. Every run record added in the window ends with zero mismatches. The ones that carry a result for this post:
| Run | What the model reproduced | Checks |
|---|---|---|
| Affixes | 3,102 item creations: 366 magic, 105 rare, 35 superior, 31 low, 2,472 normal, 36 automagic | 0 mismatches |
| Properties | 2,281 creations: base stats, property rolls, ethereal, sockets | 0 |
| Mazes, links and warps | 14 sessions, 189,355 checks | 0 |
| Outdoor levels | 11 new logs and 93 older ones, 572,211 checks on the new ones | 0 |
| Objects | 13 sessions, 142,540 checks; the room’s objects, which on day four still came from the log, are now predicted | 0 |
| Monster stats | 4,571 monster creations, 62,991 checks | 0 |
| Acts III to V presets | 6 logs, 155,215 checks | 0 |
| String tables | 336 index and 3,928 key lookups | 0 |
| Sockets and runewords | 22 sessions, 351 inserts, 50 runewords | 0 |
| The Cube | 182 transmutes, 51 of them crafted | 0 |
| Items end to end | 889 creations, 219 followed from the pick to the written stats | 0 |
| Vendors | 94 stock builds, 325 gamble windows, 9,206 created items | 0 |
| Player creation | 35 new characters, 269 item copies, 20 level-ups, 11,152 comparisons | 0 |
| The formula evaluator | 44,529 evaluations, all 14 opcodes the stock data uses | 0 |
| Hirelings | 53 hire tables, 49 hires, 33 saved mercenaries | 0 |
| Quest drops | 53 scripted sessions and 7 of mine; in mine, 221 drop resolutions and 4,737 monster levels | 0 |
A check is one value the model predicted and the game logged. The sessions were driven by the agent from screenshots, with the pilot from day four, the script that moves the character by the collision grid and clicks for it, except the seven at the end of the quest drops row.
The night of the 14th
Day four ended with five findings waiting for their runs, and with the harness slots that let several games run at once. The runs came that night, the first at 22:37, the last at 04:14, and the last of the five plans closed at 07:50.
The maze run found the first thing the day four reading had wrong. The warp pairing between two levels was read as a match of rank slots. The run showed it falls back: “Warp pairing falls back when the destination has no room with the rank slot’s bit… A Durance level carries only the slot its finisher’s rotation faced, so rank pairing alone mispredicts there.” The finding is corrected and says so. The same run found that the Act V red portals are not objects placed by the preset files or the object groups; they come from somewhere else.
The outdoor run caught the harness in a mistake. The maze run had labelled one session classic. The outdoor run loaded the same character and saw five act tabs in its waypoint menu. The save’s status byte had the expansion bit set. The maze record was corrected, and the harness play guide got a rule: “Check a classic character really is classic before a classic session: the .d2s status byte must have bit 0x20 (expansion) clear, and the waypoint menu shows four act tabs, not five.” Every character recipe now has to say which game it is for, and the save builder refuses one that does not.
Monster stats had three surprises of its own. The first run showed the regeneration of a pack’s members growing with the pack’s HP multiplier, although the handler the reverser read writes no such stat. The unit’s stat callback does. It also corrected a day-four reading about classic: the HP stat is halved together with its fraction, where the finding had said it kept the unhalved value. And unit ids are reused within a game, which a model that keyed on them had to learn.
The unattended queue
At 08:05 on the 15th nine plans and one ADR landed in one commit, under the name “the unattended queue”. The plans index records the decision: “The owner approved plans 0027–0036 together, to run without them. Phases with the human owner are gone: plan 0020 Phase 4 is agent-driven, with owner play as the fallback.” The queue was two enablers, the string tables and the formula language, six of the seven creation paths, and a wiki.
The harness had to change for it. On the 15th the memory manager killed every lane at once, and I found that in the morning: “systemd-oomd killed the whole editor scope (every lane at once) when RAM and swap passed 90%.” Each run now gets its own memory cap in its own scope, so a runaway run is stopped alone, and the rule became at most two harness lanes at a time. Slot 0, the first game, on my own display, stays mine.
One more rule came from the lanes killing themselves. On day four the cleanup rule was already “no pkill -f with several games running”. Now it is no pkill -f at all: “the pattern also matches the shell running the pkill and every other process whose command line holds it (two lanes killed their own shell this way).” A loop writes its PID at start and is stopped by it.
The queue ran for thirty-one hours, sockets first at 19:34 on the 15th and the wiki last at 15:27 on the 16th, with the Cube, player creation, the formula evaluator, vendors, hirelings and quest drops closing through the night between. What the specs say is below. Where they disagree with the community, it is nearly always the same way: a divisor, a constant, a bit.
Vendors and gambling
When the game creates a new game, it spends the first draws of the game seed on fixed things, and two of them matter for this post:
flowchart LR gs["game seed"] --> d1["draw 1: monster regions"] --> d2["draw 2: object regions"] --> d3["draw 3: the store seed"] --> d4["draw 4: the quest seed"]
The first time you talk to a vendor in a game, the server builds that vendor’s stock from the store seed.
Gambling is where the community was wrong by a factor of a hundred. The Arreat Summit gives the chance of a gambled item being upgraded as “(ilvl − qlvl) × 0.9% + 1%”, where ilvl is the item’s level and qlvl the base item’s quality level. The slope is right. The constant is one in 10,000, not one in 100. The spec’s words: “R(S, 10000) < (lvl − qlvl)·GambleUber + 1 gives (lvl − qlvl)·0.9 % + 0.01 %.” The run reproduced all 2,292 upgrade tests. The gamble level is drawn in clvl − 5 .. clvl + 4, five below your character level to four above, and it is used three times: to filter the base, as the item’s creation level, and as the upgrade level. The first two slots of the gamble screen are always a ring and an amulet, and their level and pick draws are made and thrown away. The Arreat Summit’s magic-items page says the range is plus six to minus three; the same publisher’s gambling page says minus five to plus four, and that one is right. With stock tables the quality shares are 50 unique, 100 set, 10,000 rare and 89,850 magic in 100,000. And the order of equal-level rows on the screen is whatever the C library’s qsort left, not the order of the data file.
The Cube
The server scans the recipe table in row order for the first recipe whose header conditions and seven inputs fit; the first match wins. A recipe row has two percentages, so much of your character level plus so much of the input item’s level, and a created output gets their sum. The crafted recipes have 50 and 50, so a craft sits halfway between you and the input. An output that reuses the input keeps the input’s level. The run saw one row refuse a rare amulet because its output wants sockets and an amulet cannot have any.
The cow portal opened three times in the run, in Normal, Nightmare and Hell, and was refused three other times, each for a different reason. It is refused if the game already opened one, if this character already killed the Cow King, if Baal is not dead in the expansion, or if you are not standing in the Rogue Encampment. The two Uber Tristram recipes are stubs in 1.14d single player: “PandemoniumPortalStub, PandemoniumFinalePortalStub: return 0.”
Hirelings
The first time you talk to a mercenary seller in a game, the server builds the hire table from the store seed: one seed per name in the seller’s name range, then ten names picked into the list. The list sits at your level minus five to minus one, never above you. When the tenth hire empties the list, it is rebuilt on the spot from the chained seed, and the run caught that once: “the 10th hire emptied the list, HIRE_RebuildIfEmpty built a new table from the chained S inside HIRE_Hire.”
The stats per level are the table’s values plus a per-level term, with one division the community has wrong. The resistance per level column is divided by four in 1.14d, where the community guide says eighths. The experience for the next level is (L + 1) × L² × Exp/Lvl, not the formula in the guides. A mercenary’s kill counts its own magic find plus its owner’s: “three kills by the MercMF Rogue read 0 for the mercenary and 40 for the player.” And one class in the monster table, 560, has no hireling row, so “no save and no hire can make it.”
Player creation
A new character begins as a save with only a header, written by the client. The server reads it, sees the “new” bit, and builds the character from its class row. Life at creation is vitality plus the class’s add, with no per-point factor: a Sorceress starts at 40 life, 35 mana, 74 stamina; a Barbarian at 55, 10 and 92. A level-up draws nothing from any seed. The experience penalties above level 25 are not the percentages the Arreat Summit lists; the game uses factors over 256, and the spec says so: “207/256 is 80.9 %, 13/256 is 5.1 %.”
The formula language
The game has a small formula language in its skill and item data, and the day four post said no item property uses it. Now the whole thing is specified. In the shipped data each formula is already compiled into postfix bytecode in four header-less pools, and the game runs a stack machine of 64 integers over the bytes. The stock pools use exactly 14 opcodes. The run evaluated 44,529 formulas and reproduced every one. The evaluator can draw a random number through one function, rand, and no stock formula called it in play: no seed passes through the evaluator.
Quest drops
The quest seed is the fourth draw in the diagram above, right after the store seed. From it come Andariel’s gems, the Hellforge’s gems and rune, and the quest reward items. A treasure class is one row of the game’s drop table, what a monster or a chest may drop and with what weights, and a boss has a quest treasure class that he uses while his quest is not done. The quest state is a set of bits in the save, and two things about those bits that players argue about:
- Andariel’s quest drop. Her death script sets one bit, and Warriv’s talk turns it into another. So her quest treasure class, with its two chipped gems and one standard, is used again “if the game was saved before the report”.
- Duriel’s. His bit is set at the kill and never cleared, so his quest treasure class is used until the first kill. A save with every quest done still has Duriel’s quest drop, because his quest’s completion bit is not the one the drop tests.
The imbue reward creates an item at max(clvl, 1), plus four if that is above five, as a rare, and takes two fresh steps of the game seed. Only low, normal and superior bases can be imbued.
The seven sessions I played
The quest drops plan had a Phase 2 of 53 scripted sessions. They confirmed the quest treasure class, the quest seed, the special drops and the rewards. They could not reach four things: “Mephisto quest done (4 attempts), the Countess in all four states (10 attempts), the Hell Hellforge (3 deaths), the Cow King.” The Countess sessions all ended with none killed. The Cow King session killed 565 Hell Bovines and never met him. The Hellforge in Hell: “died on the way three times.” The plan closed with those rows at [I] and an owner addendum in the backlog.
So on the 16th I played them: seven sessions on slot 0, seeds 3501 to 3507, fullscreen with sound, the logger attached, no stepping. All seven reached their target, about ten minutes each; with a prepared character it was easy. The record is careful about what is mine and what is logged: “sound and fullscreen are not in the header and rest on the owner’s statement.”
Three of the four targets, as the game draws their class
-
Hell Bovine, the class of the Cow King
-
Hephasto, who guards the Hellforge
-
Dark Stalker, the class of the Countess
Composed from the game's own sprite layers with tools/cof.py, first frame of the neutral pose, without the colour shift a superunique gets in the game. Diablo II art © Blizzard Entertainment.
What the seven sessions settled:
- Mephisto with his quest done drops from his normal treasure class, 848, not the quest one, 851. No Soulstone after the kill, because the killer’s quest bit is set.
- The Countess uses the same treasure class whatever the state of her quest, 1004 in Normal and 1005 in Nightmare. Her death script creates nothing and draws nothing from the quest seed. One of her drops, from the log:
gld tsc vbt r06 r06, gold, a scroll of town portal, a pair of boots and two runes. - The Cow King resolves his own treasure class first, then sets the killer’s bit, then asks for eight stamina potions at quality 0. The eight items that come out are quality 2, at his level, and take no draw. Why a request for quality 0 yields quality 2 is an open question in the spec.
- The Hellforge in Hell. Hephasto dropped his treasure class, then the Hellforge Hammer, at quality 7 and level 88, without a draw. Then the four waves of gems, “perfect, flawless, flawless, standard”, and the rune: the quest seed modulo 11 gave 4, which in Hell’s table is
r19. All five normal quality, at item level 85, the area’s monster level in Hell. The hammer has to be equipped and carry a stat that is at least the difficulty, with a boundary the finding checked: “a hammer whose stat 356 is below the difficulty is not found.”
Four quest items
-
The Hellforge Hammer
-
The Horadric Cube
-
Mephisto's Soulstone
-
A stamina potion, the Cow King's drop
Each sheet: the inventory picture and the frames of the item falling to the ground. Rendered with the project's tools/item_art.py. Diablo II art © Blizzard Entertainment.
Simulation enters scope
The project’s second ADR, on day one, kept game simulation out of scope until at least one item spec was reviewed. On the morning of the 16th, with nearly every row reviewed, ADR-0014 brought it in, in five phases: combat formulas, stats and states, skills and missiles, monster AI, animation timing. The ADR lists the other order, stats and states first, as the alternative it rejected: it lost because “the owner wants combat formulas first.” I had no particular reason for that order. The research map got a fourth band, Simulation, with one row in it, and the rows of the other four phases are to be added when their plans start.
The hard part is in the evidence rule, and the ADR spends most of its words on it. Everything the project reproduced so far happens once: a level is built, an item is created. Combat runs every frame, on many units, and under wine “the frame on which an event happens depends on wall-clock timing and on how long each breakpoint stalls the thread… A session can’t be replayed frame for frame.” So a simulation claim reaches [C] by reproducing events, never frames or sessions: “An event is one call of a named in-scope entry point (for example one attack resolved against one target, or one damage-over-time tick).” The model predicts every draw and every output from the logged inputs and asserts the logged exit seed. Two events of the same kind in a row on the same seed are chained, so the second’s entry seed is predicted from the first’s exit, and chaining is required for every event kind. Stat values read from the unit are value oracles. Every timing claim is in game frames; nothing is claimed about wall-clock time.
The ADR also says why this is the part of the game where the community’s numbers matter least: “much of that folklore was derived from 1.09 and 1.10 code, so its numbers and formulas may not hold for 1.14d.”
Plan 0037 followed. Its phase 0 documented the combat columns of the tables, with one surprise: no monster record that has an S1 damage entry has the S1 mode. Its phase 1 was a static reading of the server’s combat module, 77 symbols named, everything at [I] because no run has happened yet. The attack resolution it read:
flowchart TB ar["chance to hit = 100 x AR / (AR + DEF), times 2 x alvl / (alvl + dlvl), clamped to 5..95"] ar --> roll["one draw on the attacker's seed: low % 100"] roll -->|hit| def["defender's seed, in order: shield block; then evade or weapon block; then dodge (melee) or avoid (missile)"] roll -->|miss| none["no damage"] def -->|not avoided| red["reductions: a 12-row table; resistances, damage reduction, absorb"] red --> fx["on-hit effects: crushing blow, deadly strike, open wounds"]
Against the community’s thirty claims the reading compared: 15 held, 9 held with a refinement, 5 contradicted (four distinct behaviours, since two sources are wrong about crushing blow in the same way), 1 not covered.
The ones that held are the ones every player knows: the chance to hit never below 5 or above 95 percent, blocking capped at 75. The contradicted ones:
- The Arreat Summit’s class bonus to the attacker’s level in the to-hit formula, 20, 15, 5, −10, −15 by class. The constants exist, but they are
ToHitFactor, added to attack rating; the level term has no class bonus. - Healing from absorb comes from the absolute absorb only. Both the percent and the flat amounts heal.
- Crushing blow is one eighth on a boss or champion. One eighth for bosses and superuniques; champions and random uniques take one quarter.
- Crushing blow does not scale with the player count. It does:
k += MulDiv(k, PlayerHpPct(n), 100).
And one that is not in the community’s list but in the project’s own tables: a column of the difficulty table that the table documentation had called unread, HireableBossDamagePercent, is read by the combat code. The table doc was corrected at the review.
Two more ADRs went in on the 16th, both about what a run may prove. ADR-0013 rewrites the rule of day four’s forced-path ADR. That rule was written at the level of a table: a run that edits a table proves nothing about the code that reads the table. The rulings since had been finer than the rule, and “a later reviewer applying ADR-0010 literally could revert every [C] above.” The new rule is cell by cell: a claim may cite a forced run as evidence only when “the code the claim describes reads none of the edited cells.” ADR-0015 admits the emulator past pure functions. Ghidra, the disassembler, can interpret one function of the binary on its own, with no game running; the binary’s own, unmodified code run that way, with a declared memory image, counts as [C] for what the code does with those inputs and never for what the game’s memory holds at run time. The first run under it reproduced the formula functions min, max and rand and the missile code that reads formulas, with no game running.
The sweep
With every row reviewed, the next question was the one the plans never asked side by side. Plan 0038 asks it: “The reviewed specs hold 1,526 [I] statements, against 2,531 [C]. Each plan raised what its own run reached and left the rest at [I], so the remaining [I]s were never looked at side by side.” I chose it on the 16th and approved it to run unattended. It adds no subsystem and changes no spec’s status.
Its phase 0 is an inventory of all 1,526, one file per spec, every file’s count summing to its spec’s front matter. Each statement got a class: a kept log already holds the values, or a new session is needed, or a static second source, or the emulator, or blocked. The totals after review:
Two static batches ran before the cut-off. The first replayed 166 kept logs of 11 item runs through the treasure class and quality models with counts: 9,390 calls, 9,390 reproduced, and from that 29 statements raised, 25 raised in part, 3 shortfalls, 8 reclassified. The review wrote down a principle on the way: “Counterfactual replays are not evidence by themselves. A switch that fails is a sensitivity check… The evidence is still the replay.” The second batch went over the level and object logs: 57 raised, 18 in part, 2 shortfalls, 12 reclassified, with 24 addresses raised to confirmed in the symbol table. One of its reclassifications is the kind of statement a static sweep finds: “none of the 39,096 logged bit-2 merges went through rows 0–5, returned on row −2 or met the 8/9 edge rule.” It is not wrong; nothing we logged ever exercised it.
The wiki
On the 15th I asked for a human wiki, and ADR-0012 made it a rule: pages a person reads to understand the game’s systems, with no claims of their own. Plan 0036 wrote it on the 16th: an index and ten pages, about 45,000 words, over every reviewed spec. The README’s rules: “No claims of their own. … If a page and a spec disagree, the spec is right. Nothing hidden. … Each topic page ends with a What is not known yet section. Not published.” No confidence tags, no anchors, no addresses. It starts with randomness, because “almost everything else is a sequence of random draws on some seed”, and has 29 diagrams. Its second pass made about 80 wording fixes, “mostly hedges restored on code-only points”. The gate got three rules and a staleness warning so the wiki cannot drift from the specs, and the main README of the repository now starts with it. I read it. It is good, and it needs improvement.
The ADR rejected two alternatives: a summary at the top of each spec, because it mixes audiences, and a rendered site kept local, because it would add a toolchain and any rendered form raises the question of publication. So the wiki stays markdown in the repository.
The numbers
Where it is now, against the last three posts
Reviewed specs (of 28 rows, 29 from day 6)
[C] confirmed claims in findings
[I] inferred claims in findings
Named addresses in Game.exe
Python tools
Closed plans
Each measure has its own scale. Sources: the research map, docs/findings, re/symbols.csv, tools/ and docs/plans/done at each cut-off.
Confirmed and inferred claims in the findings
[C]: read in the code and confirmed by something independent, usually a run. [I]: read in the code only. Nights are cut out.
- [C] confirmed
- [I] inferred
The flat stretch on the 15th is the day the queue ran: the creation-path readings landed together in the evening. The jump of [I] at 16:08 on the 16th is the combat reading.
Show the numbers
| Time | [C] | [I] |
|---|---|---|
| 11 Oct 10:31 | 0 | 0 |
| 11 Oct 13:35 | 7 | 15 |
| 11 Oct 15:05 | 21 | 58 |
| 11 Oct 16:00 | 28 | 59 |
| 11 Oct 16:25 | 42 | 62 |
| 11 Oct 17:57 | 45 | 104 |
| 11 Oct 19:06 | 48 | 148 |
| 11 Oct 20:11 | 48 | 175 |
| 11 Oct 22:12 | 57 | 176 |
| 11 Oct 22:23 | 57 | 176 |
| 12 Oct 08:04 | 80 | 173 |
| 12 Oct 08:41 | 103 | 183 |
| 12 Oct 09:02 | 104 | 184 |
| 12 Oct 09:31 | 108 | 217 |
| 12 Oct 09:58 | 109 | 228 |
| 12 Oct 10:16 | 117 | 278 |
| 12 Oct 10:42 | 135 | 295 |
| 12 Oct 11:51 | 139 | 295 |
| 12 Oct 12:21 | 159 | 291 |
| 12 Oct 13:41 | 161 | 292 |
| 12 Oct 14:10 | 168 | 295 |
| 12 Oct 15:19 | 168 | 320 |
| 12 Oct 15:46 | 184 | 354 |
| 12 Oct 15:58 | 184 | 354 |
| 13 Oct 08:05 | 196 | 348 |
| 13 Oct 08:26 | 204 | 374 |
| 13 Oct 08:33 | 205 | 422 |
| 13 Oct 10:11 | 206 | 448 |
| 13 Oct 13:43 | 223 | 449 |
| 13 Oct 15:59 | 225 | 452 |
| 13 Oct 18:56 | 229 | 453 |
| 13 Oct 19:21 | 236 | 452 |
| 13 Oct 19:28 | 240 | 455 |
| 13 Oct 21:15 | 279 | 429 |
| 13 Oct 22:02 | 279 | 442 |
| 14 Oct 08:11 | 279 | 442 |
| 14 Oct 08:49 | 282 | 443 |
| 14 Oct 09:21 | 282 | 493 |
| 14 Oct 09:36 | 282 | 495 |
| 14 Oct 09:49 | 290 | 536 |
| 14 Oct 10:00 | 291 | 537 |
| 14 Oct 10:09 | 293 | 586 |
| 14 Oct 10:20 | 293 | 587 |
| 14 Oct 11:05 | 332 | 567 |
| 14 Oct 13:10 | 356 | 562 |
| 14 Oct 17:35 | 376 | 560 |
| 14 Oct 19:22 | 376 | 611 |
| 14 Oct 19:56 | 395 | 651 |
| 14 Oct 20:36 | 402 | 691 |
| 14 Oct 20:50 | 446 | 721 |
| 14 Oct 20:59 | 451 | 757 |
| 14 Oct 21:16 | 461 | 796 |
| 14 Oct 22:37 | 506 | 772 |
| 14 Oct 22:50 | 545 | 743 |
| 15 Oct 02:10 | 574 | 733 |
| 15 Oct 02:44 | 587 | 732 |
| 15 Oct 02:54 | 612 | 737 |
| 15 Oct 03:05 | 619 | 727 |
| 15 Oct 03:29 | 629 | 739 |
| 15 Oct 03:57 | 671 | 738 |
| 15 Oct 04:14 | 711 | 716 |
| 15 Oct 07:39 | 718 | 733 |
| 15 Oct 08:47 | 729 | 737 |
| 15 Oct 08:48 | 737 | 779 |
| 15 Oct 08:54 | 746 | 782 |
| 15 Oct 09:05 | 771 | 791 |
| 15 Oct 09:17 | 773 | 848 |
| 15 Oct 19:08 | 774 | 890 |
| 15 Oct 19:10 | 786 | 941 |
| 15 Oct 19:13 | 797 | 940 |
| 15 Oct 19:25 | 801 | 982 |
| 15 Oct 19:33 | 829 | 1015 |
| 15 Oct 19:38 | 829 | 1057 |
| 15 Oct 19:48 | 841 | 1064 |
| 15 Oct 19:56 | 845 | 1066 |
| 15 Oct 20:13 | 845 | 1072 |
| 15 Oct 20:24 | 848 | 1095 |
| 15 Oct 23:42 | 875 | 1092 |
| 15 Oct 23:54 | 886 | 1095 |
| 16 Oct 00:15 | 886 | 1094 |
| 16 Oct 00:21 | 889 | 1096 |
| 16 Oct 01:43 | 905 | 1093 |
| 16 Oct 02:23 | 918 | 1098 |
| 16 Oct 02:28 | 923 | 1103 |
| 16 Oct 03:49 | 956 | 1090 |
| 16 Oct 06:40 | 987 | 1065 |
| 16 Oct 14:29 | 1003 | 1072 |
| 16 Oct 15:31 | 1023 | 1075 |
| 16 Oct 16:08 | 1023 | 1152 |
| 16 Oct 17:21 | 1080 | 1181 |
| 16 Oct 17:36 | 1140 | 1189 |
| 16 Oct 17:53 | 1150 | 1189 |
On day four the confirmed share in the findings was about 38 percent. Now it is 1,150 against 1,189, 49 percent, and in the specs, which are the deliverable, 2,546 confirmed against 1,539 inferred. The sweep’s 1,526 was counted at 14:50 on the 16th; the specs moved again during the afternoon. The named addresses in Game.exe went from 1,143 to 1,814. The tools directory went from 56 top-level scripts to 91, and the save recipes from 10 to 112: a recipe is one character built for one purpose, a Nova Sorceress with every waypoint, a classic Barbarian, a hireling test, and the queue wrote one for nearly every session it needed.
What is open
- Combat, phase 2. The harness run of the combat formulas, under the per-event rule: 2,000 player attacks and 1,000 monster attacks, at least 300 in each difficulty, at least 300 hits and 300 misses, 20 chained pairs per event kind, 30 crushing blows, 30 deadly strikes, 30 open wounds with their ticks checked in frames. Four characters are named for it: a melee Barbarian with a mercenary, the Nova Sorceress, a shield defender, and a classic one.
- The other four phases of the simulation: stats and states, skills and missiles, monster AI, animation timing. Each gets its row on the map when its plan starts.
- The sweep’s remaining batches: eight static, twenty-one harness. And the 364 blocked statements, eight of which need me to play.
- The addendum’s rows. At the cut-off the quest drops spec still carries Mephisto, the Countess, the Cow King and the Hellforge at
[I]with “owner addendum open”; the re-tag merged twenty-four minutes after it.
And on the same day as the sweep, in another repository, a voxel engine got its first cave. Its newest decision cites this project by name: “Every system the recompilation project documents is integer arithmetic on per-thing seeds.” The combat run, the first two thousand player attacks, has not happened yet.