Skip to content

Tutorial Part 4: Creating Rooms & Items

Estimated time: 45 minutes


Welcome back! In Part 3, you learned how to create commands - the primary way players interact with your game. Now it is time to build the world itself: rooms for players to explore and items for them to find and use.

What You Will Learn

By the end of this tutorial, you will:

  1. Understand how rooms and items are represented in MAID
  2. Create rooms programmatically with components
  3. Use builder commands to quickly create game content
  4. Build items with proper components and templates
  5. Connect rooms with exits
  6. Complete a hands-on exercise: building a 5-room dungeon

Why Rooms and Items Matter

In a MUD, the world is built from two fundamental elements:

  • Rooms - The locations players can visit. Every player is always "in" a room. Rooms contain descriptions, exits to other rooms, and can hold items and NPCs.

  • Items - Objects players can interact with. Items can be picked up, dropped, equipped, used, or stored in containers.

Together, rooms and items create the tangible world that brings your game to life. A well-designed room tells a story through its description, rewards exploration through hidden items, and connects logically to other parts of your world.


Room Entity Structure

In MAID, rooms are registered with the World and contain several pieces of information:

+------------------+
|     Room Data    |
+------------------+
| - id (UUID)      |
| - name           |
| - description    |
| - exits {}       |
| - area_id        |
+------------------+

Unlike player characters or items, rooms are not full ECS entities. Instead, they are simple data objects that hold:

  • id - Unique identifier (UUID)
  • name - Display name shown to players
  • description - What players see when they "look"
  • exits - Dictionary mapping directions to destination room IDs
  • area_id - Optional zone/area grouping

Core Room Components

While basic rooms use simple data objects, you can enhance rooms with components for richer functionality.

DescriptionComponent

The DescriptionComponent provides names, descriptions, and keywords:

from maid_stdlib.components import DescriptionComponent

DescriptionComponent(
    name="Town Square",
    short_desc="A bustling town square",
    long_desc="You stand in the heart of town, surrounded by merchants...",
    keywords=["square", "plaza", "center"],
)
Field Type Description
name str Display name
short_desc str One-line description (for room lists, etc.)
long_desc str Full description shown when looking
keywords list[str] Words that can match this entity

ExtendedRoomComponent

For dynamic descriptions that change based on time of day, weather, or season, use ExtendedRoomComponent:

from maid_stdlib.components import (
    ExtendedRoomComponent,
    ExtendedDescriptions,
    TimeOfDay,
    Weather,
    Season,
)

extended = ExtendedRoomComponent(
    descriptions=ExtendedDescriptions(
        base_description="A cozy tavern with a roaring fireplace.",
        time_variants={
            TimeOfDay.NIGHT: "The tavern is dimly lit by flickering candles.",
            TimeOfDay.MORNING: "Morning light streams through dusty windows.",
        },
        weather_effects={
            Weather.RAIN: "Rain drums steadily on the roof above.",
            Weather.STORM: "Thunder rumbles outside, making the walls shake.",
        },
        season_variants={
            Season.WINTER: "A thick layer of frost covers the windows.",
        },
    )
)

The description automatically adapts based on current conditions:

context = {
    "time": TimeOfDay.NIGHT,
    "weather": Weather.RAIN,
    "season": Season.WINTER,
}
description = extended.get_description(context)
# "A cozy tavern with a roaring fireplace.
#  The tavern is dimly lit by flickering candles.
#  A thick layer of frost covers the windows.
#  Rain drums steadily on the roof above."

Creating Rooms Programmatically

Let's create a room using code. This is useful when building world generation systems or loading rooms from data files.

Basic Room Creation

from uuid import uuid4
from maid_stdlib.commands.building.create import RoomData

# Create room data
room_id = uuid4()
room = RoomData(
    id=room_id,
    name="Town Square",
    description="You stand in the heart of the bustling town. "
                "Merchants hawk their wares from colorful stalls, "
                "and the smell of fresh bread wafts from a nearby bakery.",
    exits={},  # No exits yet
    area_id=None,
)

# Register the room with the world
world.register_room(room_id, room)

Connecting Rooms with Exits

Exits are stored as a dictionary mapping direction names to destination room IDs:

