Creating an Area

Areas contain all the "content" of the MUD: items, npcs, rooms, and quests.

Directory Structure

A single bundle can contain multiple areas and, like bundles, an area need only have the files necessary for the content (i.e., you don't need to include a quests file if you have no quests.) For completeness this example bundle with a single area has all of the possible entities: items, npcs, scripts, and quests.

Note: This guide uses the default entity loading setup of using YAML files for content. This can be customized by following the Entity Loaders guide.

Click on any of the items to see more in-depth tutorials on their contents.

ranvier-areas/
  areas/
    limbo/ - Actual area folder, name will be used as key for `area:id`
             pairs which you'll see for items/npcs
      scripts/     - Scripts for individual entities
      manifest.yml - Required - Metadata about the area itself
      items.yml    - Item definitions
      npcs.yml     - NPC definitions
      rooms.yml    - Room definitions
      quests.yml    - Quest implementations

The Manifest

The manifest right now is incredibly simple and only requires one setting: title.

Example Manifest

---
title: "My Area Title"

# metadata allows you to put any arbitrary data you want to use in scripts
metadata:
  someThing: "some custom data here"

# Areas are scriptable just like other game entities. They can have both a
# specific script file as well as behaviors. If you do not have a script
# or behaviors you don't need to specify these fields
script: "foo" # lives in scripts/foo.js of the area folder
behaviors:
  # example of having the area use the behavior called 'progressive-respawn'
  # with configuration
  progressive-respawn:
    interval: 20

Entity References

You'll often see strings like limbo:sliceofcheese. These are entity references and can refer to Items, NPCs, Rooms, and Quests. The type of entity the reference points to is inferred from its context (e.g., foo:bar in an items list would point to an Item.) Let's take a look at an example NPC definition:

Assuming both of these definitions live in bundles/awesome-bundle/areas/foobar/

- id: dirk
  name: "Dirk Jones"
  items: [ "foobar:dirk" ]

and an accompanying item definition

- id: dirk
  name: "Dirk of Awesomeness"

In the definition of Dirk Jones, the value foobar:dirk in the items property's array means "Find item with the ID dirk in the area foobar". Entity ids are only unique within the same entity type of the same area. So even though Dirk Jone's entity reference is also foobar:dirk, items: ["foobar:dirk"] would refer to an item.

This string will be described in the subsequent docs as EntityReference.

Coordinates & Mapping

This section is only relevant if you are using coordinates for rooms as described in the Rooms guide.

Coordinates for an area are local to that area meaning each area is essentially its own "universe." Think of it like a video game where you are walking in an area then you come up to a door and when you go in the door you get a loading screen and area taken to a different place. So if two areas have room at [2, 3, -1] they will not overlap because that [2, 3, -1] is local to that area's map.

If you want the game to act as if there was one huge contiguous map then all you need to do is build one big contiguous area.

Mapping

One way to map a room is to simply iterate over the rooms property of an area instance as each room will have its coordinates property has an object like {x: 1, y: 0, z: -1} and you can do whatever you like with those values.

The other way is to use the map and floors properties like so:

for (const z of area.floors) {
  const floor = area.map.get(z);

  /*
  Each floor in the `map` is an instance of `AreaFloor` which has the low(X/Y)
  and high(X/Y) that you can use to define your loop boundaries.

  In this case this code will just draw a square map of the entire area.
  */
  let mapString = '';
  for (let y = floor.highY; y >= floor.lowY; y--) {
    for (let x = floor.lowX; x <= floor.highX; x++) {
      if (area.getRoomAtCoordinates(x, y, z)) {
        mapString += '.';
      } else {
        mapString += ' ';
      }
    }
    mapString += '\r\n';
  }

  console.log('Floor ' + z);
  console.log(mapString);
}

You can see an example of mapping by looking at the map command inside bundles/bundle-example-commands/commands/map.js. Further you can look at the move and look commands to see how the coordinates system is used to infer exits.