From 400ebe42757398c7d7993b232699d547a85d2b22 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Wed, 11 Feb 2026 12:12:30 -0500 Subject: [PATCH] Add object model design doc --- docs/how/object-model.rst | 250 ++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 251 insertions(+) create mode 100644 docs/how/object-model.rst diff --git a/docs/how/object-model.rst b/docs/how/object-model.rst new file mode 100644 index 0000000..369a89f --- /dev/null +++ b/docs/how/object-model.rst @@ -0,0 +1,250 @@ +object model — containment, verbs, and the location tree +======================================================== + +a design doc for the object hierarchy that powers containment, inventory, +zones, and verb-driven interaction. captures the core rule, the class +structure, and how everything connects. + +see also: ``things-and-building.rst`` (@thing/@verb decorator system), +``zones-and-building.rst`` (zone data format), ``architecture-plan.txt`` +(engine/content boundary), ``combat.rst`` (combat on Entity subgraph). + + +the core rule +------------- + +every object has a ``location`` attribute that points to another object, or +None. that's the entire containment system. + +where something is = what its location points to. None means it's a top-level +thing — a zone, a template that hasn't spawned yet, or something removed from +the world. + +here's what the tree looks like:: + + overworld zone (location=None) + ├── player "jared" (location=overworld, x=50, y=30) + │ ├── sword (location=jared) ← inventory + │ └── backpack (location=jared) ← inventory + │ ├── gem (location=backpack) ← nested + │ └── potion (location=backpack) + ├── oak tree (location=overworld, x=50, y=31) ← fixture + └── portal (location=overworld, x=52, y=30) ← leads to tavern zone + + tavern zone (location=None) + ├── bartender mob (location=tavern, x=3, y=2) + ├── chair (location=tavern, x=1, y=1) ← fixture + └── mug (location=tavern, x=3, y=3) ← item on the floor + +``contents`` is the reverse query — "give me everything whose location is me." + +spatial position (x, y) is optional. objects in zones have coordinates. items +in inventory don't. a sword in your backpack has location=backpack, x=None, +y=None. + + +the hierarchy +------------- + +:: + + Object (name, location, x, y) ← @verb targets this + ├── Zone (width, height, toroidal, terrain) + ├── Entity (combat stats) + │ ├── Player (session stuff) + │ └── Mob (ai stuff) + ├── Thing (description, portable) + │ ├── Container (capacity, closed, locked) + │ └── Portal (target_zone, target_x, target_y) + └── (Exit — maybe, if portals don't cover it) + +**Object** + base class for everything in the world. has name, location (Object or + None), optional x/y for spatial position within location. the @verb + decorator targets this — anything can have verbs. defines ``can_accept(obj)`` + method (default: False) for controlling what can be placed inside. + +**Zone** + a spatial area with a grid. the overworld, a tavern interior, a pocket + dimension. location=None (top-level). has terrain, dimensions, toroidal + flag. ``can_accept`` returns True (zones accept everything). defines + ``contents_at(x, y)`` for spatial queries. + +**Entity** + something that fights. adds combat stats (PL, stamina, defense timing). + ``can_accept`` allows portable Things (inventory). + +**Player** + a connected human. adds writer, mode_stack, caps, editor, if_session. + subclass of Entity. + +**Mob** + AI-controlled entity. adds moves list, behavior. subclass of Entity. + +**Thing** + an interactive object. adds description, portable flag. the @thing + decorator targets this for spawnable templates. + +**Container** + a Thing that explicitly accepts contents. adds capacity, closed, locked + state. game-facing behaviors (open/close, lock/unlock, put/get). + +**Portal** + a Thing that connects zones. adds target_zone, target_x, target_y. + portable=False. + +**Exit** + not needed yet. portals + zone grids might cover all transitions. parked + until we discover it's necessary. + +note: Fixture was considered as a class but we just use +``Thing(portable=False)`` instead. no shared behavior that warrants a class. + + +containment mechanics +--------------------- + +the containment MECHANISM is on Object (any object can technically be a +location via the location pointer). but the GAME restricts it via +``can_accept()``: + +- Zone: accepts everything +- Entity: accepts portable Things (inventory) +- Container: accepts items up to capacity, if not closed +- Thing: rejects by default (can't put a sword inside another sword) +- Object base: rejects by default + +this means containment is a capability, not a class. follows the Evennia/LPC +pattern. the Container class just bundles the common container game behaviors +— it's not special from a tree perspective. + + +location=None +------------- + +three things have location=None: + +1. **zones** — they're top-level containers. the overworld, tavern zone, etc. + +2. **templates/prototypes** — things that exist but aren't placed anywhere yet. + a mob template, an item blueprint. they're in code or data files but not + spawned into the world. + +3. **despawned objects** — removed from the world but not deleted. a mob dies + and goes back to location=None until respawn. + +this is first-class. a mob template at location=None is the prototype. spawn +it = clone with location=zone. dies = back to location=None until respawn. +no special flags needed, just the natural state. + + +verbs on everything +------------------- + +@verb targets Object, not Thing. everything in the world can have verbs: + +- "pet" a mob (verb on Entity) +- "open" a chest (verb on Container) +- "drink from" a fountain (verb on Thing with portable=False) +- "dig" in a zone (verb on Zone) +- "high-five" a player (verb on Entity) + +the verb system doesn't care about the class hierarchy. if it's an Object and +has a verb registered, players can use it. + + +how existing code maps in +-------------------------- + +Entity(name, x, y) → Entity(name, location=zone, x=5, y=10) + entities gain a location field. x/y stay but become relative to location. + +Player/Mob → same, just gains location field from Object parent + existing code largely unchanged. location replaces implicit zone references. + +overworld terrain grid → becomes a Zone object + the procedural perlin overworld becomes a Zone instance. toroidal, with + generator=perlin. + +planned zones (tavern, tutorial) → each a Zone object + hand-built zones like the treehouse. bounded or toroidal, tile data from + TOML files. + +planned portals → Portal things inside zones + portals are objects with target_zone, target_x, target_y. live inside zones + like any other Thing. + +@thing PepsiCan from things-and-building doc → Thing subclass + same as planned. @thing decorator creates Thing templates. spawn them into + zones or player inventory. + +combat encounters → still between Entities, unchanged + combat operates on the Entity subgraph. location doesn't matter for combat + resolution, only proximity (same zone, nearby x/y). + +IF sessions → still on Player, unchanged + if_session lives on Player. the IF subprocess doesn't care about location. + +mode stack → still on Player, unchanged + mode_stack is a Player concern. doesn't interact with the object tree. + +the migration is gentle. Entity gains a location field and x/y become +optional (None when inside a non-spatial container like a backpack). + + +what this enables +----------------- + +- **inventory** — put sword in backpack, backpack in player. nested + containment via location pointers. + +- **items on the ground** — sword at location=zone, x=5, y=10. visible to + anyone at those coordinates. + +- **furniture and fixtures** — Thing with portable=False. a fountain, a tree, + a statue. stays put, but can have verbs. + +- **containers** — chests, bags, locked doors. Container subclass handles + capacity, closed, locked state. + +- **zone transitions** — portals as objects. step on portal tile, location + changes to target zone. + +- **mob templates and spawning** — location=None is the template. spawn = + clone with location=zone. dies = back to None. + +- **verb-driven interaction on anything** — pet the cat, read the sign, dig + the ground. @verb on Object means no restrictions. + +- **the "phone switch" navigation zone** — a zone full of portals. walk to + a portal, step through, appear in that world. the hub. + + +open questions (parked) +----------------------- + +- **equipment slots** (wield, wear) — additive later when combat needs it. do + we track worn/wielded separately from inventory, or is it just metadata on + the Thing? defer until combat design demands it. + +- **Exit class** — may not be needed. portals might cover it. if we discover + a need for one-way passages with different behavior than portals, revisit. + +- **persistence** — which objects persist to SQLite, which are runtime-only? + player inventory persists. zone state (tile changes from paint mode) + persists to TOML. mob instances probably don't persist (respawn from + templates). decide per-class as we implement. + +- **object registry implementation** — global dict? spatial index? contents + cache? probably: zones maintain contents_at(x, y) lookups, global registry + maps object IDs to instances for verb resolution. + + +related docs +------------ + +- ``things-and-building.rst`` — @thing/@verb decorator system, content layer + on top of this model +- ``zones-and-building.rst`` — zone data format, building tools, paint mode +- ``architecture-plan.txt`` — overall engine/content boundary +- ``combat.rst`` — combat system (operates on Entity subgraph) diff --git a/docs/index.rst b/docs/index.rst index 2acda63..1824a96 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -19,6 +19,7 @@ engine - ``docs/how/terrain-generation.txt`` — perlin noise, elevation thresholds, river tracing - ``docs/how/things-and-building.rst`` — interactive objects, python class decorators - ``docs/how/zones-and-building.rst`` — zones as spatial unit, procedural overworld, player homes +- ``docs/how/object-model.rst`` — object hierarchy, containment, verbs, location system - ``docs/how/prompt-system.txt`` — modal prompts, color markup, per-player customization combat