# Create two rooms
square_id = uuid4()
square = RoomData(
    id=square_id,
    name="Town Square",
    description="The central plaza of the town.",
    exits={},
)

market_id = uuid4()
market = RoomData(
    id=market_id,
    name="Market Street",
    description="A busy street lined with merchant stalls.",
    exits={},
)

# Register both rooms
world.register_room(square_id, square)
world.register_room(market_id, market)

# Connect them with exits (bidirectional)
square.exits["north"] = market_id
market.exits["south"] = square_id

Standard Directions

MAID supports these standard directions:

Direction Opposite Aliases
north south n
south north s
east west e
west east w
up down u
down up d
northeast southwest ne
northwest southeast nw
southeast northwest se
southwest northeast sw
in out -
out in -

You can also use custom direction names like "portal", "trapdoor", or "climb".

Creating a Room Helper Function

Here's a reusable function for creating connected rooms:

from uuid import UUID, uuid4
from maid_stdlib.commands.building.create import RoomData


def create_room(
    world,
    name: str,
    description: str,
    area_id: UUID | None = None,
) -> UUID:
    """Create and register a new room.

    Returns:
        The UUID of the created room.
    """
    room_id = uuid4()
    room = RoomData(
        id=room_id,
        name=name,
        description=description,
        exits={},
        area_id=area_id,
    )
    world.register_room(room_id, room)
    return room_id


def connect_rooms(
    world,
    from_room_id: UUID,
    direction: str,
    to_room_id: UUID,
    bidirectional: bool = True,
) -> None:
    """Connect two rooms with exits.

    Args:
        world: The game world
        from_room_id: Source room UUID
        direction: Exit direction (e.g., "north")
        to_room_id: Destination room UUID
        bidirectional: If True, create return exit
    """
    opposites = {
        "north": "south", "south": "north",
        "east": "west", "west": "east",
        "up": "down", "down": "up",
    }

    from_room = world.get_room(from_room_id)
    to_room = world.get_room(to_room_id)

    # Create forward exit
    from_room.exits[direction] = to_room_id

    # Create return exit if bidirectional
    if bidirectional and direction in opposites:
        to_room.exits[opposites[direction]] = from_room_id

Using Builder Commands

While programmatic room creation is powerful, MAID provides builder commands for rapid world building directly from within the game. These commands are available to users with BUILDER access level or higher.

@dig - Create Rooms and Connect Them

The @dig command creates a new room and automatically connects it to your current room.

Syntax:

@dig <direction> [= room_name] [options]

Options: - --oneway - Create only the outgoing exit (no return path) - --door - The exit has a door - --locked - The door starts locked (implies --door) - --hidden - The exit is hidden until discovered

Examples:

> @dig north
Dug north to 'New Room (north of Town Square)' (ID: abc123...)

> @dig north = The Dark Cave
Dug north to 'The Dark Cave' (ID: def456...)

> @dig up = Tower Top --oneway
Dug up to 'Tower Top' (ID: ghi789...)
  (one-way exit)

> @dig east = Secret Room --door --locked --hidden
Dug east to 'Secret Room' (ID: jkl012...)
  (with door, locked)
  (hidden)

@describe - Set Room Descriptions

After creating a room, use @describe to set its description.

Syntax:

@describe <target> [description]

Examples:

> @describe here
Room: The Dark Cave
Description: An empty room.

> @describe here A damp cave stretches before you. Water drips from stalactites overhead, and strange mushrooms glow faintly in the darkness.
Set description for room 'The Dark Cave'.

@name - Rename Rooms

Change a room's name with @name.

Syntax:

@name <target> <new_name>

Example:

> @name here The Glowing Cavern
Renamed room from 'The Dark Cave' to 'The Glowing Cavern'.

@tunnel - Connect to Existing Rooms

Use @tunnel to create a passage to a room that already exists.

Syntax:

@tunnel <direction> <room_id> [options]

Example:

> @tunnel west 550e8400-e29b-41d4-a716-446655440000
Created tunnel west to 'Town Square'

For finer control over exits:

@link - Create an exit to a destination:

> @link portal #550e8400... --oneway
Linked portal to 'Magic Chamber'.
  (one-way link)

@unlink - Remove an exit:

> @unlink north
Removed exit to the north.

> @unlink east --both
Removed exit to the east.
Removed return exit (west) from destination.

