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

  /**
   * @ajspath adventurejs.Atom.Asset.Matter.Tangible.Thing.Drain
   * @augments adventurejs.Thing
   * @class adventurejs.Drain
   * @ajsconstruct MyGame.createAsset({ "class":"Drain", "name":"foo", [...] })
   * @ajsconstructedby adventurejs.Game#createAsset
   * @ajsnavheading BathroomClasses
   * @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.
   * @ajspartof Sink
   * @ajsparts Plug
   * @summary Roto Rooter, that's the name, to send your troubles down the drain.
   * @tutorial Substances_Vessels
   * @tutorial Tangibles_LinkedAssets
   * @ajssubstancecontainer in
   * @ajstangiblecontainer in
   * @todo Implement parts:Plug separately for Drain.
   * @classdesc
   * <p>
   * <strong>Drain</strong> is a subclass of the simple generic
   * {@link adventurejs.Thing|Thing}. What makes it unique is its
   * container properties. Drain has a
   * {@link adventurejs.Aspect|Aspect} with a
   * {@link adventurejs.Vessel|Vessel}.
   * That part is typical - all Vessels reside inside
   * Aspects – what makes Drain unique is that its
   * Vessel has infinite capacity, and it can be linked
   * with another Vessel such as a
   * {@link adventurejs.Sink|Sink}
   * with a limited capacity, so
   * that when the Drain is plugged, the Sink fills, and when
   * Drain is unplugged, the Sink empties into the Drain.
   * </p>
   * <p>
   * A Drain can exist on its own, or a Drain can be
   * attached to a
   * {@link adventurejs.Sink|Sink} or
   * {@link adventurejs.Bathtub|Bathtub} or other
   * {@link adventurejs.Drainable|Drainable} subclass which itself
   * has a Vessel, such that the Drainable drains
   * via the Drain. A Drain can be plugged by a
   * {@link adventurejs.Plug|Plug} to allow the
   * linked Drainable to hold liquid.
   * </p>
   * <p>
   * Links between a Drain and Plug
   * can be created automatically through the use of the
   * <code class="property">parts</code> property. Note that
   * <code class="property">parts</code>
   * is a special convenience property that only pertains to some
   * classes with inherent code for making links.
   * To learn more about the <code class="property">parts</code>
   * property, see <a href="/doc/Tangibles_LinkedAssets.html">Linked Assets</a>.
   * </p>
   * <p>
   * Following is an example of a Drain with a
   * related Plug.
   * To see an example of a more complete
   * arrangement with a Drainable, Faucet, Handles, Drain
   * and Plug, see the {@link adventurejs.Sink|Sink class}.
   * </p>
   * <h3 class="examples">Example:</h3>
   * <pre class="display"><code class="language-javascript">MyGame.createAsset({
   *   class: "Drain",
   *   name: "dank drain",
   *   descriptions: { look: "A dark drain. ", },
   *   parts: ["plug"],
   * });
   *
   * MyGame.createAsset({
   *   class: "Plug",
   *   name: "plug",
   *   synonyms: "plug",
   *   descriptions: { look: "A drain plug. ", },
   * });
   * </code></pre>
   **/
  class Drain extends adventurejs.Thing {
    constructor(name, game_name) {
      super(name, game_name);
      this.class = "Drain";

      this.singlePluralPairs = [["drain", "drains"]];

      this.is.listed_in_parent = false;

      this.descriptions.look = "It's a drain.";

      this.setDOVs(["open", "close", "plug"]);
      this.setDOV({ unplug: { with_nothing: true } });

      this.setIOVs(["pour", "fill", "put", "throw"]);
      this.can.be_poured_into = true;
      this.can.be_filled_from = false;

      this.aspects.in = new adventurejs.Aspect("in", this.game_name).set({
        parent_id: this.id,
        list_in_examine: true,
        know_with_parent: true,
        list_in_room: false,
        contents_limits: {
          height: 0.1,
          width: 0.1,
          depth: 0.1,
          count: 1,
        },
      });

      this.aspects.in.vessel = new adventurejs.Vessel(
        "in",
        game_name,
        this.id
      ).set({
        maxvolume: Infinity,
        is_drain: true,
      });

      this.registerableClasses = {
        Plug: function (object) {
          // this plugs push plug // can have multiple plugs
          if ("undefined" === typeof this.registered_parts.Plugs) {
            this.registered_parts.Plugs = [];
          }
          this.registered_parts.Plugs.push(object.id);
        },
      };

      this.linkRegisteredParts = function Drainable_linkRegisteredParts() {
        // link plugs to drain
        if ("undefined" !== typeof this.registered_parts.Plugs) {
          var drain = this; //.game.getAsset(this.registered_parts.Drain);
          this.registered_parts.Plugs.forEach(function (id) {
            var plug = this.game.getAsset(id);
            // console.warn("Drain linkRegisteredParts plug", plug);
            drain.setVerbWithAsset("plug", plug, "iov");
            plug.setVerbWithAsset("plug", drain, "dov");
          }, this);
        }
      };
    }

    // override onMoveThatToThis inherited from Tangible
    // to check if asset is plug and close drain
    onMoveThatToThis(asset, where) {
      var results = super.onMoveThatToThis(asset, where);
      if ("undefined" !== typeof results) return results;

      if (this.allowVerbWithAsset("plug", asset, "dov")) {
        console.warn("DRAIN allowVerbWithAsset");
        this.game.dictionary.verbs.plug.setVerbConnection(this, asset);
        this.is.plugged = true;
      }

      return;
    }

    // override onRemoveThatFromThis inherited from Tangible
    // to check if asset is plug and open drain
    onRemoveThatFromThis(asset) {
      var results = super.onRemoveThatFromThis(asset);
      if ("undefined" !== typeof results) return results;

      if (this.isConnectedToAsset("plug", asset, "to_iov")) {
        this.game.dictionary.verbs.plug.unsetVerbConnection(this, asset);

        var parent = this.getPlaceAsset();

        if (parent.aspects.in.vessel.getVolume() > 0) {
          var substance = this.game.getAsset(
            parent.aspects.in.vessel.substance_id
          );
          parent.aspects.in.vessel.empty();
          var msg = `${substance.Name} drains out of ${parent.articlename}. `;
          this.game.getInput().appendOutput(msg);
        }
      }
      return;
    }
  }
  adventurejs.Drain = Drain;
})();