Add SRD dungeon stocking and the KeyedEncounter.hoard gate (1.3.0)#30
Merged
Conversation
…hoard gate `osrlib.crawl.stocking.stock_area` consumes the shipped stocking tables to roll one keyed area's contents deterministically from a single RngStream, answering a frozen `StockedArea` of content models (a keyed encounter, an unguarded area treasure, or an NPC-party report) an author can review, place, and edit. Every draw comes from the passed stream in a fixed order (contents d6, treasure d6, d20, count, then variant/pool), mirroring the crawl's wandering resolution so a stocked row yields what a wandering encounter on that row would. `KeyedEncounter.hoard` (default True) gates `_generate_lair_hoard` so the treasure-absent keyed room — a monster room the stocking roll gave no treasure — is expressible; the default preserves every existing document's play semantics. Claude-Session: https://claude.ai/code/session_01SN8gc3PnSwXgKqqgfVcA4x
Extract `select_encounter_individuals` into core/tables.py as the single home for resolving a monster row's individuals (variant/pool/single) from a stream, and have both `wandering_check` and `stock_area` consume it. This removes the copy-pasted resolution and the duplicated `_dice_minimum`, so a stocked row can never drift from a wandering roll on that row — the byte-for-byte contract is now structural, not a hand-kept parallel. Adds resolver unit tests pinning its draw. Claude-Session: https://claude.ai/code/session_01SN8gc3PnSwXgKqqgfVcA4x
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Grows osrlib with the SRD dungeon-stocking procedure its own spec deferred with "the generator that consumes them comes later" — osr-editor's phase 7 is that first consumer — and cuts 1.3.0.
Added
osrlib.crawl.stocking.stock_area— the stocking procedure over the shipped tables. Given a dungeon level, an effective monster catalog, and oneRngStream, it rolls one keyed area's contents and answers a frozenStockedAreaof content models (aKeyedEncounter, an unguardedAreaTreasureSpec, or aStockedNpcPartyreport) an author can review, place, and edit. Every draw comes from the passed stream in a fixed order — contents d6, treasure d6 when the row's chance is non-zero, then on a monster room the d20 row, its count, and the variant roll or per-individual pool picks — so a stocked area is reproducible from the stream's state alone.KeyedEncounter.hoard(defaultTrue) — gates_generate_lair_hoardat first spawn. The default preserves every existing document's play semantics;hoard=Falseexpresses the treasure-absent keyed room the SRD stocking roll produces, which an unconditional lair hoard could not otherwise represent.Shared resolution, not a parallel copy
select_encounter_individualsis extracted intocore/tables.pyas the single home for resolving a monster row's individuals (variant / pool / single) from a stream. Bothwandering_checkandstock_areaconsume it, so a stocked row can never drift from a wandering roll on that row — the byte-for-byte agreement is structural rather than a hand-kept parallel. The duplicated_dice_minimumis gone with it.Boundaries
Traps and specials produce no models (B/X ships example lists as referee prose, not tables), and an NPC-party row has no authorable content model — the procedure reports the rolled kind and count and stops. Treasure generates exactly once at play: a stocked monster room's hoard comes from the encounter's gated lair cache, an empty or trap room's from its unguarded spec, never both.
Tests
tests/test_stocking.py— seeded goldens across all four contents kinds, the variant / pool / NPC-party rows, count-pinning, the catalog-resolution contract, per-address stream independence, the shared resolver's draw, and the hoard gate driven through a real session (same seed, gate flipped: exactly one cache vs. none).Full gate green: ruff format, ruff check, pyright 0 errors, 1579 passed / 58 skipped.
https://claude.ai/code/session_01SN8gc3PnSwXgKqqgfVcA4x