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

  /**
   * @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 PlumbingClasses
   * @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.
   * @ajscomponents SubstanceEmitter, GraduatedController, Drain, Plug
   * @summary Ancestor class for Sinks and Bathtubs.
   * @ajssubstancecontainer in
   * @ajstangiblecontainer in
   * @ajstangiblecontainer attached
   * @ajsdemo PlumbingDemo, BasicSink, IntegratedSink, BasicBathtub, IntegratedBathtub, Scorecard
   * @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#components|components}</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">components</code>, see <a href="/doc/Tangibles_Components.html">Components</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);

      this.unsetDOVs(["get", "take", "give", "put"]);
      this.setDOVs([
        "fill",
        "empty",
        "drink",
        "pour",
        // { turn: { with_nothing: true } },
        { turnOn: { with_nothing: true } },
        { turnOff: { with_nothing: true } },
      ]);

      this.default_aspect = "in";
      this.aspects.attached = new adventurejs.Aspect(
        "attached",
        this.game_name,
        this.id
      ).set({
        list_contents_in_examine: false,
        list_contents_in_room: false,
        know_contents_with_parent: true,
        see_contents_with_parent: true,
        player_can_add_assets_to_contents: false,
        player_can_remove_assets_from_contents: false,
      });

      this.linkableClasses = {
        Faucet: function (object) {
          this.linked_components.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.linked_components.GraduatedControllers
          ) {
            this.linked_components.GraduatedControllers = [];
          }
          this.linked_components.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.linked_components.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.linked_components.Plugs) {
            this.linked_components.Plugs = [];
          }
          this.linked_components.Plugs.push(object.id);
        },
      };

      this.linkComponents = function Drainable_linkComponents() {
        var drain;

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

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

        // link plug(s) to drain
        if ("undefined" !== typeof this.linked_components.Plugs) {
          this.linked_components.Plugs.forEach(function (id) {
            var plug = this.game.getAsset(id);

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

            // plug is indirect object, should have drain as direct connection
            plug.setVerbWithAsset("plug", drain, "iov");
          }, this);
        }
      }; // linkComponents

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

        // does this drainable have controllers?
        if (direct_object.linked_components?.GraduatedControllers?.length) {
          var controllers =
            direct_object.linked_components.GraduatedControllers;
          let controller;

          // does it have more than one controller?
          if (controllers.length === 1) {
            controller = this.game.getAsset(controllers[0]);
          }
          if (controllers.length > 1) {
            for (let n in controllers) {
              let c = this.game.getAsset(controllers[n]);
              if (c.current_position === 0) {
                controller = c;
                break;
                // can_turn_on = true;
              }
            }
          }
          if (!controller || controller.current_position !== 0) {
            this.game.debug(
              `Dxxxx | ${this.name}.js | all controllers are on `
            );
            msg += `${direct_object.Articlename} is already on. `;
            this.handleFailure(msg);
            return false;
          }
          // var rand = Math.floor(Math.random() * controllers.length);
          // var controller = this.game.getAsset(controllers[rand]);
          input.setAsset(1, controller);
          input.allow_circular_verb = true;
          return this.game.dictionary.doVerb("turnOn");
        }

        // does this drainable have a faucet?
        else if (direct_object.linked_components?.Faucet) {
          var faucet = this.game.getAsset(
            direct_object.linked_components.Faucet
          );
          input.setAsset(1, faucet);
          input.allow_circular_verb = true;
          return this.game.dictionary.doVerb("turnOn");
        }

        // no controllers or faucets so just let the verb act on it
        else {
          this.game.debug(
            `D1847 | Drainable.js | ${direct_object.id} has no GraduatedControllers or Faucet`
          );

          // msg += `{We} can't turn on ${direct_object.articlename}. `;
          // this.game.dictionary.verbs[params.verb].handleFailure(msg);
          // return null;
        }
      };

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

        // does this drainable have controllers?
        if (direct_object.linked_components?.GraduatedControllers?.length) {
          var controllers =
            direct_object.linked_components.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("turnOff");
            }
          }
          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;
        }

        // does this drainable have a faucet(s)?
        else if (direct_object.linked_components?.Faucet) {
          var faucet = this.game.getAsset(
            direct_object.linked_components.Faucet
          );
          input.setAsset(1, faucet);
          input.allow_circular_verb = true;
          return this.game.dictionary.doVerb("turnOff");
        }

        // no controllers or faucets so just let the verb act on it
        else {
          this.game.debug(
            `D1846 | Drainable.js | ${direct_object.id} has no GraduatedControllers or Faucet`
          );

          // msg += `{We} can't turn off ${direct_object.articlename}. `;
          // this.game.dictionary.verbs[params.verb].handleFailure(msg);
          // return null;
        }
      };
    }
  }
  adventurejs.Drainable = Drainable;
})();