Practical Walkthrough: Building a Small Area

Let's build a small tavern area using builder commands:

# Start in the Town Square
> look
Town Square
You are in the center of a bustling town...
Exits: none

# Create the tavern to the east
> @dig east = The Rusty Tankard
Dug east to 'The Rusty Tankard' (ID: abc123...)

# Go to the tavern
> east
The Rusty Tankard
An empty room.
Exits: west

# Set the tavern's description
> @describe here A cozy tavern filled with the smell of ale and roasting meat. Wooden beams criss-cross the ceiling, and a large fireplace crackles warmly against the far wall.
Set description for room 'The Rusty Tankard'.

# Create the cellar (one-way down - trapdoor!)
> @dig down = Tavern Cellar --door
Dug down to 'Tavern Cellar' (ID: def456...)
  (with door)

# Go to the cellar
> open down
You open the trapdoor.

> down
Tavern Cellar
An empty room.
Exits: up

# Describe the cellar
> @describe here A cool, damp cellar lined with barrels of ale and crates of supplies. Cobwebs hang in the corners, and you hear rats scurrying in the shadows.
Set description for room 'Tavern Cellar'.

Item Entity Structure

Items in MAID are full ECS entities with components attached. This makes them flexible and extensible.

+------------------+
|   Item Entity    |
+------------------+
| id: UUID         |
| tags: [item]     |
+------------------+
        |
        v
+------------------+    +------------------+
|DescriptionComp   |    |  ItemComponent   |
+------------------+    +------------------+
| name             |    | item_type        |
| short_desc       |    | quality          |
| long_desc        |    | weight           |
| keywords         |    | value            |
+------------------+    | stack_count      |
                        | is_bound         |
                        | durability       |
                        +------------------+

ItemComponent

The ItemComponent defines item-specific properties:

from maid_stdlib.components import ItemComponent

ItemComponent(
    item_type="weapon",     # weapon, armor, consumable, material, misc, etc.
    quality="uncommon",     # common, uncommon, rare, epic, legendary
    weight=2.5,             # Weight in arbitrary units
    value=100,              # Base gold value
    stack_count=1,          # Current stack size
    max_stack=1,            # Maximum stack size (1 = not stackable)
    is_bound=False,         # Cannot be traded/dropped
    durability=100,         # Current durability
    max_durability=100,     # Maximum durability
)

Common Item Types

Type Description Examples
weapon Deals damage Sword, axe, bow
armor Provides protection Helmet, chainmail
consumable Single-use items Potion, food, scroll
material Crafting components Iron ore, leather
container Holds other items Bag, chest
key Opens locked doors Brass key, skeleton key
misc Everything else Torch, rope, book

Creating Items Programmatically

Basic Item Creation

from maid_stdlib.components import DescriptionComponent, ItemComponent

# Create item entity
item = world.create_entity()
item.add_tag("item")

# Add description
item.add(DescriptionComponent(
    name="Iron Sword",
    short_desc="A sturdy iron sword lies here.",
    long_desc="This well-forged iron sword has a leather-wrapped hilt "
              "and a blade that gleams in the light.",
    keywords=["sword", "iron", "blade", "weapon"],
))

# Add item component
item.add(ItemComponent(
    item_type="weapon",
    quality="common",
    weight=3.0,
    value=50,
))

# Place in a room
world.place_entity_in_room(item.id, room_id)

Item Templates

Templates let you define reusable item configurations:

from maid_stdlib.commands.building.create import (
    EntityTemplate,
    register_template,
)

# Define a sword template
iron_sword_template = EntityTemplate(
    name="iron_sword",
    entity_type="item",
    description="A standard iron sword.",
    keywords=["sword", "iron", "blade", "weapon"],
    metadata={
        "item_type": "weapon",
        "quality": "common",
        "weight": 3.0,
        "value": 50,
    },
    tags=["weapon", "melee"],
)

# Register the template
register_template(iron_sword_template)

Now you can create items from the template:

from maid_stdlib.commands.building.create import (
    get_entity_factory,
    get_template,
)

# Get the factory and template
factory = get_entity_factory("item")
template = get_template("iron_sword")

# Create an item from the template
sword = factory.create(
    world,
    "Iron Sword",
    template=template,
    room_id=room_id,
)

