Pre-release
AdventureJS Docs Downloads Bundler Devlog
Score: 0 Moves: 0
// Room.js
(function () {
  /* global AdventureJS A */

  /**
   * @ajspath AdventureJS.Atom.Asset.Tangible.Entity.Room
   * @augments AdventureJS.Assets.Entity
   * @class AdventureJS.Assets.Room
   * @ajsconstruct MyGame.createAsset({ "class": "Room", "name": "foo", [...] })
   * @ajsconstructedby AdventureJS.Game#createAsset
   * @ajsnavheading RoomAssets
   * @param {String} game_name The name of the top level game object.
   * @param {String} name A name for the object, to be serialized and used as ID.
   * @summary Where all the action happens.
   * @tutorial GettingStarted_CreateARoom
   * @ajstangiblecontainer in
   * @ajstangiblecontainer attached
   * @classdesc
   * <p>
   * <strong>Room</strong> is a subclass of
   * {@link AdventureJS.Assets.Entity|Entity} and the class for
   * all {@link AdventureJS.Game|Game} locations. Player is always
   * in a Room. Rooms connect to other Rooms via
   * {@link AdventureJS.Assets.Exit|Exits}, and can be decorated with
   * {@link AdventureJS.Assets.Scenery|Scenery} and random events.
   * To learn more, see
   * <a href="/doc/GettingStarted_CreateARoom.html">Create a Room</a>.
   * </p>
   *
   * <h3 class="examples">Exits:</h3>
   * <p>
   * There are two methods to define Exits, which can be mixed & matched.
   * The first method is a simple shortcut that defines an Exit
   * as part of a Room definition, using a direction and a
   * Room name, as in the following example. Exits are one-way, and
   * the other Rooms will need Exits back to this Room.
   * </p>
   * <pre class="display"><code class="language-javascript">MyGame.createAsset({
   *   class: "Room",
   *   name: "West of House",
   *   exits: {
   *     south: "South of House",
   *     north: "North of House",
   *     west: "Forest",
   *     east: "The door is boarded and you can't remove the boards. "
   *   }
   * })
   * </code></pre>
   * <p>
   * In the example above, the south, north and west Exits all lead to
   * other Rooms. There is no east Exit, but by providing a string
   * instead of a Room name, that string will be returned to players
   * who try to go east.
   * </p>
   * <p>
   * This next example uses the second method of defining an Exit,
   * which is to create the Room and its Exits as distinct objects.
   * </p>
   * <pre class="display"><code class="language-javascript">MyGame.createAsset({
   *   class: "Room",
   *   name: "Inside the Barrow",
   * });
   * MyGame.createAsset({
   *   class: "Exit",
   *   direction: "south",
   *   place: { in: "Inside the Barrow" },
   *   destination: "Narrow Tunnel",
   * });
   * </code></pre>
   * <p>
   * This second method supports greater complexity and allows
   * for more granular control once you get into custom coded Exits.
   * To learn more, see
   * <a href="/doc/GettingStarted_CreateAnExit.html">Create an Exit</a>.
   * </p>
   *
   * <h3 class="examples">Scenery:</h3>
   * <p>
   * By default,
   * {@link AdventureJS.Game|Game} instances include a number of
   * {@link AdventureJS.Assets.Scenery|Scenery}
   * {@link AdventureJS.Assets.Asset|Assets} which are available to use
   * in any Room. Scenery Assets can be sensed but not interacted
   * with, like sun and sky, rain and room tone, odors, walls,
   * and non-existent exits (to provide responses when players try
   * to use exits that don't exist).
   * Default Scenery objects can be enabled, customized, and disabled
   * at will by Room, by {@link AdventureJS.Assets.Zone|Zone}, and globally.
   * It's also possible to create new custom Scenery Assets.
   * In the example below, we enable and set custom descriptions
   * for the global <code>sky</code>, <code>clouds</code>,
   * <code>sun</code>, and <code>rain</code>;
   * and create a new custom Scenery <code>crows</code>.
   * </p>
   * <pre class="display"><code class="language-javascript">MyGame.createAsset({
   *   class: "Room",
   *   name: "Creepy Playground",
   *   descriptions: {
   *     at: "This creepy looking playground is dominated by a rusted jungle gym. ",
   *   },
   *   area_scenery: {
   *     sky: {
   *       enabled: true,
   *       description: "The clouded sky is dark and foreboding. ",
   *     },
   *     clouds: {
   *       enabled: true,
   *       description: "Heavy, black, and pendulous. ",
   *     },
   *     thunder: {
   *       enabled: true,
   *       description: "Occasional thunder plays in the distance. ",
   *     },
   *     lightning: {
   *       enabled: true,
   *       description: "None yet, but it wouldn't surprise you. ",
   *     },
   *     sun: {
   *       enabled: true,
   *       description: "You can barely see it through the dark clouds. ",
   *     },
   *     rain: {
   *       enabled: true,
   *       description: "The rain patters onto the playground's worn rubber mats. ",
   *     },
   *     crows: {
   *       create: true,
   *       enabled: true,
   *       description: "Evil looking crows circle the playground. ",
   *     },
   *   },
   * });
   * </code></pre>
   * <p>
   * To learn more about using the default Scenery Assets, see
   * <a href="/doc/AreaEffects_AreaScenery.html">Area Scenery</a>.
   * </p>
   *
   * <h3 class="examples">Events:</h3>
   * <p>
   * Events are arbitrary messages that can be attached to a Room
   * and set so that they are appended to any other output for the
   * turn. Use the <code>frequency</code> property of
   * <code>area_events</code> to set the frequency of events.
   * A frequency of 1 will play an event on every turn; .1 will play
   * an event every 10th turn; etc. The <code>randomize</code>
   * property determines whether events are selected to play randomly.
   * If <code>randomize</code> is set to true, events will play in
   * random order, otherwise events will play in the order they are
   * set in the array, looping as needed.
   * </p>
   * <pre class="display"><code class="language-javascript">MyGame.createAsset({
   *   class: "Room",
   *   name: "Creepy Playground",
   *   descriptions: {
   *     at: "This creepy looking playground is dominated by a rusted jungle gym. ",
   *   },
   *   area_events: {
   *     frequency: .1,
   *     randomize: true,
   *     array: [
   *       "A crow shrieks loudly, startling you. ",
   *       "Rain pings metallically off the jungle gym. ",
   *       "The rain raises a tarry odor from the playground's rubber mats. ",
   *       "Distant thunder rolls through the clouds. ",
   *       "The barest hint of lightning flicks in the distance. ",
   *     ],
   *   },
   * });
   * </code></pre>
   * <p>
   * To learn more about using events, see
   * <a href="/doc/AreaEffects_AreaEvents.html">Area Events</a>.
   * </p>
   **/
  class Room extends AdventureJS.Assets.Entity {
    constructor(name, game_name, context_id = "", id = "") {
      super(name, game_name, context_id, id);
      this.class = "Room";

      // this.is = new AdventureJS.Traits.Room_Is("is", this.game_name, this.id);

      this.synonyms = ["room"];
      this.singular = "room";
      this.plural = "rooms";
      this.singularPluralPairs = [["room", "rooms"]];

      this.indefinite_article = "a";

      // set to "the" to have a room listed as "the room"
      // set to "" to have room listed as "room"
      this.definite_article = "";

      this.use_articles_in_lists = true;

      this.default_aspect = "in";
      this.exits = {};
      this.is.dark = false;
      this.is.vacuum = false;
      this.is.closed = null;

      /**
       * If game.settings.use_dark_room_name is true,
       * this name will be used for the room if it is dark.
       * Ex: "In the dark"
       * @var {String} AdventureJS.Assets.Room#darkname
       * @default ""
       */
      this.darkname = "";

      /**
       * If game.settings.use_dark_room_situation is true,
       * this text will be appended to the room name if it is dark.
       * Ex: "Standing Room (in the dark)"
       * @var {String} AdventureJS.Assets.Room#darksituation
       * @default ""
       */
      this.darksituation = "";

      /**
       * Used to set whether a room has a floor. Most rooms do, but,
       * for example, an aquatic room or a zero-g room might not.
       * Items dropped in rooms without floors may require special handling.
       * @var {Boolean} AdventureJS.Assets.Room#has_floor
       * @default true
       */
      this.has_floor = true;

      /**
       * Used to store arbitrary events that may be printed
       * randomly to the game display.
       * @var {Boolean} AdventureJS.Assets.Room#area_events
       * @default {}
       */
      this.area_events = {};

      /**
       * Used to define the area scenery that is available
       * in this room.
       * @var {Boolean} AdventureJS.Assets.Room#area_scenery
       * @default {}
       */
      this.area_scenery = {
        air: { enabled: null },
        moon: { enabled: null },
        sky: { enabled: null },
        sun: { enabled: null },
        stars: { enabled: null },
        sound: { enabled: null },
        rain: { enabled: null },
        wind: { enabled: null },
        clouds: { enabled: null },
        lightning: { enabled: null },
        floor: { enabled: null },
        ceiling: { enabled: null },

        "north wall": { enabled: null },
        "east wall": { enabled: null },
        "west wall": { enabled: null },
        "south wall": { enabled: null },
        "aft wall": { enabled: null },
        "fore wall": { enabled: null },
        "northeast wall": { enabled: null },
        "northwest wall": { enabled: null },
        "port wall": { enabled: null },
        "southeast wall": { enabled: null },
        "southwest wall": { enabled: null },
        "starboard wall": { enabled: null },

        north: { enabled: true },
        east: { enabled: true },
        west: { enabled: true },
        south: { enabled: true },
        aft: { enabled: true },
        fore: { enabled: true },
        northeast: { enabled: true },
        northwest: { enabled: true },
        port: { enabled: true },
        southeast: { enabled: true },
        southwest: { enabled: true },
        starboard: { enabled: true },
        up: { enabled: true },
        down: { enabled: true },
      };

      this.zone = "";

      this.dimensions.height = 1;

      // unset these verbs inherited from Tangible / Entity
      //this.setDOVs(["stomp"]);
      this.unsetDOVs(["push", "take", "give", "drop", "move", "pull", "throw"]);
      this.unsetIOV("throw");
      this.setIOVs(["take", "drop", "put"]);
      this.setDOVs(["go", "dig"]);

      /**
       * Controls whether exit descriptions are appended
       * to the room's description.
       * If left to its default seeting of null, will use
       * <a href="/doc/AdventureJS.Settings.html#property_print_exits">game.settings.print_exits</a>.
       * If set to true or false, will override game settings
       * for this room.
       * @var {Boolean} AdventureJS.Assets.Room#print_exits
       * @default true
       */
      this.print_exits = null;

      /**
       * Wormholes are exits that go directly from one room to
       * another without a direction. By default, wormholes are
       * excluded from lists of room exits.
       * If left to its default seeting of null, will use
       * <a href="/doc/AdventureJS.Settings.html#property_exclude_wormholes_from_room_exits">game.settings.exclude_wormholes_from_room_exits</a>.
       * If set to true or false, will override game settings
       * for this room.
       * @var {Boolean} AdventureJS.Assets.Room#exclude_wormholes_from_room_exits
       * @default true
       */
      this.exclude_wormholes_from_room_exits = null;

      /**
       * Controls whether a list of a room's contents is
       * appended to the room's description.
       * If left to its default seeting of null, will use
       * <a href="/doc/AdventureJS.Settings.html#property_print_room_contents">game.settings.print_exits</a>.
       * If set to true or false, will override game settings
       * for this room.
       * @var {Boolean} AdventureJS.Assets.Room#print_room_contents
       * @default true
       */
      this.print_room_contents = null;

      /**
       * If set true, when player tries to go in a direction that hasn't
       * got an {@link AdventureJS.Assets.Exit|Exit},
       * we'll print the current room's Exits as a reminder
       * of what Exits are available.
       * <br><br>
       * Setting this to true or false per room will override global
       * {@link AdventureJS.Settings|Settings} for that room.
       * @var {Boolean} AdventureJS.Assets.Room#when_travel_fails_list_exits
       * @default true
       */
      this.when_travel_fails_list_exits = null;

      /**
       * If set true,
       * {@link AdventureJS.Assets.Exit|Exit} descriptions can include
       * the name of the {@link AdventureJS.Assets.Room|Room} that the
       * Exit leads to. (The logic for this may also consider other
       * conditions such as whether the player knows about the
       * other Room.)
       * <br><br>
       * Setting this to true or false per room will override global
       * {@link AdventureJS.Settings|Settings} for that room.
       * @var {Boolean} AdventureJS.Assets.Room#print_room_names_in_exits
       * @default null
       */
      this.print_room_names_in_exits = null;

      /**
       * If set true,
       * {@link AdventureJS.Assets.Exit|Exit} descriptions can include
       * the name of the {@link AdventureJS.Assets.Room|Room} that the
       * Exit leads to once player knows about the destination Room.
       * Generally player must visit a room to know about it, but
       * there can be exceptions.
       * <br><br>
       * Setting this to true or false per room will override global
       * {@link AdventureJS.Settings|Settings} for that room.
       * @var {Boolean} AdventureJS.Assets.Room#print_room_names_in_exits_if_known
       * @default null
       */
      this.print_room_names_in_exits_if_known = null;

      /**
       * If set true,
       * {@link AdventureJS.Assets.Exit|Exit} descriptions can include
       * the name of the {@link AdventureJS.Assets.Room|Room} that the
       * Exit leads to once player has used the Exit.
       * <br><br>
       * Setting this to true or false per room will override global
       * {@link AdventureJS.Settings|Settings} for that room.
       * @var {Boolean} AdventureJS.Assets.Room#print_room_names_in_exits_if_used
       * @default null
       */
      this.print_room_names_in_exits_if_used = null;

      this.dimensions.size = 1;

      this.aspects.in = new AdventureJS.Helpers.Aspect(
        "in",
        this.game_name,
        this.id
      ).set({
        know_contents_with_parent: true,
        see_contents_with_parent: true,
      });

      // @TODO this should not be automatically assigned
      // should only be defined when needed
      this.aspects.in.vessel = new AdventureJS.Helpers.Vessel(
        "in",
        this.game_name,
        this.id
      ).set({
        maxvolume: Infinity,
        know_contents_with_parent: true,
        is: { reservoir: true },
        // enabled: false,
      });

      this.aspects.in.nest = new AdventureJS.Helpers.Nest(
        "in",
        this.game_name,
        this.id
      ).set({
        preposition: "in",
        posture: "stand",
        initial_position: { x: 0, y: 0, z: 0 },
        can: {
          // locomotion
          bounce: true,
          climb: true,
          crawl: true,
          go: true,
          get: true,
          hop: true,
          jump: true,
          ride: true,
          run: true,
          walk: true,

          // travel
          enter: true,
          exit: true,
          exit_from_height: true,
          scale: true,
          traverse: true,

          // posture
          cling: true,
          grip: true,
          hang: true,
          kneel: true,
          lie: true,
          sit: true,
          stand: true,

          // sensory
          hear: true,
          see: true,
        },
      });

      this.aspects.attached = new AdventureJS.Helpers.Aspect(
        "attached",
        this.game_name,
        this.id
      ).set({ know_contents_with_parent: true });

      this.descriptions.listen = `{We} hear the room tone. `;
      this.descriptions.dark = function () {
        return (
          A.FX.getSAF.call(this.game, this.game.settings.responses.dark_room) ||
          `It's too dark to see. `
        );
      };

      this.location_unneccessary = true;

      /**
       * If player types "exit" and the current room has its
       * default_exit set, that will be used ahead of any other
       * direction choosing logic. Value should be a string
       * matching a valid exit, such as "east" or "up".
       * @var {String} AdventureJS.Assets.Room#default_exit
       * @default ""
       */
      this.default_exit = "";

      /**
       * If player types "enter" and the current room has its
       * default_entrance set, that will be used ahead of any other
       * direction choosing logic. Value should be a string
       * matching a valid exit, such as "in" or "down".
       * @var {String} AdventureJS.Assets.Room#default_entrance
       * @default ""
       */
      this.default_entrance = "";
    }

    // @TODO I don't remember why I set this
    // it only returns things IN rooms and
    // excludes things ATTACHED
    // returns array of strings
    // getAllContents() {
    //   return [...this.aspects.in.contents];
    // }

    set darkname(value) {
      this._darkname = value;
    }

    get darkname() {
      if (
        ("string" === typeof this._darkname && this._darkname) ||
        "function" === typeof this._darkname
      ) {
        return A.FX.getSAF.call(this.game, this._darkname, this);
      } else if (
        ("string" === typeof this.game.settings.dark_room_name &&
          this.game.settings.dark_room_name) ||
        "function" === typeof this.game.settings.dark_room_name
      ) {
        return A.FX.getSAF.call(
          this.game,
          this.game.settings.dark_room_name,
          this
        );
      } else {
        return this.name;
      }
    }

    set darksituation(value) {
      this._darksituation = value;
    }

    get darksituation() {
      if (
        ("string" === typeof this._darksituation && this._darksituation) ||
        "function" === typeof this._darksituation
      ) {
        return A.FX.getSAF.call(this.game, this._darksituation, this);
      } else if (
        ("string" === typeof this.game.settings.dark_room_situation &&
          this.game.settings.dark_room_situation) ||
        "function" === typeof this.game.settings.dark_room_situation
      ) {
        return A.FX.getSAF.call(
          this.game,
          this.game.settings.dark_room_situation,
          this
        );
      } else {
        return "";
      }
    }

    set name(value) {
      this._name = value;
    }

    /**
     * name returns the name of the class instance.
     * @var {String} AdventureJS.Room#name
     */
    get name() {
      if ("function" === typeof this._name) return this._name();
      if (this.stack && this.stack.use_stack_name) {
        return this.stack.getQuantity() > 1 ? this.plural : this.singular;
      }
      return this._name;
    }

    /**
     * @method AdventureJS.Assets.Room#isDark
     * @memberof AdventureJS.Assets.Room
     */
    isDark() {
      let dark_sources = this.dark_sources;
      if (dark_sources.length) return true;

      // check for light sources
      let light_sources = this.light_sources;
      // @TODO check for light sources enclosed in opaque containers
      if (light_sources.length) return false;

      // otherwise
      return this.is.dark;
    }

    /**
     * @method AdventureJS.Assets.Room#isLit
     * @memberof AdventureJS.Assets.Room
     * @TODO add this method to light sources?
     */
    isLit() {
      return !this.isDark();
    }

    /**
     * Get a list of assets in the room that provide light.
     * @var {String} AdventureJS.Room#light_sources
     */
    get light_sources() {
      return this.findAssetsByProperty("is.light_source");
    }

    /**
     * Get a list of assets in the room that remove light.
     * @var {String} AdventureJS.Room#light_sources
     */
    get dark_sources() {
      return this.findAssetsByProperty("is.dark_source");
    }

    /**
     * Get a list of assets in the room that emit light
     * (whether positive or negative).
     * @var {String} AdventureJS.Room#light_emitters
     */
    get light_emitters() {
      return this.findAssetsByProperty("emits.light");
    }

    /**
     * Room inherits validate from {@link AdventureJS.Assets.Entity|Entity}
     * and adds some additional chunks to handle
     * {@link AdventureJS.Assets.Scenery|Scenery} and
     * {@link AdventureJS.Assets.Exit|Exits}. If the Room's definition includes
     * Scenery or Exits that haven't been defined distinctly, they will be
     * added to a list of deferred_assets to be constructed after the
     * {@link AdventureJS.Game|Game's} main validation/initialization pass.
     * @method AdventureJS.Assets.Room#validate
     * @memberof AdventureJS.Assets.Room
     */
    validate(game) {
      super.validate(game);

      this.zone = A.FX.normalize(this.zone);

      var sceneryCount = Object.keys(this.area_scenery).length;
      if (sceneryCount > 0) {
        var sceneries = Object.keys(this.area_scenery);
        for (var i = 0; i < sceneries.length; i++) {
          const id = sceneries[i];
          const global_id = id.startsWith("global_") ? id : "global_" + id;

          // if (!this.game.getAsset(sceneries[i])) {
          if (!this.game.getAsset(global_id)) {
            var newScenery = {};
            var already_deferred = false;

            newScenery = Object.assign(
              newScenery,
              // this.area_scenery[sceneries[i]]
              this.area_scenery[id]
            );
            // newScenery.name = sceneries[i];
            newScenery.name = id;
            newScenery.class = "Scenery";
            if (newScenery.is?.global) {
              // if it's global, it must be known in order
              // for player to refer to it from anywhere
              newScenery.is.known = true; // ??
            } else {
              // otherwise put it in this room
              newScenery.place = { in: this.id };
            }

            // if it's global, it can be listed in multiple rooms,
            // but we only want to construct it once,
            // and we only want to construct the one that has create:true
            for (var d = 0; d < this.game.deferred_assets.length; d++) {
              // if (sceneries[i] === this.game.deferred_assets[d].name) {
              if (id === this.game.deferred_assets[d].name) {
                if (true === this.game.deferred_assets[d].create) {
                  // created by that other instance
                  already_deferred = true;
                } else if (true === newScenery.create) {
                  // created by this instance
                  this.game.deferred_assets[d] = newScenery;
                }
              }
            }
            if (false === already_deferred) {
              this.game.deferred_assets.push(newScenery);
            }
          }
        }
      }

      // var exit_keys = Object.keys(this.exits);
      // for (var i = 0; i < exit_keys.length; i++) {
      for (const key in this.exits) {
        // const key = exit_keys[i];
        if (typeof this.exits[key] === "function") {
          var newDirection = {
            class: "Exit",
            place: { in: this.name },
            direction: key,
            descriptions: { look: this.exits[key] },
          };
          newDirection.descriptions.look = Object.assign(
            newDirection.descriptions.look,
            this.exits[key]
          );

          this.game.deferred_assets.push(newDirection);

          // erase the intitial function
          delete this.exits[key];
        } else if (typeof this.exits[key] === "string") {
          // at minimum we need location & direction, secondarily destinationName
          // does the string match a Room ID?
          // if not treat it as a description
          var newDirection = {
            class: "Exit",
            descriptions: {},
            place: { in: this.name },
            direction: key,
          };
          var destinationName = this.exits[key];
          var destinationID = A.FX.normalize(destinationName);

          if (
            "undefined" !== typeof this.game.world[destinationID] &&
            this.game.world[destinationID] instanceof AdventureJS.Assets.Room
          ) {
            // exit string matches a Room
            newDirection.destination = destinationName;
          } else {
            // doesn't match a room so treat it as a description
            newDirection.descriptions.look = destinationName;
          }

          // push it to deferred_assets for construction/validation
          // after the initial validation pass
          this.game.deferred_assets.push(newDirection);

          // erase the intitial string
          delete this.exits[key];
        } else if (typeof this.exits[key] === "object") {
          var newDirection = {};
          newDirection = Object.assign(newDirection, this.exits[key]);
          newDirection.class = "Exit";
          newDirection.direction = key;
          newDirection.place = { in: this.id };
          this.game.deferred_assets.push(newDirection);
        }
      } // for( var i = 0; i < directions.length

      return true;
    }

    /**
     * Rooms never have a place/parent, but they get queried as an Entity class.
     * Returns false to cover bases.
     * @memberOf AdventureJS.Assets.Room
     * @method AdventureJS.Assets.Room#getPlaceAssetId
     * @returns {Boolean}
     */
    getPlaceAssetId() {
      return false;
    }
    /**
     * Rooms never have a place/parent, but they get queried as an Entity class.
     * Returns false to cover bases.
     * @memberOf AdventureJS.Assets.Room
     * @method AdventureJS.Assets.Room#getPlaceAsset
     * @returns {Boolean}
     */
    getPlaceAsset() {
      return false;
    }

    /**
     * Rooms never have a place/parent, but they get queried as an Entity class.
     * Returns false to cover bases.
     * @memberOf AdventureJS.Assets.Room
     * @method AdventureJS.Assets.Room#getPlaceAspect
     * @returns {Boolean}
     */
    getPlaceAspect() {
      return false;
    }

    initialize(game) {
      super.initialize(game);

      // add to list of rooms, which we use for "go to room"
      this.game.room_lookup.push(this.id);

      if (this.area_events && this.area_events.array) {
        // ensure that we have use_saf setting
        if ("undefined" === typeof this.area_events.use_saf) {
          this.area_events.use_saf = true;
        }

        // ensure that we have randomize setting
        if ("undefined" === typeof this.area_events.randomize) {
          this.area_events.randomize =
            this.game.settings.randomize_arrays_in_getStringArrayFunction;
        }

        // ensure that we have index
        if ("undefined" === typeof this.area_events.index) {
          this.area_events.index = 0;
        }

        // ensure that we have frequency setting
        if ("undefined" === typeof this.area_events.frequency) {
          this.area_events.frequency = 0;
        }
      }

      return true;
    }

    /**
     * Get this.exits.
     * @memberOf AdventureJS.Assets.Room
     * @method AdventureJS.Assets.Room#getExits
     * @returns {Boolean}
     */
    getExits() {
      return this.exits;
    }

    /**
     * Get a list of directions leaving this room.
     * @memberOf AdventureJS.Assets.Room
     * @method AdventureJS.Assets.Room#getDirections
     * @returns {Boolean}
     */
    getDirections() {
      return Object.keys(this.exits);
    }
  }

  AdventureJS.Assets.Room = Room;
})();