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

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

  /**
   * @augments {adventurejs.Verb}
   * @class go
   * @ajsnode game.dictionary.verbs.go
   * @ajsconstruct MyGame.createVerb({ "name": "go", [...] });
   * @ajsconstructedby adventurejs.Dictionary#createVerb
   * @hideconstructor
   * @ajsinstanceof Verb
   * @ajsnavheading LocomotionVerbs
   * @summary Verb meaning go [preposition] asset or travel [direction].
   * @ajssynonyms go
   * @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; go in wardrobe</span>
   * You go in the wardrobe. Hey, it's cold in here! Better put
   * on a coat.
   * </pre>
   * <p>
   * <strong>Go</strong> can accept
   * directions and tangible assets.
   * For example, <strong>go east</strong> is equivalent
   * to entering just <strong>east</strong>;
   * <strong>go bed</strong> is equivalent to
   * <strong>get on bed</strong> and requires that the
   * {@link adventurejs.Tangible|Tangible}
   * {@link adventurejs.Asset|Asset} has an <strong>on</strong>
   * {@link adventurejs.Aspect|Aspect}.
   * See
   * <a href="/doc/Tangibles_Aspects.html">How to Use Aspects</a>
   * to learn more.
   * </p>
   * <p>
   * <strong>Go</strong> can be triggered via the verb
   * <strong>get</strong>, as in <strong>get down</strong>
   * or <strong>get on bed</strong> or
   * <strong>get out from under bed</strong>.
   * </p>
   * @ajsverbreactions doRemoveThisFromThat, doRemoveThatFromThis, doMoveThisToThat, doMoveThatToThis, doNestThatToThis, doNestThisToThat, doUnnestThatFromThis, doUnnestThisFromThat
   * @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
   */
  A.Preverbs.go = {
    name: "go",
    prettyname: "go",
    past_tense: "went",
    synonyms: ["go"],
    gerund: "joing",
    type: { locomotion: true, travel: true },

    /**
     * @ajsadverbs
     * @memberof go
     */
    accepts_adverbs: ["left", "right", "around", "back", "towards", "over"],

    /**
     * @ajsverbstructures
     * @memberof go
     */
    accepts_structures: [
      // "verb", // go
      "verb noun", // go east, go bed
      "verb preposition", // go off
      "verb preposition noun", // get off bed
      "verb noun preposition noun", // go east on bicycle
      "verb preposition noun preposition noun", // go from bed to desk
      "verb preposition noun preposition noun preposition noun",
      // go from bed to desk with rope
    ],

    player_must_be: {
      not_on_floor: true,
      not_constrained: true,
      //not_nested_elsewhere: true,
    },

    /**
     * @memberof go
     * @ajsverbphrase
     * phrase1:
     * {
     *   accepts_noun: true,
     *   //requires_noun: true, // because we allow 'get down' and similar
     *   noun_must_be: {
     *     not_global: true,
     *     tangible: true,
     *     known: true,
     *     present: true,
     *     visible: true,
     *     reachable: true,
     *   },
     *   accepts_preposition: true,
     *   accepts_preposition_without_noun: true,
     * },
     */
    phrase1: {
      accepts_noun: true,
      noun_must_be: {
        //not_global: true, // disabled to allow better handling of denial
        tangible: true,
        known: true,
        // present: true, // disabled to allow "go to"
        prefer_present_if_ambiguous: true,
        visible: true,
        reachable: true,
        not_player: true,
      },
      accepts_preposition: true,
      accepts_preposition_without_noun: true,
      accepts_direction: true,
    },

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

    /**
     * @memberof go
     * @ajsverbphrase
     * phrase3:
     * {
     *   accepts_noun:true,
     *   requires_noun:true,
     *   noun_must_be:
     *   {
     *     tangible: true,
     *     known: true,
     *     present: true,
     *     visible: true,
     *     reachable: true,
     *   },
     *   accepts_preposition: true,
     *   requires_preposition: true,
     * },
     */
    phrase3: {
      accepts_noun: true,
      requires_noun: true,
      noun_must_be: {
        tangible: true,
        known: true,
        present: true,
        visible: true,
        reachable: true,
      },
      accepts_preposition: true,
      requires_preposition: true,
      // accepts_these_prepositions: ["with", "to", "from"],
    },

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

    in_can_mean_on: true,

    getPercentStringUp: function (percent) {
      return percent === 1
        ? `to the top of`
        : percent > 0.75
          ? `almost to the top of`
          : percent > 0.5
            ? `still further up`
            : percent > 0.25
              ? `further up`
              : `part way up`;
    },

    getPercentStringDown: function (percent) {
      return percent === 1
        ? `to the top of`
        : percent > 0.75
          ? `part way down`
          : percent > 0.5
            ? `further down`
            : percent > 0.25
              ? `still further down`
              : `almost all the way down`;
    },

    getPostureString: function (posture, prep) {
      return posture === "stand"
        ? `stand upon it`
        : posture === "sit"
          ? `sit down ${prep} it`
          : posture === "lie"
            ? `lie down ${prep} it`
            : posture === "kneel"
              ? `kneel down ${prep} it`
              : posture === "cling"
                ? `cling tightly to it`
                : posture === "grip"
                  ? `grip it tightly`
                  : posture === "hang"
                    ? `hang from it`
                    : ``;
    },

    canPlayerUseThisWithThat: function (
      target_preposition,
      target_asset,
      tool_asset
    ) {
      let input = this.game.getInput();
      let input_verb = this.game.dictionary.getVerb(input.input_verb);

      // if we're here, tool_preposition is "with"
      let response = { failure: false, return: null, msg: "" };

      // works with any indirect object?
      if (target_asset.allowVerbWithAnything(this.name, "dov")) {
        return { return: true };
      }

      // indirect object not required?
      if (target_asset.allowVerbWithNothing(this.name, "dov")) {
        this.game.debug(
          `D1868 | ${this.name}.js | ${tool_asset.id} isn't needed to ${input.input_verb} ${target_preposition ? target_preposition : "to"} ${target_asset.id}`
        );
        response.msg += `${tool_asset.Articlename} isn't needed to ${input.input_verb} ${target_preposition ? target_preposition : "to"} ${target_asset.articlename}. `;
        response.failure = true;
        return response;
      }

      // indirect object subscribed to verb?
      if (!tool_asset.isIOV(input_verb.name)) {
        this.game.debug(
          `D1293 | ${this.name}.js | ${tool_asset.id}.iov.${input_verb.name} is unset`
        );
        response.msg += `$(We) can't use ${tool_asset.articlename} to ${input.input_verb} ${target_preposition} ${target_asset.articlename}. `;
        response.failure = true;
        return response;
      }

      // indirect object usable with direct object?
      if (!target_asset.allowVerbWithAsset(this.name, tool_asset, "dov")) {
        this.game.debug(
          `D1869 | ${this.name}.js | ${target_asset.id}.dov.${this.name}.with_assets does not include ${tool_asset.id} `
        );
        response.msg += `${tool_asset.Articlename} can't be used to ${input.input_verb} ${target_preposition} ${target_asset.articlename}. `;
        response.failure = true;
        return response;
      }

      // single use indirect object?
      if (
        tool_asset.allowVerbOnce(this.name, "iov") &&
        tool_asset.iDidVerb(this.name, "iov")
      ) {
        this.game.debug(
          `D1870 | ${this.name}.js | ${tool_asset.id}.iov.${
            this.name
          }.once and ${tool_asset.id}.did.${this.name}.indirectly is ${
            tool_asset.did[this.name].indirectly
          } `
        );
        response.msg += `${tool_asset.Articlename} has already been used to ${input.input_verb} ${target_preposition} something. `;
        response.failure = true;
        return response;
      }

      return response;
    },

    /**
     * canPlayerGoFromThisToThat tests whether player can reach destination from origin.
     * @param {*} origin The specified origin asset.
     * @param {*} destination The specified destination asset.
     * @returns {Object}
     */
    canPlayerGoFromThisToThat: function (origin, destination) {
      // if we're here, direct_preposition is "from" and indirect_preposition is "to"
      let response = {
        failure: false,
        msg: "",
        aspect: null,
        asset: destination,
      };
      let input = this.game.getInput();
      let input_verb = this.game.dictionary.getVerb(input.input_verb);
      let player = this.game.getPlayer();
      let origin_asset = player.getNestOrPlaceAsset();
      let origin_aspect = player.getNestOrPlaceAspect();
      // let reachable = true; // default = reachable

      // --------------------------------------------------
      // canPlayerGoFromThisToThat
      //  - is specified origin actually the origin?
      // --------------------------------------------------
      if (origin_asset.id !== origin.id) {
        // origin must be player's origin
        this.game.debug(
          `D1183 | ${this.name}.js | player is not on ${origin.id}`
        );
        response.msg += `$(We're) not ${
          origin.aspects[origin.default_aspect]?.canPlayer("enter")
            ? origin.default_aspect
            : "on"
        } ${origin.articlename}. `;
        response.failure = true;
        return response;
      }

      // --------------------------------------------------
      // canPlayerGoFromThisToThat
      //  - does destination have an aspect for player to enter?
      // --------------------------------------------------
      if (
        !destination.hasAspectAt(destination.default_aspect) ||
        !destination.getAspectAt(destination.default_aspect).canPlayer("enter")
      ) {
        this.game.debug(
          `D1239 | ${this.name}.js | ${destination.id} has no enterable aspect set `
        );
        origin_asset.hasClass("Room") ||
        origin_asset.id === destination.getPlaceAssetId()
          ? (response.msg += `$(We) edge a bit closer to ${destination.articlename}. `)
          : (response.msg += `$(We) can't reach ${destination.articlename} from ${origin_asset.hasClass("room") ? "here" : origin_asset.articlename}. `);
        response.failure = true;
        return response;
      }
      response.aspect = destination.getAspectAt(destination.default_aspect);

      // --------------------------------------------------
      // canPlayerGoFromThisToThat
      //  - is destination subscribed to the verb?
      // --------------------------------------------------
      if (!destination?.isDOV(input.input_verb)) {
        this.game.debug(
          `D1012 | ${this.name}.js | ${destination.id}.dov.${input.input_verb}.enabled is unset`
        );
        response.msg += `$(We) can't ${input.input_verb} ${response.aspect.id} ${destination.articlename}. `;
        response.failure = true;
        return response;
      }

      // --------------------------------------------------
      // canPlayerGoFromThisToThat
      //  - is destination positioned so as to prevent nesting?
      // --------------------------------------------------
      if (destination.placePreventsNesting(player)) {
        this.game.debug(
          `D1874 | ${this.name}.js | ${destination.id} can't nest ${player.id} while it's ${destination.getPlacePreposition()} ${destination.getPlaceAssetId}. `
        );
        response.msg += `$(We) can't ${input.input_verb} ${response.aspect.id} ${destination.articlename} while it's ${destination.getPlacePreposition()} ${destination.getPlaceAssetId}. `;
        response.failure = true;
        return response;
      }

      // --------------------------------------------------
      // canPlayerGoFromThisToThat
      //  - is destination too far to jump?
      // --------------------------------------------------
      if (this.game.settings.xz_determines_reachability) {
        // is distance between assets greater than jump_length?
        let distance = A.getHorizontalDistance(
          origin.position,
          destination.position
        );

        // is this a jumping situation?
        if (input_verb.can_span) {
          let reachable = distance <= player.jump_length;
          if (!reachable) {
            this.game.debug(
              `D1864 | ${this.name}.js | player is nested ${origin_aspect.id} ${origin_asset.id}, infer "go from to" `
            );
            response.msg += `$(We) can't reach ${destination.articlename} from $(our) place ${origin_aspect.id} ${origin_asset.articlename}. `;
            response.failure = true;
            return response;
          }
        }
      }

      // --------------------------------------------------
      // canPlayerGoFromThisToThat
      //  - is destination too high to jump to?
      // --------------------------------------------------
      if (this.game.settings.y_determines_reachability) {
        // is distance between assets greater than jump_length?
        let reachable =
          destination.getYBottom() < player.getY() + player.jump_height;
        console.warn(
          "player.getY()",
          player.getY(),
          "destination.getYBottom()",
          destination.getYBottom(),
          "player.jump_height",
          player.jump_height,
          "destination.getYBottom() - player.jump_height",
          destination.getYBottom() - player.jump_height
        );
        console.warn(
          "player.getY() < destination.getYBottom() - player.jump_height",
          player.getY() < destination.getYBottom() - player.jump_height
        );
        console.warn({ reachable });
        if (!reachable) {
          this.game.debug(
            `D1284 | ${this.name}.js | player is nested ${origin_aspect.id} ${origin_asset.id}, infer "go from to" `
          );
          response.msg += `$(We) can't reach ${destination.articlename} from $(our) place ${origin_aspect.id} ${origin_asset.articlename}. `;
          response.failure = true;
          return response;
        }
      }

      return response;
    }, // canPlayerGoFromThisToThat

    /**
     * Check if player should reposition up.
     * @param {Object} player
     * @param {Object} origin_asset
     * @param {Object} origin_aspect
     * @param {String} verb_name
     * @param {Boolean} off
     */
    canPlayerRepositionUp: function (origin_asset, origin_aspect) {
      let player = this.game.getPlayer();
      let input = this.game.getInput();
      let input_verb = this.game.dictionary.getVerb(input.input_verb);
      let bool =
        origin_aspect.canPlayer(input_verb.name) &&
        origin_aspect.canPlayer("scale") &&
        player.can.scale &&
        origin_aspect.scale_increment > 0 &&
        player.getY() < origin_asset.getYTop() &&
        !input_verb.override_aspect_scale_increments.up;
      return bool;
    },

    /**
     * Check if player should reposition down (as opposed to go off).
     * @param {Object} player
     * @param {Object} origin_asset
     * @param {Object} origin_aspect
     * @param {String} verb_name
     * @param {Boolean} off
     */
    canPlayerRepositionDown: function (origin_asset, origin_aspect, off) {
      let player = this.game.getPlayer();
      let input = this.game.getInput();
      let input_verb = this.game.dictionary.getVerb(input.input_verb);

      if (off && !origin_asset.hasQuirk("get_off_means_go_down")) return false;
      let bool =
        origin_aspect.canPlayer(input_verb.name) &&
        origin_aspect.canPlayer("scale") &&
        player.can.scale &&
        origin_aspect.scale_increment > 0 &&
        player.getY() - origin_asset.getY() > origin_aspect.scale_increment &&
        !input_verb.override_aspect_scale_increments.down;
      return bool;
    },

    // --------------------------------------------------
    // doTry
    // the main sequencing function
    // --------------------------------------------------
    doTry: function () {
      const input = this.game.getInput();
      const input_verb = this.game.dictionary.getVerb(input.input_verb);
      const adverb = input.getAdverb();

      // --------------------------------------------------
      // change prepositions "to from" to "from to"
      // --------------------------------------------------
      if (
        (input.getPreposition(1) === "to" &&
          input.getPreposition(2) === "from") ||
        (input.getPreposition(2) === "to" && input.getPreposition(3) === "from")
      ) {
        input.setVerbParam("fromto", true);
      }
      if (
        input.getPreposition(2) === "to" &&
        input.getPreposition(3) === "from"
      ) {
        input.swapPhrases(2, 3);
        input.setVerbParam("fromto", true);
      } else if (
        input.getPreposition(1) === "to" &&
        input.getPreposition(2) === "from"
      ) {
        input.swapPhrases(1, 2);
        input.setVerbParam("fromto", true);
      }
      if (
        input.hasStructure("verb noun preposition noun") &&
        "from" === input.getPreposition(2)
      ) {
        input.setPreposition(1, "to");
        input.swapPhrases(1, 2);
        input.setVerbParam("fromto", true);
      }

      const player = this.game.getPlayer();
      const current_room = this.game.getCurrentRoom();

      const origin_asset = player.getNestOrPlaceAsset();
      const origin_aspect = player.getNestOrPlaceAspect();
      input.setVerbParam("origin_asset", origin_asset);
      input.setVerbParam("origin_aspect", origin_aspect);

      let asset1 = input.getAsset(1);
      let preposition1 = input.getPreposition(1);
      let asset2 = input.getAsset(2);
      let preposition2 = input.getPreposition(2);
      let asset3 = input.getAsset(3);
      let preposition3 = input.getPreposition(3);

      let destination_asset;
      let destination_preposition;
      let destination_aspect;

      let tool_asset;
      let tool_preposition;

      let msg = "";
      let results;

      let verified_canPlayerGoFromThisToThat;

      // --------------------------------------------------
      // does the preposition map to an exit as in "go up"?
      // this includes global exits which generally only return information
      // --------------------------------------------------
      let exit_from_preposition = this.game.getExitFromDirection(
        input.getPreposition(1)
      );

      // --------------------------------------------------
      // did we arrive here with a sentence structure of "verb"?
      // --------------------------------------------------
      if (input.hasStructure("verb")) {
        // this is redundant as go doesn't handle "verb" and
        // extension verbs will have had their own sentence structure checks
        // but just in case
        if (input_verb.accepts_structures.indexOf("verb") === -1) {
          this.game.debug(
            `D1182 | ${input_verb.name}.js | no direct_object, soft prompt noun1`
          );
          msg += `Where did $(we) want to ${input.getInput()}? `;
          input.setSoftPrompt({
            index: 1,
            type: "noun",
            noun1: true,
            verb_phrase: input.verb_phrase,
            verb: input_verb.name,
            structure: "verb noun",
          });
          this.handleFailure(msg);
          return null;
          // END
        }

        // --------------------------------------------------
        // verb / check for verb quirks
        // --------------------------------------------------
        if (
          input_verb.name === "jump" &&
          origin_asset.hasQuirk("jump_means_jump_on")
        ) {
          return true; // PASS TO: doSuccess
          // END
        }

        if (
          input_verb.name === "jump" &&
          origin_asset.hasQuirk("jump_means_jump_off") &&
          origin_aspect.canPlayer("exit")
        ) {
          input.setPreposition(1, "off");
          input.setAsset(1, origin_asset);
          input.setStructure("verb preposition noun");
          return true; // PASS TO: doSuccess
          // END
        }
      } // END verb

      // --------------------------------------------------
      // sentence structure still "verb" after quirk checks?
      // --------------------------------------------------
      if (input.hasStructure("verb")) {
        input.setVerbParam("action", "none");
        return true;
      } // END verb

      // --------------------------------------------------
      // did player input "go up", "go down" etc while unnested?
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition") &&
        origin_asset.hasClass("Room")
      ) {
        // were we able to infer an exit?
        if (!exit_from_preposition) {
          // we got nuthin'
          this.game.debug(
            `D1121 | ${this.name}.js | no context found for ${input_verb.name} with preposition ${preposition1}`
          );
          msg = `$(We) don't see a way to ${input_verb.name} ${preposition1}. `;
          this.handleFailure(msg);
          return null;
          // END
        }
        // found an exit, tryTravel
        this.game.log(
          "L1384",
          "log",
          "high",
          `${this.name}.js > received preposition ${preposition1}, infer exit ${exit_from_preposition.id}`,
          "Verbs"
        );
        return this.game.tryTravel(exit_from_preposition.direction);
        // PASS TO: tryTravel
      } // END verb preposition, no nest

      // --------------------------------------------------
      // sentence structure: verb preposition
      // preposition without asset: go up, get off, etc
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition") &&
        !origin_asset.hasClass("Room")
      ) {
        // preposition must be direction

        if (!origin_asset.isDOV(input_verb.name)) {
          this.game.debug(
            `D1131 | ${this.name}.js | ${origin_asset.id}.dov.${input_verb.name} is unset `
          );
          msg += `$(We) can't ${input_verb.name} ${preposition1} ${origin_asset.articlename}. `;
          this.handleFailure(msg);
          return null;
        }

        // --------------------------------------------------
        // verb preposition + nested / switch
        // --------------------------------------------------
        switch (preposition1) {
          // --------------------------------------------------
          // verb preposition + nested / switch / up
          //  - climb further up origin, or tryTravel?
          // --------------------------------------------------
          case "up":
            // --------------------------------------------------
            // verb preposition + nested / switch / up
            //  - is player below the top of the nest?
            // --------------------------------------------------
            if (player.getY() < origin_asset.getYTop()) {
              // --------------------------------------------------
              // verb preposition + nested / switch / up / below top
              //  - can player reposition?
              // --------------------------------------------------
              if (this.canPlayerRepositionUp(origin_asset, origin_aspect)) {
                // let player go higher
                input.setAsset(1, origin_asset);
                input.setStructure("verb preposition noun");
                input.setVerbParam("reposition_up", true);
                input.setVerbParam("action", "reposition");
                return true; // PASS TO: doSuccess
              }

              // --------------------------------------------------
              // verb preposition + nested / switch / up / below top
              //  - player can't reposition
              // --------------------------------------------------
              else {
                this.game.debug(
                  `D1040 | ${this.name}.js | ${origin_asset.id}.aspects.${origin_aspect.id}.player.can.scale is false `
                );
                msg += `$(We) can't ${input_verb.name} any higher on ${origin_asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END
              }
            } // player below top of asset

            // --------------------------------------------------
            // verb preposition + nested / switch / up / at top
            // --------------------------------------------------
            else if (player.getY() >= origin_asset.getYTop()) {
              // --------------------------------------------------
              // verb preposition + nested / switch / up / at top
              //  - is an up exit available?
              // --------------------------------------------------
              if (exit_from_preposition) {
                this.game.log(
                  "L1385",
                  "log",
                  "high",
                  `${this.name}.js > player is at top of ${origin_asset.id}, tryTravel ${exit_from_preposition.direction}`,
                  "Verbs"
                );
                this.game.print(msg);
                return this.game.tryTravel(exit_from_preposition.direction);
                // PASS TO: tryTravel
              } // exit from preposition

              // --------------------------------------------------
              // verb preposition + nested / switch / up / at top
              //  - no up exit available
              // --------------------------------------------------
              else {
                this.game.debug(
                  `D1047 | ${this.name}.js | player is at top of ${origin_asset.id} `
                );
                msg += `$(We) can't get any higher on ${origin_asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END up
              }
            } // player at top
            break;
          // END up

          // --------------------------------------------------
          // verb preposition + nested / switch / down
          //  - climb further down origin, or get off?
          // --------------------------------------------------
          case "down":
            // --------------------------------------------------
            // verb preposition + nested / switch / down
            //  - climb further down?
            // --------------------------------------------------
            if (this.canPlayerRepositionDown(origin_asset, origin_aspect)) {
              input.setAsset(1, origin_asset);
              input.setStructure("verb preposition noun");
              input.setVerbParam("action", "reposition");
              input.setVerbParam("reposition_down", true);
              return true; // PASS TO: doSuccess
              // END down
            }

            // --------------------------------------------------
            // verb preposition + nested / switch / down
            //  - get off
            // --------------------------------------------------
            else {
              // --------------------------------------------------
              // verb preposition + nested / switch / down
              //  - can player exit nest?
              // --------------------------------------------------
              if (!origin_aspect.canPlayer("exit")) {
                this.game.debug(
                  `D1295 | ${this.name}.js | ${origin_asset.id}.aspects.${origin_aspect.id}.player.can.exit is false `
                );
                msg += `$(We) can't get get off ${origin_asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END down
              }

              // --------------------------------------------------
              // verb preposition + nested / switch / down
              //  - success
              // --------------------------------------------------
              input.setAsset(1, origin_asset);
              input.setStructure("verb preposition noun");
              input.setVerbParam("action", "unnest");
              input.setVerbParam("off", true);
              input.setPreposition(1, "off");
              return true; // PASS TO: doSuccess
              // END down
            }

          // --------------------------------------------------
          // verb preposition + nested / switch / in
          // --------------------------------------------------
          case "in":
            this.game.log(
              "L1390",
              "log",
              "high",
              `${this.name}.js > tryTravel ${exit_from_preposition.direction}`,
              "Verbs"
            );
            // tryTravel has its own logic for trying to travel while nested
            // if no in exit is present, parser will have found global_in
            return this.game.tryTravel(exit_from_preposition.direction);
          // PASS TO: tryTravel
          // END in

          // --------------------------------------------------
          // verb preposition + nested / switch / out
          // --------------------------------------------------
          case "out":
            this.game.log(
              "L1386",
              "log",
              "high",
              `${this.name}.js > infer 'get out of ${origin_asset.id}'`,
              "Verbs"
            );

            // --------------------------------------------------
            // verb preposition + nested / switch / out
            //  - can player exit nest?
            // --------------------------------------------------
            if (
              !["on", "in", "under", "behind"].includes(origin_aspect.id) ||
              !origin_aspect.canPlayer("exit")
            ) {
              this.game.debug(
                `D1130 | ${this.name}.js | player nested ${origin_aspect.id} ${origin_asset.id} `
              );
              msg += `$(We're) not in anything $(we) can get out of. `;
              this.handleFailure(msg);
              return null;
            }

            // --------------------------------------------------
            // verb preposition + nested / switch / out
            //  - success
            // --------------------------------------------------
            input.setVerbParam("action", "unnest");
            input.setVerbParam("out", true);
            input.setAsset(1, origin_asset);
            input.setStructure("verb preposition noun");
            return true; // PASS TO: doSuccess
          // END out

          // --------------------------------------------------
          // verb preposition + nested / switch / off
          // --------------------------------------------------
          case "off":
            this.game.log(
              "L1387",
              "log",
              "high",
              `${this.name}.js > infer 'get off of ${origin_asset.id}'`,
              "Verbs"
            );

            // --------------------------------------------------
            // verb preposition + nested / switch / off
            //  - is player on anything?
            // --------------------------------------------------
            if ("on" !== origin_aspect.id) {
              this.game.debug(
                `D1152 | ${this.name}.js | player nested ${origin_aspect.id} ${origin_asset.id} `
              );
              msg += `$(We're) not on ${origin_asset.articlename}. `;
              this.handleFailure(msg);
              return null;
              // END down
            }

            // --------------------------------------------------
            // verb preposition + nested / switch / off
            //  - can player exit?
            // --------------------------------------------------
            if (!origin_aspect.canPlayer("exit")) {
              this.game.debug(
                `D1304 | ${this.name}.js | ${origin_asset.id}.aspects.${origin_aspect.id}.player.can.exit is false`
              );
              msg += `$(We) can't get off ${origin_asset.articlename}. `;
              this.handleFailure(msg);
              return null;
              // END down
            }

            // --------------------------------------------------
            // verb preposition + nested / switch / off
            //  - can player reposition down?
            // --------------------------------------------------
            if (
              this.canPlayerRepositionDown(origin_asset, origin_aspect, true)
            ) {
              // --------------------------------------------------
              // verb preposition + nested / switch / off
              //  - reposition down success
              // --------------------------------------------------
              input.setAsset(1, origin_asset);
              input.setStructure("verb preposition noun");
              input.setVerbParam("action", "reposition");
              input.setVerbParam("reposition_down", true);
              return true; // PASS TO: doSuccess
              // END down
            }

            // --------------------------------------------------
            // verb preposition + nested / switch / off
            //  - get off success
            // --------------------------------------------------
            input.setVerbParam("action", "unnest");
            input.setVerbParam("off", true);
            input.setAsset(1, origin_asset);
            input.setStructure("verb preposition noun");
            return true; // PASS TO: doSuccess
          // END off

          // --------------------------------------------------
          // verb preposition + nested / switch / unhandled prepositions
          // --------------------------------------------------
          default:
            this.game.debug(
              `D1046 | ${this.name}.js | no context found for ${input_verb.name} with preposition ${preposition1}`
            );
            msg = `$(We) don't see a way to ${input_verb.name} ${preposition1}. `;
            this.handleFailure(msg);
            return null;
        } // END switch preposition
      } // END verb preposition

      // --------------------------------------------------
      // structure: verb preposition
      //  - still no direct object? prompt player
      // --------------------------------------------------
      if (input.hasStructure("verb preposition")) {
        if (!asset1) {
          this.game.debug(
            `D1001 | ${this.name}.js | no direct_object, soft prompt noun1`
          );
          msg += `Where did $(we) want to ${input.getInput()}? `;
          input.setSoftPrompt({
            index: 1,
            type: "noun",
            noun1: true,
            structure: "verb preposition noun",
          });
          this.handleFailure(msg);
          return null;
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun / goTo
      //  - did player specifically input "go to asset" ?
      // --------------------------------------------------
      // We need to do some checks before calling goTo verb
      // as goTo only has logic for finding & traveling.
      // We run this test early, out of logical sequence,
      // because we've omitted noun_must_be.present
      // to allow for "go to [other room]", but this is the
      // only block that applies to, and if it doesn't return
      // true we'll have to run selectPresent() afterwards.
      if (
        input.hasStructure("verb preposition noun") &&
        input_verb.name === "go" &&
        preposition1 === "to"
      ) {
        // --------------------------------------------------
        // sentence structure: verb preposition noun / goTo
        //  - is target a room?
        // --------------------------------------------------
        if (asset1 instanceof adventurejs.Room) {
          if (asset1.id === current_room.id) {
            this.game.debug(
              `D1205 | ${this.name}.js | player is already in ${current_room.id}`
            );
            msg += `$(We're) already there! `;
            this.handleFailure(msg);
            return null;
            // END goTo
          }

          // --------------------------------------------------
          // sentence structure: verb preposition noun / goTo
          //  - target is another room
          // --------------------------------------------------
          input.setVerbParam("goto", true);
          // PASS TO: goto
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun / goTo
        //  - is target not a room?
        // --------------------------------------------------
        if (!(asset1 instanceof adventurejs.Room)) {
          let destination = asset1.getRoomId();
          // --------------------------------------------------
          // sentence structure: verb preposition noun / goTo
          //  - is target in current room?
          // --------------------------------------------------
          if (destination !== current_room.id) {
            // --------------------------------------------------
            // sentence structure: verb preposition noun / goTo
            //  - target is in another room
            // --------------------------------------------------
            input.setVerbParam("goto", true);
            // PASS TO: goto
          }
          // else do nothing, this will be handled later
          // END
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun / goTo
        //  - did we find a legit situation for goTo?
        // --------------------------------------------------
        if (input.getVerbParam("goto")) {
          // --------------------------------------------------
          // sentence structure: verb preposition noun / goTo
          //  - is player nested?
          //  - @TODO automatically unnest?
          // --------------------------------------------------
          if (
            !origin_asset.hasClass("Room") &&
            !origin_asset.hasClass("Vehicle")
          ) {
            /* !origin_asset.isWithin(player) */
            this.game.debug(
              `D1210 | ${
                this.name
              }.js | player is nested ${player.getNestPreposition()} ${
                origin_asset.id
              }`
            );
            msg += `$(We'll) have to get ${player.getPrettyUnnestPreposition()} ${
              origin_asset.articlename
            } first. `;
            this.handleFailure(msg);
            return null;
            // END
          }

          // --------------------------------------------------
          // sentence structure: verb preposition noun / goTo
          //  - is player nested on a vehicle?
          //  - @TODO goTo needs to handle vehicles
          // --------------------------------------------------
          // if (origin_asset.isWithin(player)) {
          //   this.game.debug(
          //     ` | ${
          //       this.name
          //     }.js | player is nested ${player.getNestPreposition()} ${
          //       origin_asset.id
          //     }`
          //   );
          //   msg += `$(We'll) have to get ${player.getPrettyUnnestPreposition()} ${
          //     origin_asset.articlename
          //   } first. `;
          //   this.handleFailure(msg);
          //   return null;
          //   // END
          // }

          if (this.game.hasVerb("goTo")) {
            this.game.log(
              "L1383",
              "log",
              "high",
              `${this.name}.js > destination is not in current room, doVerb goTo `,
              "Verbs"
            );
            return this.game.dictionary.doVerb("goTo");
            // END
          } else {
            this.game.debug(
              `D1092 | ${this.name}.js | destination is not in current room and verb goTo is not enabled `
            );
            msg += `$(We) can't get to ${asset1.articlename} from here. `;
            this.handleFailure(msg);
            return null;
            // END
          }
        } // goto
      } // go to asset

      // --------------------------------------------------
      // check a series of noun/prep situations per phrase,
      // independent of sentence structure
      // some may end in failure but none result in success
      // --------------------------------------------------
      for (let i = input.getPhraseCount(); i > 0; i--) {
        const asset = input.getAsset(i);
        let preposition = input.getPreposition(i);
        // console.warn({ preposition, asset });

        // --------------------------------------------------
        // per phrase / is asset absent?
        // --------------------------------------------------
        // Most verbs use phrase.noun_must_be.present but we omitted that
        // to handle "go to [other room]" and now we need to make up
        if (asset && !this.game.parser.selectPresent([asset]).length) {
          this.game.debug(`D2138 | ${this.name}.js | ${asset.id} not in room `);
          // use the player's original input for the object
          // rather than its real name to avoid revealing information
          msg += `There doesn't appear to be any ${
            input.replacements[asset.id]
              ? input.replacements[asset.id].source
              : asset.name
          } present. `;
          this.handleFailure(msg);
          return null;
          // END
        } // absent asset

        // --------------------------------------------------
        // per phrase / is asset global?
        // --------------------------------------------------
        if (asset?.is.global && asset.id !== "global_floor") {
          this.game.debug(`D1725 | ${this.name}.js | ${asset.id}.is.global `);
          msg += `$(We) can't ${input_verb.name} `;
          msg += asset.direction
            ? asset.direction
            : ` ${preposition ? preposition : "to"} ${asset.articlename}`;
          msg += `. `;
          if (
            asset.direction &&
            this.game.settings.when_travel_fails_list_exits
          ) {
            msg += this.game.getCurrentRoomExits();
          }
          this.handleFailure(msg);
          return null;
          // END
        } // global

        // --------------------------------------------------
        // per phrase / is asset direction?
        // --------------------------------------------------
        if (asset?.direction) {
          //
        } // END asset.direction

        // --------------------------------------------------
        // per phrase / does in mean on?
        // --------------------------------------------------
        if (
          preposition === "in" &&
          asset &&
          !asset.direction &&
          asset.hasQuirk("in_means_on") &&
          asset.hasAspectAt("on") &&
          asset.getAspectAt("on").canPlayer("enter")
        ) {
          preposition = "on";
        }

        // --------------------------------------------------
        // per phrase / switch / preposition
        // Run a variety of asset+preposition checks.
        // These are independent of sentence structure.
        // They don't seek to identify so much as disqualify.
        // --------------------------------------------------

        switch (preposition) {
          // --------------------------------------------------
          // per phrase / switch / with - infer asset to be tool
          // --------------------------------------------------
          case "with":
            if (i > 1) {
              results = this.canPlayerUseThisWithThat(
                input.getPreposition(i - 1),
                input.getAsset(i - 1),
                asset
              );
              if (results.failure) {
                this.handleFailure(results.msg);
                return null;
                // END
              }
            }
            input.setVerbParam("with", true); // - not helpful?
            input.setVerbParam("tool_asset", asset);
            input.setVerbParam("tool_preposition", "with");
            input.setVerbParam("tool_position", i);
            tool_asset = asset;
            tool_preposition = "with";
            continue;
          // END with

          // --------------------------------------------------
          // per phrase / switch / from - ensure player is in asset
          // --------------------------------------------------
          case "from":
            if (asset.id !== origin_asset.id) {
              this.game.debug(
                `D1216 | ${this.name}.js | ${player.id} is not ${asset.default_aspect} ${asset.id} `
              );
              msg += `$(We're) not ${asset.default_aspect} ${asset.articlename}. `;
              this.handleFailure(msg);
              return null;
            }
            if (input.getPreposition(i + 1) === "to")
              input.setVerbParam("fromto", true);
            continue;
          // END from

          // --------------------------------------------------
          // per phrase / switch / to - infer this asset to be destination
          // --------------------------------------------------
          case "to":
            if (asset.direction) {
              // additional direction checks come later
              continue;
            }

            if (origin_asset.id === asset.id) {
              // this duplicates go D1728
              this.game.debug(
                `D1237 | ${this.name}.js | ${player.id} is already ${origin_aspect.id} ${asset.id} `
              );
              msg += `$(We're) already ${origin_aspect.id} ${asset.articlename}. `;
              this.handleFailure(msg);
              return null;
              // END to
            }

            results = this.canPlayerGoFromThisToThat(origin_asset, asset);
            if (results.failure) {
              this.handleFailure(results.msg);
              return null;
            }
            verified_canPlayerGoFromThisToThat = true;
            destination_aspect = results.aspect;
            destination_asset = asset;

            if (input.getPreposition(i - 1) === "from") {
              input.setVerbParam("fromto", true);
            }
            input.setVerbParam("to", true);
            input.setVerbParam("destination_asset", destination_asset);
            input.setVerbParam("destination_aspect", destination_aspect);

            continue;
          // END to

          // --------------------------------------------------
          // per phrase / switch / through - look for direction or aspect
          // --------------------------------------------------
          case "through":
            if (!asset.direction && !asset.hasAspectAt(preposition)) {
              this.game.debug(
                `D1129 | ${this.name}.js | neither ${asset.id}.direction nor ${asset.id}.aspects.${preposition} are set `
              );
              msg += `$(We) can't ${input_verb.name} ${preposition} ${asset.articlename}. `;
              this.handleFailure(msg);
              return null;
            }
            input.setVerbParam("destination_asset", asset);
            input.setVerbParam("destination_preposition", "through");
            input.setVerbParam("through", true);
            destination_asset = asset;
            destination_preposition = "through";

            continue;
          // END through

          // --------------------------------------------------
          // per phrase / switch / off - ensure player on asset
          // --------------------------------------------------
          case "off":
            if (asset.id !== origin_asset.id || "on" !== origin_aspect.id) {
              this.game.debug(
                `D1132 | ${this.name}.js | ${player.id} is not on ${asset.id} `
              );
              msg += `$(We're) not on ${asset.articlename}. `;
              this.handleFailure(msg);
              return null;
            }
            continue;
          // END off

          // --------------------------------------------------
          // per phrase / switch / out - ensure player in asset
          // --------------------------------------------------
          case "out":
            if (asset.direction) {
              // additional direction checks come later
              continue;
            }
            // don't handle direction here because we check thoroughly later
            if (
              asset.id !== origin_asset.id ||
              !["on", "behind", "under", "in"].includes(origin_aspect.id)
            ) {
              this.game.debug(
                `D1116 | ${this.name}.js | ${player.id} is not in ${asset.id} `
              );
              msg += `$(We're) not in ${asset.articlename}. `;
              this.handleFailure(msg);
              return null;
            }
            continue;
          // END out

          // --------------------------------------------------
          // per phrase / switch / outfromunder - ensure player under asset
          // --------------------------------------------------
          case "outfromunder":
            if (asset.id !== origin_asset.id || "under" !== origin_aspect.id) {
              this.game.debug(
                `D1136 | ${this.name}.js | ${player.id} is not under ${asset.id} `
              );
              msg += `$(We're) not under ${asset.articlename}. `;
              this.handleFailure(msg);
              return null;
            }
            input.setVerbParam("outfromunder", true);
            input.setVerbParam("action", "unnest");
            input.setPreposition(i, "out");
            i === 1
              ? (preposition1 = "out")
              : i === 2
                ? (preposition2 = "out")
                : (preposition3 = "out");

            continue;
          // END outfromunder

          // --------------------------------------------------
          // per phrase / switch / outfrombehind - ensure player behind asset
          // --------------------------------------------------
          case "outfrombehind":
            if (asset.id !== origin_asset.id || "behind" !== origin_aspect.id) {
              this.game.debug(
                `D1000 | ${this.name}.js | ${player.id} is not behind ${asset.id} `
              );
              msg += `$(We're) not behind ${asset.articlename}. `;
              this.handleFailure(msg);
              return null;
            }
            input.setVerbParam("outfrombehind", true);
            input.setVerbParam("action", "unnest");
            input.setPreposition(i, "out");
            i === 1
              ? (preposition1 = "out")
              : i === 2
                ? (preposition2 = "out")
                : (preposition3 = "out");
            continue;
          // END outfrombehind

          // --------------------------------------------------
          // per phrase / switch / on - infer "get on thing" or "go somewhere on thing"
          // --------------------------------------------------
          case "on":
            // --------------------------------------------------
            // per phrase / switch / on / "get on thing"
            // --------------------------------------------------
            if (i === 1 || (i > 1 && !input.getAsset(i - 1).direction)) {
              let aspect = asset.getAspectAt(preposition);
              if (!aspect || !aspect.canPlayer("enter")) {
                this.game.debug(
                  `D1230 | ${this.name}.js | ${asset.id}.aspects.${preposition} is unset`
                );
                msg += `$(We) can't ${input_verb.name} ${preposition} ${asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END on
              }
              if (
                origin_asset.id === asset.id &&
                origin_aspect === preposition
              ) {
                this.game.debug(
                  `D1208 | ${this.name}.js | ${player.id} is already ${origin_aspect.id} ${origin_asset.id}`
                );
                msg += `$(We're) already ${origin_aspect.id} ${origin_asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END on
              }

              input.setVerbParam("destination_asset", asset);
              input.setVerbParam("destination_aspect", aspect);
              input.setVerbParam("on", true);
              input.setVerbParam(
                "action",
                origin_asset.hasClass("Room") ? "nest" : "renest"
              );
              destination_asset = asset;
              destination_aspect = aspect;
            }

            // --------------------------------------------------
            // per phrase / switch / on / "go direction on asset"
            // --------------------------------------------------
            // infer something like "go east on bike"
            // player should be already on asset
            else if (i > 1 && input.getAsset(i - 1).direction) {
              // --------------------------------------------------
              // per phrase / switch / on / "go direction on asset"
              //  - is asset also a direction?
              // --------------------------------------------------
              if (asset.direction) {
                // don't know how to "go east on east"
                this.game.debug(
                  `D1268 | ${this.name}.js | unable to parse ${input.getInput()}`
                );
                msg += `$(We) don't know how to ${input.getInput()}. `;
                this.handleFailure(msg);
                return null;
                // END on
              }

              // --------------------------------------------------
              // per phrase / switch / on / "go direction on asset"
              //  - is player on asset?
              // --------------------------------------------------
              if (origin_asset.id !== asset.id) {
                // player is not on thing
                this.game.debug(
                  `D1118 | ${this.name}.js | ${player.id} is not ${preposition} ${asset.id}`
                );
                msg += `$(We're) not ${preposition} ${asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END in
              }

              // --------------------------------------------------
              // per phrase / switch / on / "go direction on asset"
              //  - phrase is internally ok
              // --------------------------------------------------
              input.setVerbParam("tool_asset", asset);
              input.setVerbParam("tool_preposition", preposition);
              input.setVerbParam("tool_position", i);
              tool_asset = asset;
              tool_preposition = preposition;
              // allow handling to continue
            }

            // --------------------------------------------------
            // per phrase / switch / on / unparsable
            // --------------------------------------------------
            else {
              this.game.debug(
                `D1261 | ${this.name}.js | unable to parse ${input.getInput()}`
              );
              msg += `$(We) don't know how to ${input.getInput()}. `;
              this.handleFailure(msg);
              return null;
              // END on
            }

            continue;
          // END on

          // --------------------------------------------------
          // per phrase / switch / in
          //  - infer "get in thing" or "go somewhere in thing"
          // --------------------------------------------------
          case "in":
            // --------------------------------------------------
            // per phrase / switch / in
            //  - is asset an exit?
            // --------------------------------------------------
            if (asset.direction) {
              if (asset.direction !== "in") {
                this.game.debug(
                  `L1394 | ${this.name}.js | ${asset.id}.direction is not in`
                );
                msg += `$(We) can't ${input_verb.name} ${preposition} ${asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END in
              }
              continue;
            }

            // --------------------------------------------------
            // per phrase / switch / in / phrase1
            //  - does asset have enterable in aspect?
            // --------------------------------------------------
            else if (i === 1) {
              let aspect = asset.getAspectAt(preposition);
              if (!aspect || !aspect.canPlayer("enter")) {
                // does in mean on?
                if (asset.hasQuirk("in_means_on")) {
                  aspect = asset.getAspectAt(preposition);
                }
                if (!aspect || !aspect.canPlayer("enter")) {
                  this.game.debug(
                    `D1117 | ${this.name}.js | ${asset.id}.aspects.${preposition} is unset`
                  );
                  msg += `$(We) can't ${input_verb.name} ${preposition} ${asset.articlename}. `;
                  this.handleFailure(msg);
                  return null;
                  // END in
                }
              }

              // --------------------------------------------------
              // per phrase / switch / in / phrase1
              //  - is player already in asset?
              // --------------------------------------------------
              if (origin_asset.id === asset.id) {
                this.game.debug(
                  `D1175 | ${this.name}.js | ${player.id} is already ${origin_aspect.id} ${origin_asset.id}`
                );
                msg += `$(We're) already ${origin_aspect.id} ${origin_asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END in
              }

              // --------------------------------------------------
              // per phrase / switch / in / phrase1
              //  - phrase is internally ok
              // --------------------------------------------------
              input.setVerbParam("destination_asset", asset);
              input.setVerbParam("destination_aspect", aspect);
              input.setVerbParam(aspect.id, true);
              destination_asset = asset;
              destination_aspect = aspect;
              // allow handling to continue
            }

            // --------------------------------------------------
            // per phrase / switch / in / phrase > 1
            //  - "go direction in asset"
            // --------------------------------------------------
            // infer something like "go east in boat"
            // player should be already in asset
            else if (i > 1 && input.getAsset(i - 1).direction) {
              // --------------------------------------------------
              // per phrase / switch / in / phrase > 1
              //  - is asset a direction?
              // --------------------------------------------------
              if (asset.direction) {
                // are directions the same?
                // ex: go east in east passage
                if (asset.direction === input.getAsset(i - 1).direction) {
                  // just treat it like "go east"
                  input.deletePhrase(i);
                  continue;
                }

                this.game.debug(
                  `D1248 | ${this.name}.js | unable to parse ${input.getInput()}`
                );
                msg += `$(We) don't know how to ${input.getInput()}. `;
                this.handleFailure(msg);
                return null;
                // END in
              }

              // --------------------------------------------------
              // per phrase / switch / in / phrase > 1
              //  - is player in asset?
              // --------------------------------------------------
              if (origin_asset.id !== asset.id) {
                this.game.debug(
                  `D1161 | ${this.name}.js | ${player.id} is not ${preposition} ${asset.id}`
                );
                msg += `$(We're) not ${preposition} ${asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END in
              }

              // --------------------------------------------------
              // per phrase / switch / in / phrase > 1
              //  - phrase is internally ok
              // --------------------------------------------------
              input.setVerbParam("tool_asset", asset);
              input.setVerbParam("tool_preposition", preposition);
              input.setVerbParam("tool_position", i);
              tool_asset = asset;
              tool_preposition = preposition;
              // allow handling to continue
            }

            // --------------------------------------------------
            // per phrase / switch / in - unparsable
            // --------------------------------------------------
            else {
              this.game.debug(
                `D1253 | ${this.name}.js | unable to parse ${input.getInput()}`
              );
              msg += `$(We) don't know how to ${input.getInput()}. `;
              this.handleFailure(msg);
              return null;
              // END in
            }

            continue;
          // END in

          // --------------------------------------------------
          // per phrase / switch / under | behind
          // - infer "go behind thing" or "go somewhere under thing"
          // --------------------------------------------------
          case "under":
          case "behind":
            // --------------------------------------------------
            // per phrase / switch / "go under | behind thing"
            // --------------------------------------------------
            if (i === 1) {
              let aspect = asset.getAspectAt(preposition);

              // --------------------------------------------------
              // per phrase / switch / "go under | behind thing"
              //  - does asset have enterable aspect?
              // --------------------------------------------------
              if (!aspect || !aspect.canPlayer("enter")) {
                this.game.debug(
                  `D1212 | ${this.name}.js | ${asset.id}.aspects.${preposition} is unset`
                );
                msg += `$(We) can't ${input_verb.name} ${preposition} ${asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END under/behind
              }
              if (origin_asset.id === asset.id) {
                // --------------------------------------------------
                // per phrase / switch / "go under | behind thing"
                //  - is player already in aspect?
                // --------------------------------------------------
                if (origin_aspect.id === aspect.id) {
                  this.game.debug(
                    `D1213 | ${this.name}.js | ${player.id} is already ${origin_aspect.id} ${origin_asset.id}`
                  );
                  msg += `$(We're) already ${origin_aspect.id} ${origin_asset.articlename}. `;
                  this.handleFailure(msg);
                  return null;
                } // END under/behind

                // --------------------------------------------------
                // per phrase / switch / "go under | behind thing"
                //  - is player in another aspect of asset?
                // --------------------------------------------------
                if (origin_aspect.id !== aspect.id) {
                  this.game.debug(
                    `D1215 | ${this.name}.js | ${player.id} is ${origin_aspect.id} ${origin_asset.id}`
                  );
                  msg += `$(We) can't ${input_verb.name} ${aspect.id} ${asset.articlename} while $(we're) ${origin_aspect.id} it. `;
                  this.handleFailure(msg);
                  return null;
                } // END under/behind
              }

              // --------------------------------------------------
              // per phrase / switch / "go under | behind thing"
              //  - phrase is internally ok
              // --------------------------------------------------
              input.setVerbParam("destination_asset", asset);
              input.setVerbParam("destination_aspect", aspect);
              input.setVerbParam(aspect.id, true);
              input.setVerbParam("action", "nest");
              destination_asset = asset;
              destination_aspect = aspect;
              // allow handling to continue
            }

            // --------------------------------------------------
            // per phrase / switch / "go under | behind thing"
            //  - "go direction under asset"
            // --------------------------------------------------
            // if "under" is in second position, assume something like "go east under bridge"
            // else if (
            //   i === 2 &&
            //   input.getAsset(1).direction &&
            //   origin_asset.id !== asset.id
            // ) {
            //   this.game.debug(
            //     ` | ${this.name}.js | ${player.id} is not ${preposition} ${asset.id}`
            //   );
            //   msg += `$(We're) not ${preposition} ${asset.articlename}. `;
            //   this.handleFailure(msg);
            //   return null;
            // }

            continue;
          // END under/behind

          // --------------------------------------------------
          // per phrase / switch / down
          // --------------------------------------------------
          case "down":
            console.warn("Jo down");
            continue;
          // END down

          // --------------------------------------------------
          // per phrase / switch / up
          // --------------------------------------------------
          case "up":
            console.warn("Jo up");
            continue;
          // END up
        } // switch preposition
      } // per phrase

      // --------------------------------------------------
      // sentence structure: verb noun + direction
      // go east, go stairs, etc
      // --------------------------------------------------
      if (input.hasStructure("verb noun") && asset1.direction) {
        // is asset direction?
        // if we're here with asset1.direction corresponds to a preposition
        // - which includes up, down, in, out - it's only because player specified
        // an exit by name, so we don't need to account for climbing up/down nest asset
        // and we're going to punt to tryTravel, which has its own nest logic
        this.game.log(
          "L1391",
          "log",
          "high",
          `${this.name}.js > ${asset1.id}.direction is ${asset1.direction}, tryTravel ${asset1.direction}`,
          "Verbs"
        );
        return this.game.tryTravel(asset1.direction);
        // PASS TO: tryTravel
      } // END verb noun + direction

      // --------------------------------------------------
      // sentence structure: verb noun && !direction
      // go bed, climb tree etc
      // --------------------------------------------------
      if (input.hasStructure("verb noun") && !asset1.direction) {
        // --------------------------------------------------
        // sentence structure: verb noun && !direction
        //  - does asset have enterable aspect?
        // --------------------------------------------------

        // @TODO how to handle adverbs?
        if (adverb) {
          // around is an adverb
        }

        if (
          !asset1.default_aspect ||
          !asset1.aspects[asset1.default_aspect]?.canPlayer("enter")
        ) {
          this.game.debug(
            `D1270 | ${this.name}.js | 
            ${
              !asset1.default_aspect
                ? asset1.id + ".default_aspect is unset"
                : asset1.id +
                  ".aspects." +
                  asset1.default_aspect +
                  ".player.can.enter is unset"
            }`
          );
          // can't go to it, but can we even pretend to reach it?
          origin_asset.hasClass("Room") ||
          origin_asset.id === asset1.getPlaceAssetId()
            ? (msg += `$(We) edge a bit closer to ${asset1.articlename}. `)
            : (msg += `$(We) can't reach ${asset1.articlename} from ${origin_asset.hasClass("room") ? "here" : origin_asset.articlename}. `);
          this.handleFailure(msg);
          return null;
          // END
        }
      } // END verb noun && !direction

      // --------------------------------------------------
      // sentence structure: verb noun
      //  - verified that asset can be entered
      //  - is origin room?
      // --------------------------------------------------
      if (input.hasStructure("verb noun") && origin_asset.hasClass("Room")) {
        // --------------------------------------------------
        // sentence structure: verb noun / origin is room
        //  - success
        // --------------------------------------------------
        input.setPreposition(1, asset1.default_aspect);
        input.setVerbParam("destination_asset", asset1);
        input.setVerbParam(
          "destination_aspect",
          asset1.getAspectAt(asset1.default_aspect)
        );
        input.setVerbParam(asset1.default_aspect, true);
        input.setStructure("verb preposition noun");
        input.setVerbParam("action", "nest");
        return true; // PASS TO: doSuccess
      }

      // --------------------------------------------------
      // sentence structure: verb noun
      //  - verified that player is nested
      //  - is player going from one asset to another?
      // --------------------------------------------------
      if (input.hasStructure("verb noun") && origin_asset.id !== asset1.id) {
        results = this.canPlayerGoFromThisToThat(origin_asset, asset1);
        if (results.failure) {
          this.handleFailure(results.msg);
          return null;
        }
        // --------------------------------------------------
        // sentence structure: verb noun / renest
        //  - success
        // --------------------------------------------------
        input.swapPhrases(1, 2); // set destination in phrase 2
        input.setAsset(1, origin_asset); // set origin in phrase 1
        input.setPreposition(1, "from");
        input.setPreposition(2, "to");
        input.setStructure("verb preposition noun preposition noun");
        input.setVerbParam("fromto", true);
        input.setVerbParam("action", "renest");
        input.setVerbParam("destination_asset", results.asset);
        input.setVerbParam("destination_aspect", results.aspect);
        return true; // PASS TO: doSuccess
      }

      // --------------------------------------------------
      // sentence structure: verb noun
      //  - is repositioning implied?
      //  - ex: climb tree, descend rope
      // --------------------------------------------------
      if (
        input.hasStructure("verb noun") &&
        origin_asset.id === asset1.id &&
        input_verb.default_direction === "up"
      ) {
        // --------------------------------------------------
        // sentence structure: verb noun / reposition
        //  - can player go up?
        // --------------------------------------------------
        if (this.canPlayerRepositionUp(origin_asset, origin_aspect)) {
          // --------------------------------------------------
          // sentence structure: verb noun / reposition up
          //  - success
          // --------------------------------------------------
          input.setPreposition(1, "up");
          input.setStructure("verb preposition noun");
          input.setVerbParam("reposition_up", true);
          input.setVerbParam("action", "reposition");
          return true; // PASS TO: doSuccess
        } else {
          // can't go up
          this.game.debug(
            `D1126 | ${this.name}.js | ${player.id} is at top of ${origin_asset.id}`
          );
          msg += `$(We're) as high as $(we) can ${input_verb.name} ${origin_aspect.id} ${origin_asset.articlename}. `;
          this.handleFailure(msg);
          return null;
          // END
        }
      }

      // --------------------------------------------------
      // sentence structure: verb noun
      //  - can player climb down or get off?
      //  - ex: descend ladder
      // --------------------------------------------------
      if (
        input.hasStructure("verb noun") &&
        origin_asset.id === asset1.id &&
        ["down", "off", "out"].includes(input_verb.default_direction)
      ) {
        if (
          this.canPlayerRepositionDown(
            origin_asset,
            origin_aspect,
            "off" === input_verb.default_direction
          )
        ) {
          // --------------------------------------------------
          // sentence structure: verb noun / reposition down
          //  - success
          // --------------------------------------------------
          input.setPreposition(1, "down");
          input.setStructure("verb preposition noun");
          input.setVerbParam("action", "reposition");
          input.setVerbParam("reposition_down", true);
          return true; // pass to doSuccess
          // END down
        }

        // --------------------------------------------------
        // sentence structure: verb noun / unnest
        //  - can player get off?
        // --------------------------------------------------
        else if (
          origin_aspect.canPlayer(input_verb.name) &&
          origin_aspect.canPlayer("exit")
        ) {
          // --------------------------------------------------
          // sentence structure: verb noun / unnest
          //  - success
          // --------------------------------------------------
          input.setPreposition(1, "off");
          input.setStructure("verb preposition noun");
          input.setVerbParam("action", "unnest");
          input.setVerbParam("off", true);
          return true; // pass to doSuccess
        }

        // --------------------------------------------------
        // sentence structure: verb noun / unnest
        //  - failure
        // --------------------------------------------------
        else {
          this.game.debug(
            `D1511 | ${this.name}.js | ${player.id} can't ${input_verb.name} ${preposition1} ${origin_asset.id}`
          );
          msg += `$(We) don't know how to ${input_verb.name} ${origin_aspect.id} ${origin_asset.articlename}. `;
          this.handleFailure(msg);
          return null;
          // END
        }
      }

      // --------------------------------------------------
      // sentence structure: verb noun
      //  - unparsable
      // --------------------------------------------------
      if (input.hasStructure("verb noun") && origin_asset.id === asset1.id) {
        this.game.debug(
          `D1125 | ${this.name}.js | ${player.id} is already ${origin_aspect.id} ${origin_asset.id}`
        );
        msg += `$(We're) already ${origin_aspect.id} ${origin_asset.articlename}. `;
        this.handleFailure(msg);
        return null;
        // END
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - verify preposition and noun
      // --------------------------------------------------
      if (input.hasStructure("verb preposition noun") && asset1.direction) {
        // --------------------------------------------------
        // sentence structure: verb preposition noun
        //  - does preposition match direction?
        // --------------------------------------------------
        if (
          (asset1.direction === "down" &&
            ["through", "in", "down"].includes(preposition1)) ||
          (asset1.direction === "up" &&
            ["through", "out", "up"].includes(preposition1)) ||
          (asset1.direction === "in" &&
            ["through", "in"].includes(preposition1)) ||
          (asset1.direction === "out" &&
            ["through", "out"].includes(preposition1)) ||
          (asset1.direction !== "in" &&
            ["through", "out"].includes(preposition1)) ||
          (asset1.direction !== "out" &&
            ["through", "in"].includes(preposition1)) ||
          ["through", "to"].includes(preposition1)
        ) {
          this.game.log(
            "L1393",
            "log",
            "high",
            `${this.name}.js > ${asset1.id}.direction is ${asset1.direction}, tryTravel ${asset1.direction}`,
            "Verbs"
          );
          return this.game.tryTravel(asset1.direction);
          // PASS TO: tryTravel
          // END
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun
        //  - fail
        // --------------------------------------------------
        this.game.debug(
          `D1375 | ${this.name}.js | ${preposition1} ${asset1.id} not understood `
        );
        msg += `$(We're) not sure how to ${input_verb.name} ${preposition1} ${asset1.articlename}. `;
        this.handleFailure(msg);
        return null;
        // END
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun / from
      //  - verified player is nested on noun in per phrase
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        "from" === preposition1
      ) {
        // --------------------------------------------------
        // sentence structure: verb preposition noun / from
        //  - can player reposition down?
        // --------------------------------------------------
        if (this.canPlayerRepositionDown(origin_asset, origin_aspect)) {
          // --------------------------------------------------
          // sentence structure: verb preposition noun / from / reposition_down
          //  - success
          // --------------------------------------------------
          input.setVerbParam("action", "reposition");
          input.setVerbParam("reposition_down", true);
          return true; // PASS TO: doSuccess
          // END from
        } else {
          // --------------------------------------------------
          // sentence structure: verb preposition noun / from / off
          //  - can player exit asset?
          // --------------------------------------------------
          if (!origin_aspect.canPlayer("exit")) {
            this.game.debug(
              `D1308 | ${this.name}.js | ${origin_asset.id}.aspects.${origin_aspect.id}.player.can.exit is false `
            );
            msg += `$(We) can't get ${input_verb.name} from ${origin_asset.articlename}. `;
            this.handleFailure(msg);
            return null;
            // END down
          }

          // --------------------------------------------------
          // sentence structure: verb preposition noun / from / off
          //  - success
          // --------------------------------------------------
          input.setPreposition(1, "off");
          input.setVerbParam("off", true);
          input.setVerbParam("action", "unnest");
          return true; // PASS TO: doSuccess
          // END from
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun / with
      // - ex: fly with jetpack, climb with piton
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        "with" === preposition1
      ) {
        // --------------------------------------------------
        // sentence structure: verb preposition noun / with
        //  - is asset direct object of verb?
        //  - ex: fly with jetpack
        // --------------------------------------------------
        if (asset1.isDOV(input_verb.name)) {
          // --------------------------------------------------
          // sentence structure: verb preposition noun / with / dov
          //  - DOV with no IOV is equivalent to "use asset"
          //  - success
          // --------------------------------------------------
          input.setVerbParam("with", true);
          input.setVerbParam("action", "none");
          return true; // PASS TO: doSuccess
          // END
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun / with / iov
        //  - is asset indirect object of verb?
        //  - ex: climb with piton
        // --------------------------------------------------
        else if (asset1.isIOV(input_verb.name)) {
          // --------------------------------------------------
          // sentence structure: verb preposition noun / with / iov
          //  - is origin direct object of verb?
          //  - can player do verb in aspect?
          // --------------------------------------------------
          if (
            !origin_asset.isDOV(input_verb.name) ||
            !origin_aspect.playerCan(input_verb.name)
          ) {
            this.game.debug(
              `D1312 | ${this.name}.js | ${origin_asset.id}.dov.${input_verb.name} or ${origin_asset.id}.aspects.${origin_aspect.id}.player.can.${input_verb.name} is unset`
            );
            msg += `$(We) can't ${input_verb.name} ${origin_asset.articlename} ${preposition1} ${asset1.articlename}. `;
            this.handleFailure(msg);
            return null;
            // END
          }

          // we're inferring player to mean "verb origin with asset"
          // ex: climb cliff with piton
          results = this.canPlayerUseThisWithThat(
            origin_aspect.id,
            origin_asset,
            asset1
          );
          if (results.failure) {
            this.handleFailure(results.msg);
            return null;
            // END
          }

          // what's our preposition?
          preposition2 = input_verb.default_direction
            ? input_verb.default_direction
            : origin_aspect.id;

          // is preposition up/down/off?
          switch (preposition2) {
            case "up":
              if (!this.canPlayerRepositionUp(origin_asset, origin_aspect)) {
                this.game.debug(
                  `D1316 | ${this.name}.js | ${origin_asset.id}.aspects.${origin_aspect.id}.player.can.scale is false `
                );
                msg += `$(We) can't ${input_verb.name} any higher on ${origin_asset.articlename}. `;
                this.handleFailure(msg);
                return null;
                // END
              }
              break;
            case "down":
            case "off":
              preposition2 = this.canPlayerRepositionDown(
                origin_asset,
                origin_aspect,
                true
              )
                ? "down"
                : "off";
              break;
            default:
              this.game.debug(
                `D1318 | ${this.name}.js | ${input_verb.name} ${preposition1} ${asset1.id} is unhandled`
              );
              msg += `$(We're) not sure how to ${input_verb.name} ${preposition1} ${asset1.articlename}. `;
              this.handleFailure(msg);
              return null;
            // END
          }

          // second check - is preposition off?
          if (preposition2 === "off" && !origin_aspect.playerCan("exit")) {
            this.game.debug(
              `D1123 | ${this.name}.js | ${origin_asset.id}.aspects.${origin_aspect.id}.player.can.exit is unset`
            );
            msg += `$(We) can't ${input_verb.name} off ${origin_asset.articlename} ${preposition1} ${asset1.articlename}. `;
            this.handleFailure(msg);
            return null;
            // END
          }

          switch (preposition2) {
            case "down":
              input.setVerbParam("reposition_down", true);
              input.setVerbParam("action", "reposition");
              break;
            case "up":
              input.setVerbParam("reposition_up", true);
              input.setVerbParam("action", "reposition");
              break;
            case "off":
              input.setVerbParam("action", "unnest");
              break;
            default:
              // input.setVerbParam("action", "none");
              // break;
              this.game.debug(
                `D1317 | ${this.name}.js | ${input_verb.name} ${preposition1} ${asset1.id} not handled`
              );
              msg += `$(We) don't know how to ${input_verb.name} ${preposition1} ${asset1.articlename}. `;
              this.handleFailure(msg);
              return null;
            // END
          }

          // --------------------------------------------------
          // sentence structure: verb preposition noun / with
          //  - success
          // --------------------------------------------------
          input.setPreposition(2, preposition2);
          input.setAsset(2, origin_asset);
          input.swapPhrases(1, 2); // move tool_asset to phrase 2
          input.setStructure("verb preposition noun preposition noun");
          input.setVerbParam("with", true);
          return true; // PASS TO: doSuccess
          // END
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun / with
        //  - asset is not object of verb
        // --------------------------------------------------
        else {
          this.game.debug(
            `D1282 | ${this.name}.js | neither ${asset1.id}.dov.${input_verb.name} nor ${asset1.id}.iov.${input_verb.name} is set`
          );
          msg += `$(We) can't ${input_verb.name} ${preposition1} ${asset1.articlename}. `;
          this.handleFailure(msg);
          return null;
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - to
      //  - already verified that to maps to a valid aspect
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        preposition1 === "to"
      ) {
        // --------------------------------------------------
        // sentence structure: verb preposition noun / to
        //  - is player unnested?
        //  - if so we're just getting [on] asset
        // --------------------------------------------------
        if (origin_asset.hasClass("Room")) {
          input.setVerbParam("action", "nest");
          return true; // PASS TO: doSuccess
          // END
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun / to
        //  - is player nested?
        //  - raise the information level to "go from a to b"
        // --------------------------------------------------
        else if (!origin_asset.hasClass("Room")) {
          results = this.canPlayerGoFromThisToThat(origin_asset, asset1);
          if (results.failure) {
            this.handleFailure(results.msg);
            return null;
          }
          // --------------------------------------------------
          // sentence structure: verb preposition noun / to
          //  - success
          // --------------------------------------------------
          input.setPreposition(2, "from");
          input.setAsset(2, origin_asset);
          input.swapPhrases(1, 2);
          input.setStructure("verb preposition noun preposition noun");
          input.setVerbParam("fromto", true);
          input.setVerbParam("action", "renest");
          return true; // PASS TO: doSuccess
          // END
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - off or out of room
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        ["off", "out"].includes(preposition1) &&
        asset1.id === current_room.id
      ) {
        // --------------------------------------------------
        // is player trying to leave the room while nested?
        // for example: "get off bus" while seated
        // @TODO automatically unnest
        // --------------------------------------------------
        if (
          current_room.aspects.in.canPlayer("exit") &&
          origin_asset.id !== current_room.id
        ) {
          this.game.debug(`D1003 | ${this.name}.js | player.isNested`);
          msg += `$(We) can't do that from $(our) position ${player.getPostureGerund()} ${origin_aspect.id} ${
            origin_asset.articlename
          }. `;
          this.handleFailure(msg);
          return null;
          // END
        }

        // --------------------------------------------------
        // is player trying to leave the room while on the floor?
        // for example: "get off bus" while lying down
        // @TODO automatically have player get up
        // --------------------------------------------------
        if (current_room.aspects.in.canPlayer("exit") && player.isOnFloor()) {
          this.game.debug(`D1004 | ${this.name}.js | player.isOnFloor `);
          msg += `$(We) can't do that from $(our) position ${player.getPostureGerund()} on the floor. `;
          this.handleFailure(msg);
          return null;
          // END
        }

        // --------------------------------------------------
        // is player trying to leave the room?
        // for example: "get off bus"
        // redirect to exit verb
        // --------------------------------------------------
        if (
          current_room.aspects.in.canPlayer("exit") &&
          this.game.hasVerb("exit")
        ) {
          this.game.log(
            "L1395",
            "log",
            "high",
            `${this.name}.js > ${asset1.id}.player_can_exit, doVerb exit`,
            "Verbs"
          );
          return this.game.dictionary.doVerb("exit");
          // PASS TO: exit
          // END
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - off or out of asset
      //  - this block overlaps per-phrase checks
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        ["off", "out"].includes(preposition1) &&
        asset1.id !== current_room.id
      ) {
        let prep = "";
        let prep_match = false;

        // if off, is player on asset1?
        if ("off" === preposition1) {
          prep = "on";
          if (origin_aspect.id === "on") prep_match = true;
        }

        // if out from under, is player under asset1?
        if (input.getVerbParam("outfromunder")) {
          prep = "under";
          if (origin_aspect.id === prep) prep_match = true;
        }

        // if out from behind, is player behind asset1?
        else if (input.getVerbParam("outfrombehind")) {
          prep = "behind";
          if (origin_aspect.id === prep) prep_match = true;
        }

        // if out, is player in asset1?
        else if ("out" === preposition1) {
          prep = "in";
          if (origin_aspect.id === prep) prep_match = true;

          // does in mean on for this item? (like "in bed")
          if (
            !prep_match &&
            origin_aspect.id === "on" &&
            origin_asset.hasQuirk("in_means_on")
          ) {
            prep = "on";
            prep_match = true;
          }

          // if out, is player under? we'll allow it
          if (!prep_match && origin_aspect.id === "under") {
            prep = "under";
            prep_match = true;
          }

          // if out, is player behind? we'll allow it
          if (!prep_match && origin_aspect.id === "behind") {
            prep = "behind";
            prep_match = true;
          }
        }

        // is player not on/in/under/behind direct object?
        if (origin_asset.id !== asset1.id || !prep_match) {
          this.game.debug(
            `D1045 | ${this.name}.js | player not ${prep} ${asset1.id} `
          );
          msg += `$(We're) not ${prep} ${asset1.articlename}. `;
          this.handleFailure(msg);
          return null;
          // END
        }

        // is player prevented from exiting the object?
        if (!origin_aspect.canPlayer("exit")) {
          this.game.debug(
            `D1002 | ${this.name}.js | ${asset1.id}.aspects.${origin_aspect.id}.player.can.exit is false`
          );
          msg += `$(We) can't ${input_verb.name} ${player.getPrettyUnnestPreposition()} ${asset1.articlename}. `;
          this.handleFailure(msg);
          return null;
          // END
        }

        // did player use wrong preposition
        // or we transmogrified it?
        let unnest_prep = player.getUnnestPreposition();
        if (preposition1 !== unnest_prep) {
          preposition1 = unnest_prep;
          input.setPreposition(1, preposition1);
          input.setVerbParam(preposition1, true);
        }
        input.setVerbParam("action", "unnest");
        // CONTINUE WITH: verb preposition noun
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - off, but should it be down?
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        "off" === preposition1
      ) {
        if (
          this.canPlayerRepositionDown(
            player,
            origin_asset,
            origin_aspect,
            input_verb,
            true
          )
        ) {
          input.setPreposition(1, "down");
          input.setVerbParam("reposition_down", true);
          input.setVerbParam("action", "reposition");
          return true; // pass to doSuccess
          // END off
        }
      } // preposition1 is off

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - from origin_asset to asset1
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        origin_asset.id !== asset1.id &&
        !origin_asset.hasClass("Room")
      ) {
        results = this.canPlayerGoFromThisToThat(origin_asset, asset1);
        if (results.failure) {
          this.handleFailure(results.msg);
          return null;
        }
        destination_asset = asset1;
        destination_aspect = asset1.getAspectAt(preposition1) || results.aspect;

        // // this block is left over from version that prevented travel while nested
        // // @todo add reachability check
        // this.game.debug(
        //   ` | ${this.name}.js | player.isNested ${origin_aspect.id} ${origin_asset.id}`
        // );
        // msg += `$(We) can't do that from $(our) position ${player.getPostureGerund()} ${origin_aspect.id} ${
        //   origin_asset.articlename
        // }. `;
        // this.handleFailure(msg);
        // return null;

        // upgrade to "go from a to b"
        input.swapPhrases(1, 2);
        input.setAsset(1, origin_asset);
        input.setPreposition(1, "from");
        input.setPreposition(2, "to");
        asset1 = input.getAsset(1);
        preposition1 = input.getPreposition(1);
        asset2 = input.getAsset(2);
        preposition2 = input.getPreposition(2);
        input.setVerbParam("destination_asset", destination_asset);
        input.setVerbParam("destination_aspect", destination_aspect);
        input.setStructure("verb preposition noun preposition noun");
        input.setVerbParam("fromto", true);
        input.setVerbParam("action", "renest");
        return true;
        // PASS TO: doSuccess
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - on, but but should it be up?
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        "on" === preposition1
      ) {
        const aspect = asset1.aspects.on;
        if (origin_aspect.UID === aspect.UID) {
          // player is already on asset
          const dir = input_verb.default_direction || "up";
          console.warn({ preposition1, dir });
          preposition1 = dir;
          input.setPreposition(1, dir);
          input.setVerbParam(dir, true);
          // no return - allow to be handled by "up" catch
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - up, but should it be on?
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        "up" === preposition1
      ) {
        const aspect = asset1.aspects.on;
        if (origin_aspect.UID !== aspect.UID) {
          // player is not on asset yet
          preposition1 = "on";
          input.setPreposition(1, "on");
          input.setVerbParam("on", true);
          input.setVerbParam("action", "nest");
          // no return - allow to be handled by "on" catch
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - on
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        "on" === preposition1
      ) {
        const aspect = asset1.aspects.on;
        input.setVerbParam("on", true);
        input.setVerbParam("action", "nest");
        input.setVerbParam("destination_asset", asset1);
        input.setVerbParam("destination_aspect", aspect);

        // CONTINUE WITH: verb preposition noun

        // @TODO what are we doing here?
        // climb in increments or climb directly to top?
        // const aspect = direct_object.aspects.on;
        // player is already on this aspect
        // if (
        //   aspect.canPlayer("scale") &&
        //   aspect.scale_increment > 0 &&
        //   aspect.scale_increment < direct_object.getHeight()
        // ) {
        //   // climb up in increments
        //   input.setPreposition(1, "up");
        //   direct_preposition = "up";
        //   input.setVerbParam("reposition_up", true);
        //   input.setVerbParam("action", "reposition");
        // } else {
        //   // climb to top
        //   input.setPreposition(1, "on");
        //   direct_preposition = "on";
        //   input.setVerbParam("on", true);
        //   input.setVerbParam(
        //     "action",
        //     nest_aspect.UID === aspect.UID ? "reposition" : "nest"
        //   );
        // }
        // CONTINUE WITH: verb preposition noun
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - up
      // --------------------------------------------------
      // already verified that player is on asset
      if (
        input.hasStructure("verb preposition noun") &&
        preposition1 === "up"
      ) {
        // climb in increments or climb directly to top?
        const aspect = asset1.aspects.on;
        // can aspect be climbed in increments?
        if (this.canPlayerRepositionUp(asset1, aspect)) {
          // climb up in increments
          input.setPreposition(1, "up");
          preposition1 = "up";
          input.setVerbParam("reposition_up", true);
          input.setVerbParam("action", "reposition");
          // @TODO should this return true?
          // } else if (
          //   player.getY() < asset1.getYTop() &&
          //   aspect.canPlayer("scale")
          // ) {
          //   // climb to top
          //   input.setPreposition(1, "up");
          //   preposition1 = "up";
          //   input.setVerbParam("reposition_top", true);
          //   input.setVerbParam("action", "reposition");
          //   // @TODO should this return true?
        } else {
          // can't get any higher
          this.game.debug(
            `D1274 | ${this.name}.js | player can't go higher on ${asset1.id} `
          );
          msg += `$(We) can't ${input_verb.name} any higher on ${asset1.articlename}. `;
          this.handleFailure(msg);
          return null;
        }
        // CONTINUE WITH: verb preposition noun
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - down
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        "down" === preposition1
      ) {
        // --------------------------------------------------
        // sentence structure: verb preposition noun / down
        //  - can player go down asset1 from current position?
        // --------------------------------------------------
        if (origin_asset.id !== asset1.id) {
          // is dobj lower than player?
          if (player.getY() > asset1.getY()) {
            // @TODO player should be able to climb down things
            // below ground level (classic ex: a ladder in a pit)
          }
          this.game.debug(
            `D1244 | ${this.name}.js | player not nested on ${asset1.id} `
          );
          msg += `$(We're) not on ${asset1.articlename}. `;
          this.handleFailure(msg);
          return null;
        }
        // if (origin_asset.id !== asset1.id && !origin_asset.hasClass("Room")) {
        //   // @TODO fromto?
        // }
        // if (origin_asset.hasClass("Room")) {
        //   // @TODO can player climb down?
        //   // ex: ladder in a hole in the ground
        // }
        // // CONTINUE WITH: verb preposition noun

        // --------------------------------------------------
        // sentence structure: verb preposition noun / down
        //  - can player go down on origin?
        // --------------------------------------------------
        if (origin_asset.id === asset1.id) {
          if (this.canPlayerRepositionDown(origin_asset, origin_aspect)) {
            // climb down in increments
            input.setVerbParam("action", "reposition");
            input.setVerbParam("reposition_down", true);
            return true; // PASS TO: doSuccess
            // END down
          }
          // --------------------------------------------------
          // sentence structure: verb preposition noun / down
          //  - get off
          // --------------------------------------------------
          else {
            input.setPreposition(1, "off");
            input.setVerbParam("off", true);
            input.setVerbParam("action", "unnest");
            return true; // PASS TO: doSuccess
            // END down
          }
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - misc situations
      // --------------------------------------------------
      if (input.hasStructure("verb preposition noun")) {
        // --------------------------------------------------
        // sentence structure: verb preposition noun
        //  - is player on floor?
        //  - @TODO just get off the floor automatically?
        // --------------------------------------------------
        if (origin_asset.hasClass("Room") && player.isOnFloor()) {
          this.game.debug(`D1006 | ${this.name}.js | player.isOnFloor `);
          msg += `$(We) can't do that from $(our) position ${player.getPostureGerund()} on the floor. `;
          this.handleFailure(msg);
          return null;
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun
        //  - is player already nested within target?
        // --------------------------------------------------
        if (
          (asset1.id === origin_asset.id &&
            preposition1 === origin_aspect.id) ||
          (origin_asset.hasClass("Room") && asset1 instanceof adventurejs.Floor)
        ) {
          if (input_verb.hasStructure("verb")) {
            this.game.log(
              "L1388",
              "log",
              "high",
              `${this.name}.js > player is already ${
                asset1.id === origin_asset.id
                  ? origin_aspect.id + " " + origin_asset.id
                  : "on the floor"
              }\ninferring sentence structure "verb"`,
              "verbs"
            );
            input.setStructure("verb");
            input.setVerbParam("action", "none");
            return true;
          }

          this.game.debug(
            `D1007 | ${this.name}.js | player is already ${
              asset1.id === origin_asset.id
                ? "nested " + origin_aspect.id + " " + origin_asset.id
                : "on the floor"
            } `
          );
          msg += `$(We're) already ${
            origin_aspect ? origin_aspect.id : asset1.default_aspect
          } ${asset1.articlename}. `;
          this.handleFailure(msg);
          return null;
        }
      } // verb preposition noun

      // --------------------------------------------------
      // sentence structure: verb preposition noun
      //  - not off or out or up or down
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun") &&
        !["off", "out", "up", "down"].includes(preposition1)
      ) {
        // --------------------------------------------------
        // sentence structure: verb preposition noun
        //  - does player need to unnest from other aspect of target?
        //  - @TODO do this automatically?
        // --------------------------------------------------
        if (
          asset1.id === origin_asset.id &&
          preposition1 !== origin_aspect.id
        ) {
          this.game.debug(
            `D1008 | ${this.name}.js | player.is ${origin_aspect.id} ${origin_asset.id} not ${preposition1}`
          );
          msg += `$(We) can't do that from $(our) position ${player.getPostureGerund()} ${origin_aspect.id} ${
            origin_asset.articlename
          }. `;
          this.handleFailure(msg);
          return null;
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun
        //  - does asset have specified aspect?
        // --------------------------------------------------
        if (!asset1.hasAspectAt(preposition1)) {
          this.game.debug(
            `D1009 | ${this.name}.js | ${asset1.id}.aspects.${preposition1} is undefined`
          );
          msg += `$(We) can't ${input_verb.name} ${preposition1} ${asset1.articlename}. `;
          this.handleFailure(msg);
          return null;
        }

        // --------------------------------------------------
        // sentence structure: verb preposition noun
        //  - can player enter specified aspect?
        // --------------------------------------------------
        if (!asset1.aspects[preposition1].canPlayer("enter")) {
          this.game.debug(
            `D1005 | ${this.name}.js | ${asset1.id}.aspects.${preposition1}.player.can.enter is false`
          );
          msg += `$(We) can't ${input_verb.name} ${preposition1} ${asset1.articlename}. `;
          this.handleFailure(msg);
          return null;
        }
      } // verb preposition noun / not off or out or up or down

      // --------------------------------------------------
      // if we haven't eliminated verb preposition noun
      // then we should be good to go as is
      // pass to doSuccess
      // --------------------------------------------------
      if (input.hasStructure("verb preposition noun")) {
        return true;
      }

      // --------------------------------------------------
      // sentence structure: verb noun preposition noun
      //  - can we handle the preposition?
      // --------------------------------------------------
      if (
        input.hasStructure("verb noun preposition noun") &&
        !["with", "in", "on", "through"].includes(preposition2)
      ) {
        this.game.debug(`D1867 | ${this.name}.js | irregular phrase `);
        // msg += this.game.parser.getUnparsedMessage(input.getInput());
        msg += `$(We) can't ${input_verb.name} ${preposition2} ${asset2.articlename}. `;
        this.handleFailure(msg);
        return null;
      }

      // --------------------------------------------------
      // sentence structure: verb noun preposition noun
      //  - is asset1 a direction?
      //  - ex: go east on bridge, go east on bike
      // --------------------------------------------------
      if (
        input.hasStructure("verb noun preposition noun") &&
        asset1.direction
      ) {
        let allow_travel = false;

        // --------------------------------------------------
        // sentence structure: verb noun preposition noun / direction
        //  - is asset2 a vehicle?
        // --------------------------------------------------
        if (asset2.hasClass("Vehicle")) {
          // --------------------------------------------------
          // sentence structure: verb noun preposition noun / direction / vehicle
          //  - is player on the vehicle?
          // --------------------------------------------------
          if (origin_asset.id !== asset2.id) {
            this.game.debug(
              `D1042 | ${this.name}.js | player is not on ${asset2.name} `
            );
            msg += `$(We're) not on ${asset2.articlename}. `;
            this.handleFailure(msg);
            return null;
            // @TODO automatically get on bike
          }
          // else ok
          allow_travel = true;
        }

        // --------------------------------------------------
        // sentence structure: verb noun preposition noun / direction
        //  - is asset2 equivalent to asset1?
        //  - ex: go east through east passage
        // --------------------------------------------------
        else if (asset1.direction === asset2.direction) {
          allow_travel = true;
        }

        if (allow_travel) {
          // --------------------------------------------------
          // sentence structure: verb noun preposition noun / direction
          //  - success
          // --------------------------------------------------
          return this.game.tryTravel(
            asset1.direction,
            asset2.direction ? {} : { with: [asset2.id] }
          ); // PASS TO: tryTravel
          // END
        } else {
          // --------------------------------------------------
          // sentence structure: verb noun preposition noun / direction
          //  - failure
          // --------------------------------------------------
          this.game.debug(`D1871 | ${this.name}.js | irregular phrase `);
          // msg += this.game.parser.getUnparsedMessage(input.getInput());
          msg += `$(We) can't ${input_verb.name} ${asset1.direction} ${preposition2} ${asset2.articlename}. `;
          this.handleFailure(msg);
          return null;
          // END
        }
        // are there any other valid uses for verb noun preposition noun?
        // ex: go east under bridge?
      } // verb noun preposition noun + asset1 direction

      // --------------------------------------------------
      // sentence structure: verb noun preposition noun
      //  - does input verb have a default direction?
      //  - ex: climb [up] tree, descend [down] tree
      // --------------------------------------------------
      if (
        input.hasStructure("verb noun preposition noun") &&
        !asset1.direction
      ) {
        if (input_verb.default_direction) {
          preposition1 = input_verb.default_direction;
          input.setPreposition(1, preposition1);
          input.setStructure("verb preposition noun preposition noun");
          // PASS TO: verb preposition noun preposition noun
        }
      } // verb noun preposition noun

      // --------------------------------------------------
      // sentence structure: verb noun preposition noun
      //  - can we get a preposition?
      // --------------------------------------------------
      if (input.hasStructure("verb noun preposition noun")) {
        if (
          asset1.getAspectAt(asset1.default_aspect) &&
          asset1.getAspectAt(asset1.default_aspect).player.can.enter
        ) {
          preposition1 = asset1.default_aspect;
          input.setPreposition(1, preposition1);
          input.setStructure("verb preposition noun preposition noun");
          // PASS TO: verb preposition noun preposition noun
        }
      } // verb noun preposition noun

      // --------------------------------------------------
      // still verb noun preposition noun?
      //  - we don't know how to handle it
      // --------------------------------------------------
      if (input.hasStructure("verb noun preposition noun")) {
        this.game.debug(
          `D1325 | ${this.name}.js | "${input.getInput()}" isn't handled by go.js `
        );
        msg += `$(We) don't know how to ${input.getInput()}. `;
        this.handleFailure(msg);
        return null;
        // END
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun preposition noun
      // sentence structure: verb preposition noun preposition noun preposition noun
      // - can player use tool and reach destination?
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun preposition noun") ||
        input.hasStructure(
          "verb preposition noun preposition noun preposition noun"
        )
      ) {
        let asset = destination_asset ? destination_asset : origin_asset;
        let aspect = destination_aspect ? destination_aspect : origin_aspect;

        console.warn("FROMTO?", input.getVerbParam("fromto"));

        // --------------------------------------------------
        // - can tool asset be used?
        // - is this redundant to per-phrase checks?
        // --------------------------------------------------
        if (tool_asset) {
          results = this.canPlayerUseThisWithThat(aspect.id, asset, tool_asset);
          if (results.failure) {
            this.handleFailure(results.msg);
            return null;
            // END
          }
        }

        // --------------------------------------------------
        // - can player reach destination?
        // --------------------------------------------------
        if (destination_asset) {
          results = this.canPlayerGoFromThisToThat(
            origin_asset,
            destination_asset
          );
          if (results.failure) {
            this.handleFailure(results.msg);
            return null;
            // END
          }
          verified_canPlayerGoFromThisToThat = true;
        }
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun preposition noun
      // preposition: with
      // --------------------------------------------------
      // ex: climb up cliff with piton, climb up cliff with rope
      if (
        input.hasStructure("verb preposition noun preposition noun") &&
        "with" === preposition2
      ) {
        // is player nested?
        if (!origin_asset.hasClass("Room") && origin_asset.id !== asset1.id) {
          input.swapPhrases(2, 3);
          input.swapPhrases(1, 2);
          input.setAsset(1, origin_asset);
          input.setPreposition(1, "from");
          input.setVerbParam("fromto", true);
          input.setStructure(
            "verb preposition noun preposition noun preposition noun"
          );
          input.setVerbParam("action", "renest");
        }
        return true; // PASS TO: doSuccess
      } // with

      // --------------------------------------------------
      // sentence structure: verb preposition noun preposition noun
      //  - preposition: from to
      //  - ex: go from bed to bath
      // --------------------------------------------------
      if (
        input.hasStructure("verb preposition noun preposition noun") &&
        input.getVerbParam("fromto")
      ) {
        // we should have already checked all the things
        input.setVerbParam("action", "renest");
        return true;
        // PASS TO: doSuccess
      } // verb preposition noun preposition noun

      // --------------------------------------------------
      // still verb preposition noun preposition noun?
      //  - we don't know how to handle it
      // --------------------------------------------------
      if (input.hasStructure("verb preposition noun preposition noun")) {
        this.game.debug(
          `D1328 | ${this.name}.js | "${input.getInput()}" isn't handled by go.js `
        );
        msg += `$(We) don't know how to ${input.getInput()}. `;
        this.handleFailure(msg);
        return null;
        // END
      }

      // --------------------------------------------------
      // sentence structure: verb preposition noun preposition noun preposition noun
      //  - ex: climb from ramp to ledge with grapple
      //  - ex: climb from branch to window with rope
      // --------------------------------------------------

      if (
        input.hasStructure(
          "verb preposition noun preposition noun preposition noun"
        )
      ) {
        if (input.getVerbParam("fromto") && input.getVerbParam("with")) {
          // we should have already checked all the things
          input.setVerbParam("action", "renest");
          return true; // PASS TO: doSuccess
          // END
        }
      }

      // --------------------------------------------------
      // otherwise it's unrecognized
      // --------------------------------------------------
      this.game.debug(
        `D1279 | ${this.name}.js | "${input.getInput()}" isn't handled by go.js `
      );
      msg += `$(We) don't know how to ${input.getInput()}. `;
      this.handleFailure(msg);
      return null;

      // return true;
    }, // END doTry

    doSuccess: function () {
      const input = this.game.getInput();
      const input_verb = this.game.dictionary.getVerb(input.input_verb);
      const adverb = input.getAdverb();
      const player = this.game.getPlayer();
      const current_room = this.game.getCurrentRoom();

      const origin_asset = input.getVerbParam("origin_asset");
      const origin_aspect = input.getVerbParam("origin_aspect");

      const destination_asset = input.getVerbParam("destination_asset");
      const destination_aspect = input.getVerbParam("destination_aspect");

      const tool_asset = input.getVerbParam("tool_asset");
      const tool_preposition = input.getVerbParam("tool_preposition");
      const tool_string = tool_asset ? `use ${tool_asset.articlename} to` : "";

      const none = input.getVerbParam("action", "none");
      const action = input.getVerbParam("action");
      const repositioning = action === "reposition";
      const exiting = action === "unnest" || action === "renest";
      const entering = action === "nest" || action === "renest";

      const fromto = input.getVerbParam("fromto");

      const reposition_up = input.getVerbParam("reposition_up");
      const reposition_down = input.getVerbParam("reposition_down");
      const reposition_top = input.getVerbParam("reposition_top");
      const reposition_bottom = input.getVerbParam("reposition_bottom");

      let reposition_percent_string = "";
      let reposition_percent = 100;

      // if player input something like "go bed" change to "get on bed"
      // otherwise use the verb that was given
      const get_off = exiting
        ? input_verb.name === "go"
          ? "get"
          : input_verb.name
        : false;

      const get_on = entering
        ? input_verb.name === "go"
          ? "get"
          : input_verb.name
        : false;

      let mount_up;
      let mount_down;
      let mount_percent;
      let mount_percent_string = "";

      let msg = "";
      let results;
      let newY = 0;
      let posture;
      let posture_string = "";

      this.game.log(
        "L1398",
        "log",
        "high",
        `${this.name}.js > 
       sentence structure: ${input.getStructure()}
       ${input_verb.name} action: ${input.getVerbParam("action")}
       player start y: ${player.getY()}`,
        "verbs"
      );

      // --------------------------------------------------
      // sentence structure: verb
      // action: none
      // --------------------------------------------------
      if (input.hasStructure("verb") || none) {
        if (input_verb.name === "jump") {
          msg += `$(We) jump ${adverb ? adverb : "up and down"}`;
          if (origin_asset.hasClass("Room")) {
            msg += ` in place`;
          } else {
            msg += `${
              origin_aspect ? " " + origin_aspect.id : ""
            }${origin_asset ? " " + origin_asset.articlename : ""}`;
          }
          msg += `. `;
        } else {
          msg += `$(We) ${input_verb.name} ${adverb ? adverb : "about"}`;
          if (origin_asset.hasClass("Room")) {
            msg += ` in place`;
          } else {
            msg += `${
              origin_aspect ? " " + origin_aspect.id : ""
            }${origin_asset ? " " + origin_asset.articlename : ""}`;
          }
          msg += `${input.getVerbParam("with") ? " with " + tool_asset.articlename + " " : ""}`;
          msg += `${adverb ? "" : " for a bit"}`;
          msg += `. `;
        }
        // print output
        return this.handleSuccess(msg, origin_asset);
      }

      // --------------------------------------------------
      // action: reposition
      // --------------------------------------------------
      if (repositioning) {
        if (reposition_top) {
          newY = origin_asset.getYTop();
        }
        if (reposition_bottom) {
          newY = origin_asset.getY();
        }
        if (reposition_up) {
          newY = Math.min(
            player.getY() + origin_aspect.scale_increment,
            origin_asset.getYTop()
          );
        }
        if (reposition_down) {
          newY = Math.max(
            player.getY() - origin_aspect.scale_increment,
            origin_asset.getYBottom()
          );
        }
        reposition_percent = newY / origin_asset.getHeight();
        reposition_percent_string = reposition_up
          ? this.getPercentStringUp(reposition_percent)
          : this.getPercentStringDown(reposition_percent);
      }

      // --------------------------------------------------
      // action: unnest or renest
      // --------------------------------------------------
      if (exiting) {
        newY = 0;
      }

      // --------------------------------------------------
      // action: nest or renest
      // --------------------------------------------------
      if (entering) {
        const top = destination_asset.getYTop();
        // @TODO what if player mounts the ladder in the hole in the ground?
        mount_up = false;
        if (
          destination_aspect.scale_increment > 0 &&
          destination_aspect.scale_increment < destination_asset.getHeight() &&
          !input_verb.override_aspect_scale_increments.up
        ) {
          // player gets on at scale_increment height
          newY = destination_asset.getY() + destination_aspect.scale_increment;
          mount_up = true;
        } else {
          // go to top
          newY = top;
        }
        mount_percent = newY / top;
        if (mount_up) {
          mount_percent_string = this.getPercentStringUp(mount_percent);
        }
        if (mount_down) {
          mount_percent_string = this.getPercentStringDown(mount_percent);
        }
      }

      // --------------------------------------------------
      // unnest and nest
      // --------------------------------------------------
      let unnest_preposition = player.getPrettyUnnestPreposition();
      if (exiting) {
        results = player.onUnnestThisFromThat(origin_asset);
        if ("undefined" !== typeof results) return results;
      }
      if (entering) {
        results = player.onNestThisToThat(
          destination_asset,
          destination_aspect.id
        );
        if ("undefined" !== typeof results) return results;
      }

      // --------------------------------------------------
      // apply state changes
      // --------------------------------------------------
      let verb_posture = input_verb.override_aspect_posture;
      let aspect = player.getNestOrPlaceAspect();
      posture =
        verb_posture && aspect.canPlayer(verb_posture)
          ? verb_posture
          : player.getNestOrPlaceAspect().player.posture;
      posture_string = this.getPostureString(posture, aspect.id);
      player.posture = posture;

      player.position.y = newY;

      // --------------------------------------------------
      // compose output
      // --------------------------------------------------
      msg += `$(We)
        ${tool_asset ? "use " + tool_asset.articlename + " to" : ""}
        ${get_off && get_on ? get_off : get_on && !get_off ? get_on : get_off && !get_on ? get_off : input_verb.name}
        ${repositioning ? reposition_percent_string + " " + origin_asset.articlename : ""}
        ${exiting ? unnest_preposition + " " + origin_asset.articlename : ""}
        ${action === "renest" ? " and then " + get_on : ""}
        ${mount_percent_string}
        ${entering && !mount_percent_string ? destination_aspect.id : ""}
        ${entering ? destination_asset.articlename : ""}
        ${entering ? "and " + posture_string : ""}
      `;
      msg = msg.trim() + ". ";

      this.game.log(
        "L1392",
        "log",
        "high",
        `${this.name}.js > 
       player end y: ${player.getY()}
       player posture: ${posture}`,
        "verbs"
      );

      // print output
      return this.handleSuccess(msg, destination_asset || origin_asset);
    }, // END doSuccess
  };
})(); // go