Pre-release
Adventure.js Docs Downloads
Score: 0 Moves: 0
// Drainable.js
(function () {
  /*global adventurejs A*/
  "use strict";

  /**
   * @ajspath adventurejs.Atom.Asset.Matter.Tangible.Thing.Container.LiquidContainer.Drainable
   * @augments adventurejs.LiquidContainer
   * @class adventurejs.Drainable
   * @ajsconstruct MyGame.createAsset({ "class":"Drainable", "name":"foo", [...] })
   * @ajsconstructedby adventurejs.Game#createAsset
   * @ajsnavheading MiscAssetClasses
   * @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.
   * @ajsparts Faucet, GraduatedController, Drain, Plug
   * @summary Ancestor class for Sinks and Bathtubs.
   * @ajssubstancecontainer in
   * @ajstangiblecontainer in
   * @ajstangiblecontainer attached
   * @classdesc
   * <p>
   * <strong>Drainable</strong> is a subsclass of
   * {@link adventurejs.Container|Container} /
   * {@link adventurejs.LiquidContainer|LiquidContainer},
   * and the ancestor class for
   * {@link adventurejs.Sink|Sink} and
   * {@link adventurejs.Bathtub|Bathtub} and other basins.
   * You wouldn't construct a Drainable directly, but you can
   * subclass it to create new types of Drainables.
   * </p>
   * <p>
   * Drainables can be easily linked with
   * {@link adventurejs.Faucet|Faucets},
   * {@link adventurejs.Handle|Handles},
   * {@link adventurejs.Drain|Drains} and
   * {@link adventurejs.Plug|Plugs}
   * through the use of the
   * <code class="property">{@link adventurejs.Tangible#parts|parts}</code>
   * property,
   * a special convenience property that can be used to link some
   * {@link adventurejs.Asset|Asset} classes to other Asset classes.
   * To learn more about which classes can be linked with
   * <code class="property">parts</code>, see <a href="/doc/Tangibles_LinkedAssets.html">Linked Assets</a>.
   * </p>
   **/
  class Drainable extends adventurejs.LiquidContainer {
    constructor(name, game_name) {
      super(name, game_name);
      this.class = "Drainable";

      this.noun = "drainable";
      this.plural = "drainables";
      this.singlePluralPairs = [["drainable", "drainables"]];

      this.is = new adventurejs.Drainable_Is("is", this.game_name, this.id).set(
        {
          parent_id: this.id,
        }
      );

      this.unsetDOVs(["take", "give", "put"]);
      this.setDOVs(["fill", "empty", "turn", "drink", "pour"]);

      this.default_aspect = "in";
      this.aspects.attached = new adventurejs.Aspect(
        "attached",
        this.game_name
      ).set({
        parent_id: this.id,
        list_in_examine: false,
        list_in_room: false,
        player_can_add_assets_to_contents: false,
        player_can_remove_assets_from_contents: false,
      });

      this.registerableClasses = {
        Faucet: function (object) {
          this.registered_parts.Faucet = object.id;
          // this faucet = faucet
          // faucet sink = this
          // what else does a sink need to know about a faucet?
          // faucet is attached to sink

          object.setPlace("attached", this.id);
          object.aspects.in.vessel.target_id = this.id;
        },

        GraduatedController: function (object) {
          // this faucets push faucet
          // can have multiple handles
          // faucet sink = this
          // where do we ask about multiple inputs mixing?
          // is each handle worth a fraction of max_volume_of_flow_per_turn?
          if (
            "undefined" === typeof this.registered_parts.GraduatedControllers
          ) {
            this.registered_parts.GraduatedControllers = [];
          }
          this.registered_parts.GraduatedControllers.push(object.id);
          // handles are attached to sink... but don't need to be? shower handles/
          object.control_target_id = this.id;
          object.setPlace("attached", this.id);
        },

        Drain: function (object) {
          this.registered_parts.Drain = object.id;
          // this drain = drain
          // drain sink = this
          // what else does a sink need to know about a drain?
          // drain is attached to sink

          object.setPlace("attached", this.id);
        },

        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() {
        var drain;

        // link handles to faucet
        if (
          "undefined" !== typeof this.registered_parts.Faucet &&
          "undefined" !== typeof this.registered_parts.GraduatedControllers
        ) {
          var faucet = this.game.getAsset(this.registered_parts.Faucet);
          if (
            "undefined" === typeof faucet.registered_parts.GraduatedControllers
          ) {
            faucet.registered_parts.GraduatedControllers = [];
          }
          this.registered_parts.GraduatedControllers.forEach(function (id) {
            this.game.getAsset(id).control_target_id =
              this.registered_parts.Faucet;
            faucet.registered_parts.GraduatedControllers.push(id);
          }, this);
        }

        // link drain to sink
        if ("undefined" !== typeof this.registered_parts.Drain) {
          drain = this.game.getAsset(this.registered_parts.Drain);
          this.aspects.in.vessel.drain_id = drain.id;
        } else {
          drain = this;
        }

        // link plugs to drain
        if ("undefined" !== typeof this.registered_parts.Plugs) {
          //console.warn('drain',drain);
          this.registered_parts.Plugs.forEach(function (id) {
            var plug = this.game.getAsset(id);
            //console.warn('Drainable linkRegisteredParts plug',plug);

            // plug sink with plug
            // need to add verb connections

            drain.DOVsetWithAsset("plug", plug);
            // drain is direct object, should have plug as indirect connection

            // plug is indirect object, should have drain as direct connection
            plug.IOVsetWithAsset("plug", drain);

            // @TODO PLUGCHECK
          }, this);
        }
      }; // linkRegisteredParts

      this.dov.turn.doAfterTry = function (params) {
        var input = this.game.getInput();
        var direct_object = input.getAsset(1);
        var direct_preposition = input.getPreposition(1);

        // sentence structure: verb preposition noun
        if (input.hasStructure("verb preposition noun")) {
          if (direct_preposition === "on") return this.turnOn_doAfterTry();
          if (direct_preposition === "off") return this.turnOff_doAfterTry();
        } // verb preposition noun
      };

      this.turnOn_doAfterTry = function (params) {
        var input = this.game.getInput();
        var direct_object = input.getAsset(1);
        var msg = "";

        // nothing with which to turn the faucet on
        if (
          "undefined" ===
            typeof direct_object.registered_parts.GraduatedControllers ||
          0 === direct_object.registered_parts.GraduatedControllers.length
        ) {
          this.game.debug(
            `F1847 | Drainable.js | ${direct_object.id} has no GraduatedControllers `
          );
          msg += `$(We) can't turn on ${direct_object.articlename}. `;
          this.game.dictionary.verbs[params.verb].handleFailure(msg);
          return null;
        }
        // else if( 1 === direct_object.registered_parts.GraduatedControllers.length )
        else {
          var controllers = direct_object.registered_parts.GraduatedControllers;
          var controller_count = controllers.length;
          var rand = Math.floor(Math.random() * controller_count);
          var controller = this.game.getAsset(controllers[rand]);
          input.setAsset(1, controller);
          input.allow_circular_verb = true;
          this.game.dictionary.doVerb("turn");
          return null;
        }
      };

      this.turnOff_doAfterTry = function (params) {
        var input = this.game.getInput();
        var direct_object = input.getAsset(1);

        // nothing with which to turn the faucet off
        if (
          "undefined" ===
          typeof direct_object.registered_parts.GraduatedControllers
        ) {
          this.game.debug(
            `F1846 | Drainable.js | ${direct_object.id} has no GraduatedControllers `
          );
          msg += `$(We) can't turn off ${direct_object.articlename}. `;
          this.game.dictionary.verbs[params.verb].handleFailure(msg);
          return null;
        }

        var controllers = direct_object.registered_parts.GraduatedControllers;
        var controller_count = controllers.length;
        var controllers_to_turn_off_count = 0;
        for (var c = 0; c < controller_count; c++) {
          var controller = this.game.getAsset(controllers[c]);
          if (0 < controller.current_position) {
            controllers_to_turn_off_count++;
            input.setAsset(1, controller);
            input.allow_circular_verb = true;
            this.game.dictionary.doVerb("turn");
          }
        }
        if (0 === controllers_to_turn_off_count) {
          var msg = direct_object.Articlename + " isn't on. ";
          this.game.dictionary.verbs[params.verb].handleFailure(msg);
        }
        return null;
      };
    }
  }
  adventurejs.Drainable = Drainable;
})();