Using @create for Items

In-game, use @create to make items:

> @create item Rusty Dagger
Created item 'Rusty Dagger' with ID: abc123... in current room

> @create item Health Potion = potion_template
Created item 'Health Potion' with ID: def456... in current room

Container Items

Containers are special items that can hold other items. They have both ItemComponent and InventoryComponent.

Creating Containers

from maid_stdlib.components import (
    DescriptionComponent,
    ItemComponent,
    InventoryComponent,
)

# Create container entity
chest = world.create_entity()
chest.add_tag("item")
chest.add_tag("container")

# Add description
chest.add(DescriptionComponent(
    name="Wooden Chest",
    short_desc="A sturdy wooden chest sits here.",
    long_desc="This iron-bound wooden chest looks old but solid. "
              "A simple latch holds it closed.",
    keywords=["chest", "wooden", "container", "box"],
))

# Add item component (containers are items)
chest.add(ItemComponent(
    item_type="container",
    weight=10.0,
    value=25,
))

# Add inventory component (containers have inventory)
chest.add(InventoryComponent(
    capacity=20,           # Can hold 20 items
    weight_limit=100.0,    # Maximum weight capacity
))

# Place in room
world.place_entity_in_room(chest.id, room_id)

Using @create for Containers

> @create container Large Chest
Created container 'Large Chest' with ID: abc123... in current room

Putting Items in Containers

Programmatically:

# Get the container's inventory
inventory = chest.get(InventoryComponent)

# Add an item to the container
item_weight = item.get(ItemComponent).weight
inventory.add_item(item.id, weight=item_weight)

# Update item's location (remove from room)
world.remove_entity_from_room(item.id)

Spawning Items

The @spawn command creates items from templates with additional options:

> @spawn health_potion
Spawned 'Health Potion' (item) in 'Town Square' with ID: abc123...

> @spawn health_potion 5
Spawned 5 'Health Potion' (item) entities in 'Town Square'
  - ID: abc123...
  - ID: def456...
  - ID: ghi789...
  - ID: jkl012...
  - ID: mno345...

> @spawn treasure_chest 3 = #550e8400...
Spawned 3 'Treasure Chest' (container) entities in 'Dungeon Treasury'

Respawning Mechanics

For items that should reappear over time (like loot in a dungeon), you would typically implement a respawn system. This is covered in more detail in the content pack tutorials, but the basic approach is:

  1. Create item templates for respawnable items
  2. Implement a RespawnSystem that tracks spawn points
  3. Use the tick loop to check and respawn items periodically

Exercise: Build a 5-Room Dungeon

Now let's put everything together! Your task is to build a small dungeon with:

  1. Entrance Hall - The entry point
  2. Guard Room - Contains a torch
  3. Treasury - Contains a treasure chest with gold
  4. Prison Cell - Contains a skeleton key
  5. Boss Chamber - Contains a locked door requiring the key

Step 1: Create the Rooms

Connect via telnet and create the dungeon:

# Start at your current location (or create a starting room)
> @dig down = Dungeon Entrance
Dug down to 'Dungeon Entrance' (ID: entrance-id...)

> down
Dungeon Entrance
An empty room.

> @describe here You descend into a damp stone passage. Moss covers the ancient walls, and the air smells of earth and decay. Flickering torchlight reveals passages leading deeper into the darkness.
Set description for room 'Dungeon Entrance'.

# Create the Guard Room to the north
> @dig north = Guard Room
Dug north to 'Guard Room' (ID: guard-id...)

> north

> @describe here An abandoned guard post. Rusty weapons hang on the walls, and a battered table sits in the corner. Empty bottles suggest the guards left in a hurry.
Set description for room 'Guard Room'.

# Create the Treasury to the east (from Guard Room)
> @dig east = Treasury --door --locked
Dug east to 'Treasury' (ID: treasury-id...)
  (with door, locked)

# Go back and create the Prison Cell to the west of entrance
> south
> @dig west = Prison Cell
Dug west to 'Prison Cell' (ID: prison-id...)

> west

> @describe here A cramped cell with rusted iron bars. Bones litter the floor, and chains hang from the walls. Whatever was imprisoned here is long gone.
Set description for room 'Prison Cell'.

