Pre-release
Adventure.js Docs Downloads
Score: 0 Moves: 0
// Atom.js
(function () {
  /*global adventurejs A*/
  "use strict";
  /**
   * @class adventurejs.Atom
   * @ajsinternal
   * @ajsnavheading FrameworkReference
   * @param {String} game_name A reference back to the top level
   * game object, by way of window[game_name]. Done this way
   * rather than using an object reference in order to avoid circular
   * references, because they're difficult to parse into JSON, the
   * method that's used for saving/restoring game data.
   * @param {String} name The name of the object in the game world,
   * ie "brass lantern". The name is also used to create the object's
   * <a href="#id">id</a> by means of removing periods and spaces and
   * converting to lowercase.
   * @summary Experimental class made with Javascript ES6 class keyword.
   * @classdesc
   * <strong>Atom</strong> is a bedrock class that is used as the
   * prime ancestor for all in-game classes. It defines several
   * important base properties including <a href="#name">name</a>,
   * <a href="#class">class</a>, <a href="#id">id</a>,
   * and the <a href="#set">set</a> method.
   * Authors should not need to instantiate or subclass Atom.
   * Start with the {@link adventurejs.Tangible|Tangible} class
   * to create new physical Assets, or the
   * {@link adventurejs.Intangible|Intangible} class to create
   * new abstract Assets.
   */
  class Atom {
    constructor(name, game_name) {
      /**
       * game_name stores the name of
       * the current game instance as scoped to window.
       * (By default, we use "MyGame", but you can use
       * any name.) In order
       * to refer to the game object, we use window[this.game_name].
       * We store a string instead of the object itself in order to
       * avoid problems caused by circular references during
       * JSON encoding, which is used extensively for managing game
       * state and saved games.
       * @alias game_name
       * @type {string}
       * @memberof adventurejs.Atom
       */
      this.game_name = game_name;

      /**
       * Class identifier to be provided in the asset definition.
       * All game objects start as generic objects that get passed to
       * {@link adventurejs.Game#createAsset|createAsset},
       * which uses an object's class field to specify
       * a class constructor.
       * @alias class
       * @type {string}
       * @memberof adventurejs.Atom
       */
      this.class = "Atom";

      // Name should only be undefined when restoring from JSON.
      if ("undefined" !== typeof name) {
        /**
         * Class identifier to be provided in the asset definition.
         * All game objects start as generic objects that get passed to
         * {@link adventurejs.Game#createAsset|createAsset},
         * which uses an object's class field to specify
         * a class constructor.
         * @alias name
         * @type {string}
         * @memberof adventurejs.Atom
         */
        this.name = name;

        if (this.name) {
          /**
           * A unique ID for the game asset, based on the object name
           * provided in the asset definition.
           * @alias id
           * @type {string}
           * @memberof adventurejs.Atom
           */
          this.id = A.serialize(name);
        }

        /**
         * A unique numerical ID for the game asset. Currently unused but
         * included as a potential alternative to id.
         * @alias UID
         * @type {string}
         * @memberof adventurejs.Atom
         */
        this.UID = adventurejs.UID.get();
      }
    }

    /**
     * Name returns the name of the class instance
     * with the first character uppercased.
     * @var {String} adventurejs.Atom#Name
     */
    get Name() {
      return A.propercase(this.name);
    }

    get self() {
      return this;
    }

    /**
     * Returns the top level game object. Use <code class="property">this.game</code>.
     * @var {Getter} adventurejs.Atom#game
     * @returns {adventurejs.Game}
     */
    get game() {
      return window[this.game_name] || false;
    }

    /**
     * Provides a chainable shortcut method for setting a number of properties on the instance.
     * @method adventurejs.Atom#set
     * @memberOf adventurejs.Atom
     * @param {Object} props A generic object containing properties to copy to the Object instance.
     * @returns {Object} Returns the instance the method is called on (useful for chaining calls.)
     * @chainable
     */
    set(props) {
      return A.deepSet.call(this.game, props, this);
    }

    /**
     * A method to test whether the Atom is an instance of a given class.
     * @method adventurejs.Atom#hasClass
     * @memberOf adventurejs.Atom
     * @param {String} prop Name of the class to test for.
     * @returns {Boolean}
     */
    hasClass(classname) {
      if (!classname || "string" !== typeof classname) return false;
      if (!adventurejs[classname]) {
        // classes have leading capitalization so we'll make an effort
        // to see if that's the problem
        classname = A.propercase(classname);
      }
      if (!adventurejs[classname]) {
        return false;
      }
      return this instanceof adventurejs[classname];
    }

    /**
     * <strong>getInheritance</strong> is a utility method to get
     * an asset's inheritance chain. Returns a list of class names
     * from high to low.
     * @method adventurejs.Atom#getInheritance
     * @memberOf adventurejs.Atom
     * @returns {Array}
     */
    getInheritance() {
      var proto = ".__proto__";
      var chain = "this" + proto;
      var classlist = [];
      var classname;
      while (classname !== "Atom") {
        classname = eval(chain).constructor.name;
        classlist.push(classname);
        chain += proto;
      }
      return classlist;
    }
  }

  adventurejs.Atom = Atom;
})();