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

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

  /**
   * @augments {adventurejs.Verb}
   * @class ride
   * @ajsnode game.dictionary.verbs.ride
   * @ajsextendverb go
   * @ajsconstruct MyGame.createVerb({ "name": "ride", [...] });
   * @ajsconstructedby adventurejs.Dictionary#createVerb
   * @hideconstructor
   * @ajsinstanceof Verb
   * @ajsnavheading LocomotionVerbs
   * @summary Verb meaning ride, as in "ride horse".
   * @todo Ride NPCs (like a horse). Will NPC be a Vehicle?
   * @todo What about things like rafts that aren't under subject's control?
   * @tutorial Verbs_Subscriptions
   * @tutorial AdvancedVerbs_VerbAnatomy
   * @tutorial AdvancedVerbs_VerbProcess
   * @tutorial AdvancedVerbs_ModifyVerbs
   * @tutorial AdvancedVerbs_ModifyVerbs
   * @classdesc
   * <pre class="display border outline">
   * <span class="ajs-player-input">&gt; ride hippogryph</span>
   * You ride the hippogryph, bearing in mind that this is not one of your classical type hippogryphs - you know, half horse, half gryphon - but is in fact a full-on hippopotamus named Griff. As such, Griff has mixed feelings about the arrangement of being ridden. On the one hand, you could kick your heels and go "yah!" and he could carry you across the lake. On the other, he could roll over and crush you. Griff casually regurgitates some cud and reswallows it while he considers the situation. (Unlike other ruminants, hippos don't chew their cud. THE MORE YOU KNOW!)
   * </pre>
   * <p>
   * <strong>Ride</strong> a
   * {@link adventurejs.Tangible|Tangible}
   * {@link adventurejs.Asset|Asset}, optionally in a direction
   * as transporation to another room.
   * Requires that the Asset to be ridden has
   * <code>asset.dov.ride.enabled</code>
   * set to true. If subject isn't on Asset, verb will
   * redirect to {@link go}. If subject is already on Asset
   * and a direction is specified, subject will try to travel.
   * </p>
   * <p>
   * It's assumed that anything that has
   * dov.ride will be a
   * {@link adventurejs.Vehicle|Vehicle}.
   * See
   * <a href="/doc/Tangibles_Vehicles.html">Simple Vehicles</a>
   * to learn more.
   * </p>
   *
   * <p>
   * Subscribing a Tangible
   * {@link adventurejs.Asset|Asset}
   * to verb <code>ride</code>
   * allows players to ride the Tangible Asset
   * while still holding it in inventory.
   * <br><br>
   * Normally, when putting one Tangible
   * in/on/under/behind another, the child asset is
   * added to the parent asset's in/on/under/behind
   * {@link adventurejs.Aspect|Aspect}.
   * <br><br>
   * In the case of {@link adventurejs.Character|Characters},
   * they can only be
   * <strong>in</strong> the {@link adventurejs.Room|Room}
   * they are in. When Characters move in/on/under/behind
   * Tangible subclasses such as {@link adventurejs.Chair|Chairs}
   * or {@link adventurejs.Bed|Beds}, they become
   * <strong>nested</strong>, which is a secondary form of
   * parent/child relationship.
   * <br><br>
   * For example, the subject is <strong>IN</strong> a room.
   * A bed is also <strong>IN</strong> the same room.
   * When the subject gets <strong>ON</strong> the bed,
   * the subject remains <strong>IN</strong> the room
   * and also becomes <strong>NESTED ON</strong> the bed.
   * <br><br>
   * We do this for a couple of reasons. One is to prevent
   * overcomplicating the routines that determine what
   * Tangible Assets are considered to be within scope when
   * parsing player input. Another is to avoid
   * circular child/parent relationships,
   * which overcomplicate save/restore operations.
   * Circular relationships also overcomplicate parsing player input.
   * <br><br>
   * For example, imagine that a subject holds a skateboard
   * <strong>IN</strong> their inventory
   * and then stands <strong>ON</strong> the skateboard.
   * If both objects were in each other's Aspects,
   * that would be a circular relationship. By nesting the
   * subject to the skateboard, the skateboard can remain
   * in the subject's inventory with fewer complications.
   * </p>
   *
   * @ajsverbreactions doNestThatToThis, doNestThisToThat, doUnnestThatFromThis, doUnnestThisFromThat, doRemoveThisFromThat, doRemoveThatFromThis, doMoveThisToThat, doMoveThatToThis
   * @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
   */
  A.Preverbs.ride = {
    name: "ride",
    prettyname: "ride",
    past_tense: "ridden",
    synonyms: ["ride"],
    verb_prep_noun: ["ride on"],
    gerund: "riding",

    /**
     * @ajsverbstructures
     * @memberof ride
     */
    accepts_structures: [
      "verb", // ride
      "verb noun", // ride bike, ride east
      "verb noun noun", // ride bike east
      "verb preposition noun", // ride on bike, ride in boat
      "verb noun noun", // ride bike east
      "verb noun preposition noun", // ride east on bike, ride bike under bridge?
    ],

    subject_must_be: {
      not_constrained: true,
      not_on_floor: true,
      not_nested_elsewhere: true,
      able_to_ride: true,
    },

    /**
     * @memberof ride
     * @ajsverbphrase
     * phrase1:
     * {
     *   accepts_noun:true,
     *   noun_must_be:
     *   {
     *     known: true,
     *     tangible: true,
     *     present: true,
     *     visible: true,
     *     singular: false,
     *     //not_in_inventory: true,
     *   },
     * },
     */
    phrase1: {
      accepts_noun: true,
      noun_must_be: {
        known: true,
        tangible: true,
        present: true,
        visible: true,
        singular: false,
      },
    },

    /**
     * @memberof ride
     * @ajsverbphrase
     * phrase2:
     * {
     *   accepts_noun:true,
     *   noun_must_be:
     *   {
     *     direction: true,
     *   },
     *   accepts_preposition: true,
     *   // accepts_these_prepositions: ["to"], // ride onto? ride into?
     * },
     * @TODO what about "ride east on bike" ?
     */
    phrase2: {
      accepts_noun: true,
      noun_must_be: {
        known: true,
        tangible: true,
        present: true,
        visible: true,
        reachable: true,
      },
      accepts_preposition: true,
    },

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

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

      if (verb_phrase === "ride on") {
        //
      }

      // if player inputs "ride east on bike"
      // ensure sentence is in order of "ride bike to east"
      if (direct_object && indirect_object && direct_object.direction) {
        if (!indirect_object.isDOV(input_verb)) {
          this.game.debug(
            `D1149 | ${this.name}.js | ${indirect_object.id}.dov.${input_verb}.enabled is unset `
          );
          msg += `{We} can't ${input_verb} ${indirect_object.articlename}. `;
          this.handleFailure(msg);
          return null;
        }
        input.swapPhrases(1, 2);
        direct_object = input.getAsset(1);
        direct_preposition = input.getPreposition(1);
        indirect_object = input.getAsset(2);
        indirect_preposition = input.getPreposition(2);
      }

      // ride, peddle, skate, drive
      if (input.hasStructure("verb")) {
        if (!nest_asset || !nest_asset.isDOV(input_verb)) {
          // or prompt?
          input.setSoftPrompt({
            index: 1,
            type: "noun",
            noun1: true,
            verb: input_verb,
          });
          this.game.debug(
            `D1122 | ${this.name}.js | no direct_object received or inferred, soft prompt noun1 `
          );
          msg += `What would {we} like to ${input_verb}? `;

          this.handleFailure(msg);
          return null;
        }
        this.game.log(
          "L1366",
          "log",
          "high",
          `[${this.name}.js] infer ${direct_object.id} as direct_object `,
          "verbs"
        );
        direct_object = nest_asset;

        input.setAsset(1, direct_object);
        input.setStructure("verb noun");
      }

      // "verb noun",
      // ride bike, peddle boat, skate..., drive car
      // ride east, peddle east, skate east, drive east
      if (input.hasStructure("verb noun")) {
        if (!direct_object.direction && !direct_object.isDOV(input_verb)) {
          this.game.debug(
            `D1135 | ${input_verb}.js | subject is not nested on an asset with asset.dov.${input_verb}.enabled set `
          );
          msg += `{We} can't ${input_verb} ${direct_object.articlename}. `;
          this.handleFailure(msg);
          return null;
        }

        // ride east, peddle east, skate east, drive east
        // all ok
        if (direct_object.direction) {
          if (nest_asset && nest_asset.isDOV(input_verb)) {
            input.swapPhrases(1, 2);
            // set nest as direct object
            input.setAsset(1, nest_asset);
            input.setStructure("verb noun noun");
            direct_object = nest_asset;
            indirect_object = input.getAsset(2);
            this.game.printInferred(
              `${subject.getNestPreposition()} ${nest_asset.articlename}`
            );
          } else {
            // is subject carrying anything they can get on and input_verb?
            let rides = subject.findNestedAssetsWithProperty("dov.ride");
            if (rides.length) {
              input.swapPhrases(1, 2);
              input.setAsset(1, rides[0]);
              input.setStructure("verb noun noun");
              direct_object = rides[0];
              indirect_object = input.getAsset(2);
              input.verb_params.mount = true;
            } else {
              this.game.debug(
                `D1139 | ${this.name}.js | subject is not nested on an asset with asset.dov.${input_verb}.enabled set `
              );
              msg += `{We're} not on anything {we} can ${input_verb}. `;
              this.handleFailure(msg);
              return null;
            }
          }
        }

        // rike bike, peddle bike, drive car
        else if (direct_object.isDOV(input_verb)) {
          if (!nest_asset || nest_asset.id !== direct_object.id) {
            // not on it, so try to get on it
            input.setVerb(1, "go");
            input.setPreposition(1, direct_object.default_aspect);
            input.setPreposition(1, "on");
            input.setStructure("verb preposition noun");
            return this.game.dictionary.doVerb("go");
          }

          // good to go
          return true;
        } else {
          input.setSoftPrompt({
            index: 2,
            type: "noun",
            noun2: true,
            verb: input_verb,
          });
          this.game.debug(
            `D1143 | ${this.name}.js | no destination received or inferred, soft prompt noun2 `
          );
          msg += `Where would {we} like to ${input_verb}? `;
          this.handleFailure(msg);
          return null;
        }
      }

      if (
        input.hasStructure("verb noun noun") ||
        input.hasStructure("verb noun preposition noun")
      ) {
        if (direct_object.direction && indirect_object.isDOV(input_verb)) {
          input.swapPhrases(1, 2);
          direct_object = input.getAsset(1);
          direct_preposition = input.getPreposition(1);
          indirect_object = input.getAsset(2);
          indirect_preposition = input.getPreposition(2);
        }
      }

      if (!nest_asset || nest_asset.id !== direct_object.id) {
        if (indirect_object) {
          this.game.debug(
            `D1217 | ${this.name}.js | subject must be on ${direct_object.id} `
          );
          msg += `{We're} not on ${direct_object.articlename}. `;
          this.handleFailure(msg);
          return null;
        }
        input.setVerb(1, "go");
        input.setPreposition(1, "on");
        input.setStructure("verb preposition noun");
        return this.game.dictionary.doVerb("go");
      }

      // if (!subject.can.ride || !subject.getNestOrPlaceAspect().canCharacter("ride")) {
      //   this.game.debug(
      //     `D1854 | ${
      //       this.name
      //     }.js | subject.can.ride is false or ${subject.getNestOrPlaceAsset()}.aspects.${player.getNestOrPlacePreposition() }.nest.can.ride is false`,
      //   );
      //   msg += `{We} can't ride ${direct_object.articlename} here. `;
      //   this.handleFailure(msg);
      //   return null;
      // }

      if (indirect_object && indirect_object.direction) {
        if (input.verb_params.mount) {
          results = subject.onNestThisToThat(nest_asset);
          if ("undefined" !== typeof results) return results;
        }
        return this.game.tryTravel(indirect_object.direction, {
          with: [direct_object.id],
        });
      }

      return true;
    },

    doSuccess: function () {
      var input = this.game.getInput();
      var subject = input.getSubject();
      var input_verb = input.input_verb;
      var direct_object = input.getAsset(1);
      var direct_preposition = input.getPreposition(1);
      var indirect_object = input.getAsset(2);
      var indirect_preposition = input.getPreposition(2);
      var nest_asset = subject.getNestAsset();
      var msg = "";
      var results;

      if (!input.did.tryTravel) {
        msg += `{We} ${input_verb} ${direct_object.articlename} about a bit. `;
      }

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