# Create the Boss Chamber to the north of entrance (requires going back)
> east
> @dig east = Boss Chamber --door --locked --hidden
Dug east to 'Boss Chamber' (ID: boss-id...)
  (with door, locked)
  (hidden)

Step 2: Add Items

# Go to Guard Room and create a torch
> north
> @create item Burning Torch
Created item 'Burning Torch' with ID: torch-id...

> @describe torch A torch burning with a bright, steady flame. It illuminates the surrounding area.
Set description for 'Burning Torch'.

# Go to Prison Cell and create a skeleton key
> south
> west
> @create item Skeleton Key
Created item 'Skeleton Key' with ID: key-id...

> @describe key An ancient key made of yellowed bone. It seems to vibrate slightly when held.
Set description for 'Skeleton Key'.

# Go to Treasury (need to unlock it first - for now, use @goto)
> @goto #treasury-id
Treasury
An empty room.

> @describe here Piles of gold coins glitter in the torchlight. Jewel-encrusted goblets and ancient artifacts line the shelves. This must have been the dragon's hoard.
Set description for room 'Treasury'.

> @create container Treasure Chest
Created container 'Treasure Chest' with ID: chest-id...

> @describe chest A massive iron-bound chest overflowing with gold and jewels.
Set description for 'Treasure Chest'.

# Go to Boss Chamber
> @goto #boss-id
Boss Chamber
An empty room.

> @describe here A vast cavern with a high vaulted ceiling. Bones of previous adventurers crunch underfoot. In the center, upon a throne of skulls, waits the dungeon's master.
Set description for room 'Boss Chamber'.

Step 3: Verify Your Dungeon

Walk through your dungeon to make sure everything is connected:

> @goto #entrance-id
Dungeon Entrance
You descend into a damp stone passage...
Exits: up, north, west, east

> look
Dungeon Entrance
You descend into a damp stone passage. Moss covers the ancient walls, and the air smells of earth and decay. Flickering torchlight reveals passages leading deeper into the darkness.

Obvious exits: up, north, west, east

> north
Guard Room
An abandoned guard post...

You see here:
  A Burning Torch

Congratulations!

You have built your first dungeon! This exercise demonstrated:

  • Creating rooms with @dig
  • Setting descriptions with @describe
  • Creating items with @create
  • Creating containers
  • Using doors and locks
  • Connecting areas logically

What's Next?

You now know how to:

  • Create rooms programmatically and with builder commands
  • Use components to define room properties
  • Build items with templates
  • Create containers for item storage
  • Connect rooms with exits
  • Use the @dig, @describe, @create, and related commands

In the next tutorial, you will learn about NPCs and AI, bringing your world to life with characters that players can interact with.

Coming up in Part 5: NPCs & Basic AI

  • Creating NPC entities
  • NPC components and behaviors
  • AI-powered dialogue
  • NPC spawn points and respawning
  • Simple patrol and behavior patterns

< Previous: Part 3 - Commands Back to Tutorial Index Next: Part 5 - NPCs & AI >


Quick Reference

Room Creation Commands

Command Description Example
@dig <dir> [= name] Create room with exit @dig north = Cave
@tunnel <dir> <id> Connect to existing room @tunnel west #abc123
@describe <target> [text] Set/view description @describe here A cave.
@name <target> <name> Rename room/entity @name here Dark Cave
@link <dir> <dest> Create exit @link portal #abc123
@unlink <dir> Remove exit @unlink north --both

@dig Options

Option Description
--oneway No return exit
--door Exit has a door
--locked Door starts locked
--hidden Exit is hidden

Item Creation Commands

Command Description Example
@create item <name> Create item @create item Sword
@create item <name> = <template> Create from template @create item Sword = iron_sword
@create container <name> Create container @create container Chest
@spawn <template> [count] Spawn from template @spawn goblin 5

Standard Components

Component Purpose Key Fields
DescriptionComponent Names and descriptions name, short_desc, long_desc, keywords
ItemComponent Item properties item_type, quality, weight, value
InventoryComponent Storage capacity capacity, weight_limit, items
ExtendedRoomComponent Dynamic descriptions descriptions, exit_descriptions

Item Types

Type Description
weapon Damage-dealing items
armor Protective equipment
consumable Single-use items
material Crafting components
container Holds other items
key Opens locks
misc Miscellaneous items