Skip to content

Let authors place named magic items in treasure caches - #40

Merged
mmacy merged 1 commit into
mainfrom
feat/authored-magic-items
Jul 30, 2026
Merged

Let authors place named magic items in treasure caches#40
mmacy merged 1 commit into
mainfrom
feat/authored-magic-items

Conversation

@mmacy

@mmacy mmacy commented Jul 30, 2026

Copy link
Copy Markdown
Owner

What

An authored treasure cache could carry coins, mundane equipment ids, and named valuables — but a specific magic item (the sword +1 in the captain's strongbox) was unplaceable at every layer: magic entered play only through generated hoards. This PR adds the authoring surface:

  • FeatureSpec.magic_item_ids — an additive tuple of ids from the shipped magic-item catalog (see the magic item id index). Listing an id twice places two.
  • instantiate_magic_item — the named-item half of generate_magic_item, factored out as a public function: no table selection, just the depth-first creation-detail resolution (the Magic Armour Type d8, charges, quantities, wish counts, scroll contents, the energy-drain total, sword sentience). generate_magic_item now calls it per row item, so the two paths cannot drift.
  • Take-path instantiation — hand-placed magic items instantiate when the cache is emptied, details rolling on the treasure stream at the tier in force at that moment, exactly as a generated hoard's would. Authored content stays frozen; a save made before the take carries no undiscoverable referee facts.
  • Validationvalidate_adventure resolves the new ids against the shipped magic-item catalog (loaded internally; adventures bundle no magic items), a hard content error before play. validate_content_pack reports the same gap as the new pack.feature.unknown_magic_item finding.

Contracts

  • No schema bump: additive field with an empty default; existing documents load unchanged.
  • Determinism: a cache placing no magic items consumes no extra draws — the goldens are untouched. Placed items draw on TREASURE_STREAM in tuple order at take time.
  • Layering: no new core→crawl imports; the take path in osrlib.crawl calls into osrlib.core.treasure.

Tests

  • test_treasure_kernel.py::TestMagicItemInstantiation — details roll like a generated item's (charges 2d10, ammunition 3d10, generic armour's base d8), same seed same instance, unknown id/tier raise.
  • test_exploration.py::TestAuthoredMagicItems — placed items land in packs unidentified with allocator ids, ride ItemAcquiredEvent, the cache empties once, and two seeded runs roll identical details.
  • test_dungeon.py — a shipped magic id validates; an unknown one is a ContentValidationError naming the id.
  • test_content_pack.py — the new finding code, with the known id passing silently.

Full suite: 1668 passed, 58 skipped. ruff format/check clean, mkdocs build -s clean.

https://claude.ai/code/session_01FAGD8y9X4XeCdZN1nuLJxc

FeatureSpec grows magic_item_ids, an additive tuple of shipped magic-item
catalog ids. The instances are created when the cache is emptied: the new
public instantiate_magic_item — the named-item half of generate_magic_item,
now factored out — rolls the creation details (charges, quantities, generic
armour's base type, scroll contents, sword sentience) on the treasure stream
at the tier in force at the take, exactly as a generated hoard's would.

validate_adventure resolves the new ids against the shipped magic-item
catalog (loaded internally — adventures bundle no magic items), and
validate_content_pack reports the same gap as the new
pack.feature.unknown_magic_item finding.

No schema bump: the field is additive with an empty default, existing
documents load unchanged, and a cache placing no magic items consumes no
extra draws — the goldens are untouched.

Claude-Session: https://claude.ai/code/session_01FAGD8y9X4XeCdZN1nuLJxc
@mmacy
mmacy merged commit a26c08c into main Jul 30, 2026
5 checks passed
@mmacy
mmacy deleted the feat/authored-magic-items branch July 30, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant