Pre-release
Adventure.js Docs Downloads
Score: 0 Moves: 0
// drink.js

(function () {
  /*global adventurejs A*/
  "use strict";

  /**
   * @augments {adventurejs.Verb}
   * @class drink
   * @ajsnode game.dictionary.verbs.drink
   * @ajsconstruct MyGame.createVerb({ "name": "drink", [...] });
   * @ajsconstructedby adventurejs.Dictionary#createVerb
   * @hideconstructor
   * @ajsinstanceof Verb
   * @ajsnavheading ConsumptionVerbs
   * @summary Verb meaning drink substance.
   * @todo finish writing
   * @tutorial Scripting_VerbSubscriptions
   * @tutorial Verbs_VerbAnatomy
   * @tutorial Verbs_VerbProcess
   * @tutorial Verbs_ModifyVerbs
   * @tutorial Verbs_WriteVerbs
   * @classdesc
   * <pre class="display border outline">
   * <span class="input">&gt; drink milk</span>
   * You drink milk from the carton. It does a body good.
   * </pre>
   * <p>
   * <strong>Drink</strong> a {@link adventurejs.Substance|Substance}
   * {@link adventurejs.Asset|Asset}.
   * Requires that a quantity of the Substance be present and reachable.
   * Parser will search for the specified Substance among available
   * Assets.
   * </p>
   * @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
   */
  A.Preverbs.drink = {
    name: "drink",
    prettyname: "drink",
    past_tense: "drank",
    synonyms: ["drink", "sip"],

    /**
     * @ajsverbstructures
     * @memberof drink
     */
    accepts_structures: [
      "verb noun",
      "verb preposition noun",
      "verb noun preposition noun",
    ],

    /**
     * @memberof drink
     * @ajsverbphrase
     * phrase1:
     * {
     *   accepts_noun:true,
     *   requires_noun:true,
     *   noun_must_be:
     *   {
     *     known: true,
     *     matter: true,
     *     present_if_tangible: true,
     *     reachable_if_tangible: true,
     *   },
     *   accepts_preposition: true,
     *   accepts_these_prepositions: ["from"],
     * },
     */
    phrase1: {
      accepts_noun: true,
      requires_noun: true,
      noun_must_be: {
        known: true,
        matter: true,
        present_if_tangible: true,
        reachable_if_tangible: true,
      },
      accepts_preposition: true,
      accepts_these_prepositions: ["from"],
    },

    /**
     * @memberof drink
     * @ajsverbphrase
     * phrase2:
     * {
     *   accepts_noun:true,
     *   noun_must_be:
     *   {
     *     known: true,
     *     tangible: true,
     *     present: true,
     *     visible: true,
     *     reachable: true,
     *   },
     *   accepts_preposition:true,
     *   requires_preposition: true,
     *   accepts_these_prepositions: [ "from" ],
     * },
     */
    phrase2: {
      accepts_noun: true,
      noun_must_be: {
        known: true,
        tangible: true,
        present: true,
        visible: true,
        reachable: true,
      },
      accepts_preposition: true,
      requires_preposition: true,
      accepts_these_prepositions: ["from"],
    },

    /**
     * @memberof drink
     * @ajsverbparams
     * with_params: {},
     */
    with_params: {},

    doTry: function () {
      var input = this.game.getInput();
      var player = this.game.getPlayer();
      var direct_object = input.getAsset(1);
      var direct_preposition = input.getPreposition(1);
      var indirect_object = input.getAsset(2);
      var indirect_preposition = input.getPreposition(2);
      var currentRoom = this.game.getCurrentRoom();
      var containers;
      var msg = "";
      var results, hook;

      var find_container_for_direct_object = false;
      var find_substance_for_direct_object = false;

      // parsed sentence structure: verb
      if (input.hasStructure("verb")) {
      }

      // parsed sentence structure: verb noun
      if (input.hasStructure("verb noun")) {
      } // verb noun

      if (input.hasStructure("verb preposition noun")) {
      }

      // has player entered "drink asset"?
      if (
        input.hasStructure("verb noun") ||
        input.hasStructure("verb preposition noun")
      ) {
        // is asset a substance? > get container
        if (direct_object instanceof adventurejs.Substance) {
          find_container_for_direct_object = true;
        } else if (direct_object.doesContainAnySubstance()) {
          find_substance_for_direct_object = true; // check open / reachable etc
        } else if (direct_object.canContainAnySubstance()) {
          this.game.debug(
            `F1575 | ${this.name}.js | ${direct_object.id} is empty `,
          );
          msg += `${direct_object.Articlename} is empty. `;
          this.handleFailure(msg);
          return null;
        } else if (direct_object.isDOV("drink")) {
          // is player carrying the thing?
          if (direct_object.isDOV("take") && !direct_object.isIn(player)) {
            this.game.debug(
              `F1748 | ${this.name}.js | ${direct_object.id} is not in player `,
            );
            msg += `$(We're) not carrying ${direct_object.articlename}. `;
            this.handleFailure(msg);
            return null;
          }

          // special handling for things that are not substance containers
          // but which can be drunk, as in a case like "drink potion"
          // where potion asset responds directly to drink
          input.verb_params.can_be_drunk = true;
          return true;
        } else {
          this.game.debug(
            `F1171 | ${this.name}.js | ${direct_object.id}.dov.drink.enabled is false `,
          );
          msg += `${direct_object.Articlename} can't be drunk from. `;
          this.handleFailure(msg);
          return null;
        }
      } // verb noun

      // player input "drink substance" and we need to infer container
      if (find_container_for_direct_object) {
        containers = this.game.findSubstanceContainers(direct_object.id, [
          "Present",
          "Known",
          "Visible",
          "Reachable",
        ]);
        switch (containers.length) {
          case 0:
            this.game.debug(`F1576 | ${this.name}.js | no containers found `);
            msg += `There's no ${direct_object.name} available. `;
            this.handleFailure(msg);
            return null;
          case 1:
            // set indirect object to the container
            // ie "drink water" becomes "drink water from bowl"
            indirect_object = this.game.getAsset(containers[0]);
            input.setAsset(2, indirect_object);
            input.setPreposition(2, "from");
            input.setAssumed(2, true);
            input.setStructure("verb noun preposition noun");
            break;
          default:
            var asset, room;
            for (var i = 0; i < containers.length; i++) {
              asset = this.game.getAsset(containers[i]);
              if (asset.id === currentRoom.id) {
                room = true;
                break;
              }
            }
            // if room is among multiple sources, always prefer room
            // meant for environmental substances, like standing by a lake
            if (room) {
              // set indirect object to the room
              // ie "drink water" becomes "drink water from room"
              indirect_object = asset;
              input.setAsset(2, indirect_object);
              input.setPreposition(2, "from");
              input.setAssumed(2, true);
              input.verb_params.drink_from_room = true;
              input.setStructure("verb noun preposition noun");
              break;
            } else {
              // disambiguate - set parsedNoun.matches for next turn
              this.game.debug(
                `F1578 | ${this.name}.js | multiple containers found, disambiguate `,
              );
              // set preposition to "from" for disambiguation
              // because we're asking player to choose a container
              input.setPreposition(1, "from");
              // save containers back to input for next turn disambiguation
              input.setParsedNounMatchesQualified(1, containers);
              this.game.parser.printNounDisambiguation({
                parsedNoun: input.getParsedNoun(1),
                nounIndex: 1,
              });
              return null;
            }
        } // switch
      } // find_container_for_direct_object

      // player input "drink container" and we need to infer substance
      if (find_substance_for_direct_object) {
        indirect_object = direct_object;
        direct_object = this.game.getAsset(
          indirect_object.getAnySubstanceThisContains(),
        );
        input.setAsset(1, direct_object);
        input.setPreposition(1, "");
        input.setAsset(2, indirect_object);
        input.setPreposition(2, "from");
        input.setStructure("verb noun preposition noun");
      } // find_substance_for_direct_object

      // now we can get into verb noun preposition noun
      if (input.hasStructure("verb noun preposition noun")) {
        // is substance unpotable? for instance could be sand
        if (!direct_object.isDOV("drink")) {
          this.game.debug(
            `F1577 | ${this.name}.js | ${direct_object.id}.dov.drink.enabled is false `,
          );
          msg += `$(We) can't drink ${direct_object.name}. `;
          this.handleFailure(msg);
          return null;
        }

        // can indirect object contain substance?
        if (!indirect_object.canContainAnySubstance()) {
          this.game.debug(
            `F1582 | ${this.name}.js | ${indirect_object.id} has no substance container `,
          );
          msg += `${indirect_object.Articlename} can't be drunk from. `;
          this.handleFailure(msg);
          return null;
        }

        // DOES indirect object contain substance?
        if (!indirect_object.doesContainAnySubstance()) {
          if (indirect_object instanceof adventurejs.SubstanceEmitter) {
            this.game.debug(
              `F1580 | ${this.name}.js | "+${indirect_object.id}+" is class SubstanceEmitter and .is_emitting is false `,
            );
            msg += `Nothing is coming out of ${indirect_object.articlename}. `;
          } else {
            this.game.debug(
              `F1581 | ${this.name}.js | ${indirect_object.id}.aspects.in.vessel.volume is 0 `,
            );
            msg += `${indirect_object.Articlename} is empty. `;
          }
          this.handleFailure(msg);
          return null;
        }

        // can indirect object be drunk from?
        if (!indirect_object.can.drink_from) {
          this.game.debug(
            `F1173 | ${this.name}.js | ${indirect_object.id}.can.drink_from is false `,
          );
          msg += `$(We) can't drink from ${indirect_object.articlename}. `;
          this.handleFailure(msg);
          return null;
        }

        // Is indirect object takeable but not in player?
        if (indirect_object.isDOV("take") && !indirect_object.isIn(player)) {
          this.game.debug(
            `F1579 | ${this.name}.js | ${indirect_object.id} is not in player `,
          );
          msg += `$(We're) not holding ${indirect_object.articlename}. `;
          this.handleFailure(msg);
          return null;
        }

        // Is indirect object closed?
        if (
          indirect_object.getAspectWithVessel() === "in" &&
          indirect_object.isDOV("open")
        ) {
          this.game.debug(
            `F1571 | ${this.name}.js | ${indirect_object.id}.is.closed `,
          );
          msg += `${indirect_object.Articlename} is closed. `;
          this.handleFailure(msg);
          return null;
        }

        if (!indirect_object.doesContainSubstance(direct_object.id)) {
          this.game.debug(
            `F1583 | ${this.name}.js | ${indirect_object.id} does not contain "+${direct_object.id}+" `,
          );
          msg += `${indirect_object.Articlename} contains ${
            this.game.getAsset(indirect_object.getAnySubstanceThisContains())
              .name
          }. `;
          this.handleFailure(msg);
          return null;
        }
      } // verb noun preposition noun

      return true;
    },

    doSuccess: function () {
      var input = this.game.getInput();

      var direct_object = input.getAsset(1);
      var direct_preposition = input.getPreposition(1);
      var indirect_object = input.getAsset(2);
      var indirect_preposition = input.getPreposition(2);
      var player = this.game.getPlayer();
      var msg = "";
      var results;
      var source_aspect;
      var source_vessel;
      var substance;

      if (input.verb_params.can_be_drunk) {
        this.game.debug(
          `F1172 | ${this.name}.js | doSuccess ${direct_object.name}.dov.drink.enabled `,
        );
        // we only arrive here if the object can be direct object of drink but
        // no substance involved. For simple things like "drink potion"

        // parsed sentence structure: verb
        if (input.hasStructure("verb")) {
        }

        // parsed sentence structure: verb noun
        if (input.hasStructure("verb noun")) {
        } // verb noun

        msg += `$(We) drink ${direct_object.articlename}. `;

        if (direct_object && direct_object.on_drink_destroy) {
          direct_object.destroy();
        }
      } else if (input.hasStructure("verb noun")) {
        // shouldn't happen because we inferred verb noun preposition noun
      } else if (input.hasStructure("verb preposition noun")) {
        // shouldn't happen because we inferred verb noun preposition noun
      } else if (input.hasStructure("verb noun preposition noun")) {
        this.game.debug(
          `F1170 | ${this.name}.js | doSuccess dObj = ${direct_object.name}, iObj = ${indirect_object?.name} `,
        );

        source_aspect = indirect_object.getAspectWithVessel();
        source_vessel = indirect_object.getVesselAt(source_aspect);
        substance = this.game.getAsset(source_vessel.substance_id);

        if (indirect_object.on_drink_empty) {
          source_vessel.setVolume(0);
        } else {
          source_vessel.subtractVolume(this.game.settings.mouthful);
        }

        msg += `$(We) drink some ${substance.name} from ${indirect_object.articlename}`;
        if (0 >= source_vessel.getVolume()) {
          msg += `, emptying it in one gulp`;
        }
        msg += `. `;
      }

      // print output
      this.handleSuccess(msg, direct_object);
      return true;
    },
  };
})(); // drink