Pre-release
AdventureJS Docs Downloads
Score: 0 Moves: 0
// put.js

(function () {
  /*global adventurejs A*/

  /**
   * @augments {adventurejs.Verb}
   * @class put
   * @ajsnode game.dictionary.verbs.put
   * @ajsconstruct MyGame.createVerb({ "name": "put", [...] });
   * @ajsconstructedby adventurejs.Dictionary#createVerb
   * @hideconstructor
   * @ajsinstanceof Verb
   * @ajsnavheading ManipulationVerbs
   * @summary Verb meaning put, as in 'put sword' or 'put sword in scabbard'.
   * @ajssynonyms put
   * @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; put paper behind painting</span>
   * You put the slip of paper on which is written the Illuminati
   * password behind the painted portrait of Grover Cleveland.
   * </pre>
   * <pre class="display border outline">
   * <span class="input">&gt; put sword in stone</span>
   * You put the sword in the stone. The stone begins to glow
   * with a soft purple light. The glow brightens slowly,
   * growing gradually into incandescence. You shield your eyes
   * with your hands. There is a loud WHUMPF followed by cool
   * darkness. You lower your hands. The sword and the stone are gone.
   * </pre>
   * <pre class="display border outline">
   * <span class="input">&gt; put syrup on pancakes</span>
   * You can't put anything on the pancakes.
   *
   * Kidding! The game understands that you actually meant
   * "pour syrup on pancakes". The game is not cruel or dumb
   * or inflexible (not on purpose, at least). The game loves you,
   * and validates you, and only wants you to enjoy a healthy
   * nutritious breakfast. You pour some syrup on the pancakes. Mmmm.
   * </pre>
   * <pre class="display border outline">
   * <span class="input">&gt; put lizard under rock</span>
   * You put the lizard back under the hot rock. It wriggles its
   * legs and burrows in contentedly.
   * </pre>
   * <p>
   * <strong>Put</strong> one
   * {@link adventurejs.Tangible|Tangible}
   * {@link adventurejs.Asset|Asset} behind/in/on/under another Tangible Asset.
   * Requires that the destination Asset has a
   * {@link adventurejs.Aspect|Aspect}
   * there.
   * To learn about Aspects, see
   * <a href="/doc/Tangibles_Aspects.html">How to Use Aspects</a>.
   * </p>
   * @ajsverbreactions doRemoveThisFromThat, doRemoveThatFromThis, doMoveThisToThat, doMoveThatToThis
   * @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
   */
  A.Preverbs.put = {
    name: "put",
    prettyname: "put",
    past_tense: "put",
    synonyms: ["put", "place", "set"],
    enqueue_collections: true,
    gerund: "putting",

    /**
     * @ajsverbstructures
     * @memberof put
     */
    accepts_structures: [
      "verb noun", // put lantern
      "verb noun preposition", // put clothes on
      "verb preposition noun", // put down lantern
      "verb noun preposition noun", // put lantern on chest
    ],

    /**
     * @memberof put
     * @ajsverbphrase
     * phrase1:
     * {
     *   accepts_noun: true,
     *   requires_noun: true,
     *   accepts_plural_noun: true,
     *   noun_must_be:
     *   {
     *     in_inventory: true,
     *     not_worn_if_all: true,
     *     not_nested_inventory_if_all: true,
     *   },
     * },
     */
    phrase1: {
      accepts_noun: true,
      requires_noun: true,
      accepts_plural_noun: true,
      noun_must_be: {
        known: true,
        present: true,
        reachable: true,
        visible: true,
        // in_inventory: true,
        takeable: true,
        not_worn_if_all: true,
        not_nested_inventory_if_all: true,
      },
    },

    /**
     * @memberof put
     * @ajsverbphrase
     * phrase2:
     * {
     *   accepts_noun: true,
     *   noun_must_be:
     *   {
     *     tangible: true,
     *     present: true,
     *     visible: true,
     *     reachable: true,
     *     known: true,
     *     not_in_prior_plural: true,
     *   },
     *   accepts_preposition: true,
     *   requires_preposition: true,
     * },
     */
    phrase2: {
      accepts_noun: true,
      noun_must_be: {
        tangible: true,
        present: true,
        visible: true,
        reachable: true,
        known: true,
        not_in_prior_plural: true,
      },
      accepts_preposition: true,
      requires_preposition: true,
    },

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

    doTry: function () {
      var input = this.game.getInput();
      var subject = input.getSubject();
      var verb_phrase = input.verb_phrase;
      var direct_object = input.getAsset(1);
      var indirect_object = input.getAsset(2);
      var direct_preposition = input.getPreposition(1);
      var indirect_preposition = input.getPreposition(2);
      var indirect_aspect;
      var room = this.game.getCurrentRoom();
      var msg = "";
      var results;

      if (input.hasStructure("verb noun") && direct_object.isDOV("drop")) {
        // we've arrived here without an indirect_object, which is legit,
        // subject can "put thing", in which case we just want to drop
        this.game.log(
          "L1337",
          "log",
          "high",
          `${this.name}.js > no indirect object, doVerb drop`,
          "Verbs"
        );
        return this.game.dictionary.doVerb("drop");
      }

      // can be direct object of verb?
      if (!direct_object.isDOV(this.name)) {
        this.game.debug(
          `D1722 | ${this.name}.js | ${direct_object.id}.dov.${this.name}.enabled is unset `
        );
        msg += `${direct_object.Articlename} can't be ${this.past_tense}. `;
        this.handleFailure(msg);
        return null;
      }

      if (subject.getNestId() === direct_object.id) {
        this.game.debug(
          `D1181 | ${this.name}.js | subject is nested on ${direct_object.id}`
        );
        msg += `$(We) can't ${this.name} ${direct_object.articlename} ${
          indirect_preposition ? indirect_preposition : ""
        } ${
          indirect_object ? indirect_object.articlename : ""
        } while $(we're) ${subject.getPostureGerund()} ${subject.getNestPreposition()} it. `;
        this.handleFailure(msg);
        return null;
      }

      if (input.hasStructure("verb noun preposition")) {
        if (["on", "down"].includes(indirect_preposition)) {
          input.setPreposition(1, indirect_preposition);
          input.deletePhrase(2);
          input.setStructure("verb preposition noun");
        } else {
          this.game.debug(
            `D1925 | ${this.name}.js | ${this.name} ${indirect_preposition} not handled `
          );
          msg += `$(We) $(don't) know how to ${this.name} ${direct_object.articlename} ${indirect_preposition}. `;
          this.handleFailure(msg);
          return null;
        }
      }

      if (input.hasStructure("verb preposition noun")) {
        if (direct_preposition === "down" && this.game.hasVerb("drop")) {
          this.game.debug(`D1926 | ${this.name}.js | put down, doVerb drop `);
          return this.game.dictionary.doVerb("drop");
        }
        if (direct_preposition === "on" && direct_object.isDOV("wear")) {
          this.game.debug(`D1891 | ${this.name}.js | put on, doVerb wear `);
          return this.game.dictionary.doVerb("wear");
        }
        // @TODO what about "put in key"? prompt for indirect object? assume from context?
        this.game.debug(
          `D1927 | ${this.name}.js | ${this.name} ${direct_preposition} not handled `
        );
        msg += `$(We) $(don't) know how to ${this.name} ${direct_preposition} ${direct_object.articlename}. `;
        this.handleFailure(msg);
        return null;
      }

      if (input.hasStructure("verb noun preposition noun")) {
        if (direct_object === indirect_object) {
          this.game.debug(
            `D1154 | ${this.name}.js | direct_object ${direct_object.id} is indirect_object ${indirect_object.id} `
          );
          msg += `$(We) can't put ${direct_object.articlename} ${indirect_preposition} itself. `;
          this.handleFailure(msg);
          return null;
        }

        // direct_object.canRemoveThatFromThis(subject)

        // can be direct object of verb?
        if (!indirect_object.isIOV(this.name)) {
          this.game.debug(
            `D1026 | ${this.name}.js | ${indirect_object.id}.iov.${this.name}.enabled is unset `
          );
          msg += `Nothing can be ${this.past_tense} ${indirect_preposition} ${indirect_object.articlename}. `;
          this.handleFailure(msg);
          return null;
        }

        if (indirect_object instanceof adventurejs.Floor) {
          if (!room.has_floor) {
            this.game.debug(
              `D1678 | ${this.name}.js | ${room.id}.has_floor is false `
            );
            msg += `$(We) can't see a floor here. `;
            this.handleFailure(msg);
            return null;
          }

          if (indirect_preposition !== "on") {
            // @TODO what if there's a hole in the floor?
            this.game.debug(
              `D1685 | ${this.name}.js | ${this.name} ${indirect_preposition} floor is not handled `
            );
            msg += `$(We) $(don't) know how to ${this.name} anything ${indirect_preposition} the floor. `;
            this.handleFailure(msg);
            return null;
          }

          // @TODO handle this instead of deferring
          this.game.debug(
            `D1162 | ${this.name}.js | indirect_object is floor, doVerb drop `
          );
          return this.game.dictionary.doVerb("drop");
        }

        // in some cases "put on" can mean "attach to"
        // ex "put cap on pen"
        // so see if we can attach these things
        if (
          indirect_preposition === "on" &&
          !indirect_object.hasAspectAt(indirect_preposition) &&
          (direct_object.canBePut("attached", indirect_object) ||
            indirect_object.canBePut("attached", direct_object)) &&
          this.game.hasVerb("attach")
        ) {
          input.setPreposition(2, "attached");
          this.game.debug(
            `D1155 | ${this.name}.js | ${direct_object.id} and ${indirect_object.id} can attach, doVerb attach `
          );
          return this.game.dictionary.doVerb("attach");
        }

        if (!indirect_object.hasAspectAt(indirect_preposition)) {
          this.game.debug(
            `D1156 | ${this.name}.js | ${indirect_object.id} has no ${indirect_preposition} aspect `
          );
          msg += `$(We) can't put anything ${indirect_preposition} ${indirect_object.articlename}. `;
          this.handleFailure(msg);
          return null;
        }

        if (
          direct_object.getPlacePreposition() === indirect_preposition &&
          direct_object.getPlaceAssetId() === indirect_object.id
        ) {
          this.game.debug(
            `D1163 | ${this.name}.js | ${indirect_object.id} is ${indirect_preposition} ${indirect_object.id}`
          );
          msg += `${direct_object.Articlename_is} already ${indirect_preposition} ${indirect_object.articlename}. `;
          this.handleFailure(msg);
          return null;
        }

        if (
          "in" === indirect_preposition &&
          indirect_object.isDOV("close") &&
          indirect_object.is.closed
        ) {
          // @TODO automatically open the thing, if context allows it
          this.game.debug(
            `D1157 | ${this.name}.js | ${indirect_object.id}.is.closed `
          );
          msg += `${indirect_object.Articlename_is} closed. `;
          this.handleFailure(msg);
          return false;
        }

        results = this.tryToPutThisInThatAspect(
          direct_object,
          indirect_preposition,
          indirect_object
        );
        if (results.fail) {
          msg = results.msg;
          this.handleFailure(msg);
          if (results.end_turn) return false;
          return null;
        }
      } // verb noun preposition noun

      return true;
    },

    doSuccess: function () {
      var input = this.game.getInput();
      var subject = input.getSubject();
      var verb_phrase = input.verb_phrase;
      var direct_object = input.getAsset(1);
      var indirect_object = input.getAsset(2);
      var indirect_preposition = input.getPreposition(2);
      var msg = "";
      var results;
      var moved = false;

      if (direct_object.is.worn) {
        results = direct_object.unfasten();
        msg += results ? `$(We) ${results} and remove ` : `$(We) remove `;
        msg += `${direct_object.articlename} first. `;
        direct_object.incrementDoVerbCount("remove", "dov");
        direct_object.is.worn = false;
      }

      // sentence structure: verb noun preposition noun
      if (input.hasStructure("verb noun preposition noun")) {
        msg += `$(We)`;

        if (direct_object.getPlaceAssetId() !== subject.id) {
          msg += ` take ${direct_object.articlename} from ${
            direct_object.getPlaceAsset().articlename
          } and `;

          // remove direct object from current location
          results = direct_object
            .getPlaceAsset()
            .onRemoveThatFromThis(direct_object);
          if ("undefined" !== typeof results) return results;

          // subject has to pick this up
          // set direct object's temporary location to subject
          results = subject.onMoveThatToThis(direct_object);
          if ("undefined" !== typeof results) return results;

          moved = true;
        }

        msg += ` put ${
          moved ? direct_object.getPronoun("we") : direct_object.articlename
        } ${indirect_preposition} ${indirect_object.articlename}. `;

        // remove noun1 from subject
        results = subject.onRemoveThatFromThis(direct_object);
        if ("undefined" !== typeof results) return results;

        // set noun1's new location to noun2
        // add noun1 to noun2's contents
        results = indirect_object.onMoveThatToThis(
          direct_object,
          indirect_preposition
        );
        if ("undefined" !== typeof results) return results;

        if (
          input.parsedNoun1.matches.qualified.length > 1 &&
          -1 === input.output_class.indexOf("concatenate_output")
        ) {
          input.output_class += " concatenate_output";
        }
      }

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