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

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

  /**
   * @augments {adventurejs.Verb}
   * @class untie
   * @ajsnode game.dictionary.verbs.untie
   * @ajsconstruct MyGame.createVerb({ "name": "untie", [...] });
   * @ajsconstructedby adventurejs.Dictionary#createVerb
   * @hideconstructor
   * @ajsinstanceof Verb
   * @ajsnavheading ManipulationVerbs
   * @summary Verb meaning untie, as in "untie string from finger".
   * @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; untie shoelace</span>
   * You untie your shoelace. Hung from the tree branch by your shoe as you are, this promptly results in you resuming your fall toward the ground. Yoink! Your parachute catches in the same branch and you're caught again, but thankfully only a couple of feet off the ground this time.
   * </pre>
   * <p>
   * <strong>Untie</strong> a {@link adventurejs.Tangible|Tangible}
   * {@link adventurejs.Asset|Asset}.
   * Requires that the asset has
   * <code>asset.dov.untie.enabled</code> set to true. If the asset also has
   * its <code>asset.dov.tie.enabled</code> property set true and asset.is.tied
   * is true, asset.is.tied will be set to false. If the asset is connected to
   * another asset by tie, the connection will be broken.
   * </p>
   * <p>
   * To apply untie to a non-rope asset such as a shoe
   * or a bowtie, set its
   * <code class="property">asset.dov.tie.with_params.with_nothing</code>
   * to true.
   * </p>
   * <h3 class="example">Example</h3>
   * <pre class="display"><code class="language-javascript">MyGame.createAsset({
   *   class: "Clothing",
   *   name: "shoe"
   *   dov: {
   *     untie: true,
   *   },
   *   is: { tied: true },
   * });
   * <p>
   * If a rope is being tied to another asset, the other asset must have its
   * <code class="property">asset.iov.tie.enabled</code> set to true.
   * This is true even if a player inputs the other asset as a direct object.
   * For example, "tie rope to zebra" and "tie zebra with rope" will both be
   * parsed with the rope as the direct object and the zebra as the indirect object.
   * (Instances of the {@link adventurejs.Rope|Rope} class will inherit
   * a direct object subscription, though you may redefine it in order
   * to set custom parameters.)
   * </p>
   * <pre class="display"><code class="language-javascript">MyGame.createAsset({
   *   class: "Rope",
   *   name: "sisal rope"
   *   dov: {
   *     tie: {
   *       with_assets: [ "balustrade" ],
   *     },
   *     untie: true,
   *   },
   * });
   * MyGame.createAsset({
   *   class: "Thing",
   *   name: "balustrade",
   *   dov: { climb: true },
   *   iov: {
   *     tie: {
   *       with_assets: [ "sisal rope" ],
   *     },
   *     untie: true,
   *   },
   * });
   * </code></pre>
   * @ajsverbreactions doRemoveThisFromThat, doRemoveThatFromThis, doMoveThisToThat, doMoveThatToThis
   * @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
   */
  A.Preverbs.untie = {
    name: "untie",
    synonyms: ["untie"],
    past_tense: "untied",
    prettyname: "untie",
    gerund: "untying",
    unstate: "tied",

    /**
     * @ajsverbstructures
     * @memberof untie
     */
    accepts_structures: [
      "verb noun", // untie rope, untie shoelace
      "verb noun preposition noun",
      // untie rope from thing, untie rope with thing?
      // "verb noun preposition noun preposition noun",
      // untie rope from thing with thing?
    ],

    /**
     * @memberof untie
     * @ajsverbphrase
     * phrase1:
     * {
     *   accepts_noun: true,
     *   requires_noun: true,
     *   noun_must_be:
     *   {
     *     known: true,
     *     tangible: true,
     *     present: true,
     *     visible: true,
     *     reachable: true,
     *   },
     * },
     */
    phrase1: {
      accepts_noun: true,
      requires_noun: true,
      noun_must_be: {
        known: true,
        tangible: true,
        present: true,
        visible: true,
        reachable: true,
      },
    },

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

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

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

      // example: untie rope (from thing)
      // example: untie table (untie rope from table)

      // sentence structure: verb noun
      if (input.hasStructure("verb noun")) {
        // does it have state?
        // only applies to non-ropes such as a shoe or a bowtie
        // which don't require an indirect object
        if (direct_object.is.tied) {
          return true;
        }

        // did player try to untie a rope without specifying
        // the thing it's tied to?
        if (
          direct_object.isDOV("tie") &&
          direct_object.getVerbConnectionCount("tie", "to_iov")
        ) {
          // get the first thing the rope is tied to
          // not currently accounting for multiple targets
          input.setAsset(
            2,
            this.game.getAsset(
              direct_object.getVerbConnections("tie", "to_iov")[0]
            )
          );
          input.setPreposition(2, "from");
          indirect_object = input.getAsset(2);
          indirect_preposition = "from";
          input.setStructure("verb noun preposition noun");
        }

        // did player try to untie a thing a rope is tied to
        // rather than the rope?
        if (
          direct_object.isIOV("tie") &&
          direct_object.getVerbConnectionCount("tie", "to_dov")
        ) {
          // get the first rope that is tied to this thing
          // not currently accounting for multiple ropes
          input.setAsset(
            2,
            this.game.getAsset(
              direct_object.getVerbConnections("tie", "to_dov")[0]
            )
          );
          input.swapNouns(1, 2);
          input.setPreposition(2, "from");
          direct_object = input.getAsset(1);
          indirect_object = input.getAsset(2);
          indirect_preposition = "from";
          input.setStructure("verb noun preposition noun");
        }
      } // verb noun

      // @TODO handling for "untie knots in/from rope"

      // can't tie to or tie with
      if (!direct_object.isDOV(this.name) && !direct_object.isIOV(this.name)) {
        this.game.debug(
          `D1482 | ${this.name}.js | ${direct_object.id}.dov.untie and .iov.untie are unset `
        );
        msg += `${direct_object.Articlename} can't be untied. `;
        this.handleFailure(msg);
        return null;
      }

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

      // explicitly separate iov/dov check here because
      // ropes may have both, leading to false results
      if (direct_object.isDOV("tie")) {
        // if object is rope but not tied to anything
        if (!direct_object.getVerbConnectionCount("tie", "to_iov")) {
          // is another rope tied to this rope? that is a real thing
          if (
            direct_object.isIOV("tie") &&
            direct_object.getVerbConnectionCount("tie", "to_dov")
          ) {
            let other_rope = this.game.getAsset(
              direct_object.getVerbConnections("tie", "to_dov")[0]
            );
            if (other_rope) {
              input.setAsset(1, other_rope);
              direct_object = other_rope;
            }
          } else {
            // rope isn't tied to anything
            this.game.debug(
              `D1484 | ${this.name}.js | ${direct_object.id}.is.connected_by.tie.to_iov is unset `
            );
            msg += `${direct_object.Articlename_isnt} tied to anything. `;
            this.handleFailure(msg);
            return null;
          }
        }
      } else if (direct_object.isIOV("tie")) {
        // if object can have rope tied to it but doesn't
        if (!direct_object.getVerbConnectionCount("tie", "to_dov")) {
          this.game.debug(
            `D1485 | ${this.name}.js | ${direct_object.id}.is.connected_by.tie.to_dov is empty`
          );

          if (direct_object.allowVerbWithNothing("tie", "dov")) {
            msg += `${direct_object.Articlename_is} already ${this.past_tense}. `;
          } else {
            msg += `Nothing is tied to ${direct_object.articlename}. `;
          }

          this.handleFailure(msg);
          return null;
        }
      }
      return true;
    },

    doSuccess: function () {
      var input = this.game.getInput();
      var subject = input.getSubject();
      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 results;
      var msg = "";

      if (input.hasStructure("verb noun")) {
        // if we got here without an indirect object
        // it means none is required

        // apply state changes
        direct_object.is.tied = false;

        // compose output
        msg = `{We} ${this.agree()} ${direct_object.articlename}. `;

        // --------------------------------------------------
        // print output
        // --------------------------------------------------
        this.handleSuccess(msg);
        return true;
      }

      // apply state changes
      let tie = this.game.dictionary.verbs.tie;
      if (tie) {
        tie.unsetVerbConnection(direct_object, indirect_object);
      }

      // compose output
      msg +=
        `{We} ${this.agree()}` +
        `${direct_preposition ? " " + direct_preposition : ""}` +
        `${direct_object ? " " + direct_object.articlename : ""}` +
        `${indirect_preposition ? " " + indirect_preposition : ""}` +
        `${indirect_object ? " " + indirect_object.articlename : ""}`;
      if (direct_object.getVerbConnectionCount("tie", "dov")) {
        msg += `, leaving it tied to ${this.game.getPrintableObjectList({
          objects: direct_object.getVerbConnections("tie", "to_iov"),
        })}`;
      }
      msg = msg.trim();
      msg += `. `;

      if (
        this.game.parser.isParsingMultiple() &&
        -1 === input.output_class.indexOf("concatenate_output")
      ) {
        input.output_class += " concatenate_output ";
      }

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