Pre-release
AdventureJS Docs Downloads Bundler Devlog
Score: 0 Moves: 0
// doVerbAction.js
(function () {
  /* global AdventureJS A */
  var p = AdventureJS.Assets.Asset.prototype;
  /**
   * Check if this asset has a general verb action or reaction
   * for the specified event, or if the asset has an action for
   * the specific asset. If either form is found, pass it to
   * getStringArrayFunction and return the results. If the
   * result returns false or null it will terminate the calling
   * verb's default behavior.
   * <br><br>
   * We look for actions in two forms:<br>
   * <li>Function properties such as <code>asset.doThisToThat()</code>
   * are called. If a function returns null or false, that effectively
   * ends the turn.</li>
   * <li>String properties such as <code>asset.do_this_to_that</code>
   * override the turn's default output.</li>
   * @memberOf AdventureJS.Assets.Asset
   * @method AdventureJS.Assets.Asset#doVerbAction
   * @param {string} action The name of this action.
   * @param {string} target Target is relative. Depending on whether
   * "this" is a direct or indirect object, the target may be an
   * indirect or direct object. The target is the other object in the
   * sentence, regardless of where in the sentence it lies. We pass
   * asset.name here instead of asset.id – though ids are also
   * accepted – because this is an author facing system and we've
   * trained authors to work with names rather than IDs. Hooks will
   * only be defined by authors, so we let them use asset.name as
   * their identifier. We do however make an effort to see
   * if an id has been passed instead of a name, because Ivan.
   * @param {string} target2 An optional second target. In a sentence
   * with three nouns, this would be the last noun. For example,
   * in "throw rock at troll with slingshot", the slingshot would
   * be target2.
   * @param {object} params Arbitrary parameter object.
   * @return {Boolean}
   */
  p.doVerbAction = function Asset_doVerbAction({
    action,
    params = {},
    type = "Hook",
    target,
    target2,
  } = {}) {
    // if we didn't receive an action, exit
    if (!action) return;

    let target_key = "";
    let target2_key = "";

    // in addition to checking for camel cased method properties,
    // we also look for alternative snake cased string properties
    const _action_ = A.FX.camelToSnake(action);

    // if this hasn't got function or string, exit
    if (!this[action] && !this[_action_]) return;

    const input = this.game.getInput();

    if (target) {
      // if an asset was passed, disregard assets retrieved from input
      target = target.class ? target : this.game.getAsset(target);
      if (target2) {
        target2 = target2.class ? target2 : this.game.getAsset(target2);
      }
    } else {
      target = input.getAsset(2);
      target2 = input.getAsset(3);
      if (!target) target = this.game.getPlayer();
    }

    let target_is_player = target && target.id === this.game.world._player;

    //

    if (target2) {
      this.game.log(
        "L1459",
        "log",
        "high",
        `[doVerbAction.js] TRY ${type}: ${this.id}.${action}(${target.id ? target.id : target}, ${target2.id ? target2.id : target2})`,
        type
      );

      this.game.debug(
        `D1442`,
        `${type}`,
        `<span class="ajs-tryfound">HOOK</span> <span class="ajs-actor">${this.id}</span>.<span class="ajs-action">${action}(</span><span class="ajs-target">"${target.name ? target.name : target}", "${target2.name ? target2.name : target2}"</span><span class="ajs-action">)</span>`
      );
    } else if (target) {
      this.game.log(
        "L1456",
        "log",
        "high",
        `[doVerbAction.js] TRY ${type}: ${this.id}.${action}(${target.id ? target.id : target})`,
        type
      );

      this.game.debug(
        `D1420`,
        `${type}`,
        `<span class="ajs-tryfound">HOOK</span> <span class="ajs-actor">${this.id}</span>.<span class="ajs-action">${action}(</span><span class="ajs-target">"${target.name ? target.name : target}"</span><span class="ajs-action">)</span>`
      );
    } else {
      this.game.log(
        "L1476",
        "log",
        "high",
        `[doVerbAction.js] TRY ${type}: ${this.id}.${action}()`,
        type
      );

      this.game.debug(
        `D1415`,
        `${type}`,
        `<span class="ajs-tryfound">HOOK</span> <span class="ajs-actor">${this.id}</span>.<span class="ajs-action">${action}(</span><span class="ajs-target">${""}</span><span class="ajs-action">)</span>`
      );
    }

    //

    let _a = this[action] ? action : _action_;
    let _o = this[action] ? "(" : "[";
    let _c = this[action] ? ")" : "]";

    this.game.log(
      "L1038",
      "log",
      "high",
      `[doVerbAction.js] ↳ FOUND ${type}: ${this.id}.${_a}${_o}${target ? target.id : ""}${target && target2 ? ", " : ""}${target2 ? target2.id : ""}${_c}`,
      `${type}`
    );

    this.game.debug(
      `D1383`,
      `${type}`,
      `<span class="ajs-tryfound">↳ FOUND</span> <span class="ajs-actor">${this.id}</span>.<span class="ajs-action">${_a}${_o}</span><span class="ajs-target">${target ? '"' + target.name + '"' : ""}${target && target2 ? ", " : ""}${target2 ? '"' + target2.name + '"' : ""}</span><span class="ajs-action">${_c}</span>`
    );

    // is there a method at this[action]?
    if ("function" === typeof this[action]) {
      return this[action].call(this, {
        action,
        target,
        target2,
        params,
        type,
        self: this,
      });
    }

    // if no method was found at this[action]
    // is there an alt string at this[_action_]?
    if (this[_action_]) {
      // did author specify an output method?
      if (
        this[_action_].append ||
        this[_action_].prepend ||
        this[_action_].override
      ) {
        let method = this[_action_].append
          ? "append"
          : this[_action_].prepend
            ? "prepend"
            : "override";
        // console.warn(`this[_action_][method]`, this[_action_][method]);
        input[`${method}Output`](
          A.FX.getSAF.call(this.game, this[_action_][method])
        );
      } else if (
        "string" === typeof this[_action_] ||
        Array.isArray(this[_action_]) ||
        ("undefined" !== typeof this[_action_].array &&
          Array.isArray(this[_action_].array)) ||
        "function" === typeof this[_action_]
      ) {
        input.overrideOutput(A.FX.getSAF.call(this.game, this[_action_]));
      }
    } // this[_action_]

    // --------------------------------------------------
    // is there a method at this[action][target]?
    // --------------------------------------------------
    if (target) {
      target_key = [target.name, target.id].find(
        (key) => "function" === typeof this[action]?.[key]
      );
    }
    if (target_key) {
      return this[action][target_key].call(this, {
        action,
        target,
        target2,
        params,
        type,
        self: this,
      });
    }

    // --------------------------------------------------
    // @TODO testing out using "player" as an identifier
    // have not carried this through remaining blocks
    // --------------------------------------------------
    if (
      target_is_player &&
      this[action] &&
      "function" === typeof this[action]["player"]
    ) {
      return this[action]["player"].call(this, {
        action,
        target,
        target2,
        params,
        type,
        self: this,
      });
    }

    // --------------------------------------------------
    // if no method was found at this[action][target]
    // is there an alt string at this[_action_][target]?
    // --------------------------------------------------
    if (target) {
      target_key = [target.name, target.id].find(
        (key) => "string" === typeof this[_action_]?.[key]
      );
    }
    if (target_key) {
      // if (this[_action_] && target && this[_action_][target.name]) {
      if (
        this[_action_][target_key].append ||
        this[_action_][target_key].prepend ||
        this[_action_][target_key].override
      ) {
        let method = this[_action_][target_key].append
          ? "append"
          : this[_action_][target_key].prepend
            ? "prepend"
            : "override";
        input[`${method}Output`](
          A.FX.getSAF.call(this.game, this[_action_][target_key][method])
        );
      } else if (
        "string" === typeof this[_action_][target_key] ||
        Array.isArray(this[_action_][target_key]) ||
        "function" === typeof this[_action_][target_key]
      ) {
        input.overrideOutput(
          A.FX.getSAF.call(this.game, this[_action_][target_key])
        );
        return;
      }
      // }
    }

    // --------------------------------------------------
    // is there a method at this[action][target][target2]?
    // --------------------------------------------------
    if (target && target2) {
      target_key = [target.name, target.id].find(
        (key) => "undefined" !== typeof this[action]?.[key]
      );
      if (target_key) {
        target2_key = [target2.name, target2.id].find(
          (key) => "function" === typeof this[action][target_key]?.[key]
        );
      }
    }
    if (target_key && target2_key) {
      return this[action][target.name][target2.name].call(this, {
        action,
        target,
        target2,
        params,
        type,
        self: this,
      });
    }

    // --------------------------------------------------
    // if no method was found at this[action][target][target2]
    // is there an alt string at this[_action_][target][target2]?
    // --------------------------------------------------
    if (target && target2) {
      target_key = [target.name, target.id].find(
        (key) => "undefined" !== typeof this[_action_]?.[key]
      );
      if (target_key) {
        target2_key = [target2.name, target2.id].find(
          (key) => "string" === typeof this[_action_][target_key]?.[key]
        );
      }
    }
    if (target_key && target2_key) {
      if (
        this[_action_][target_key][target2_key].append ||
        this[_action_][target_key][target2_key].prepend ||
        this[_action_][target_key][target2_key].override
      ) {
        let method = this[_action_][target_key][target2_key].append
          ? "append"
          : this[_action_][target_key][target2_key].prepend
            ? "prepend"
            : "override";
        input[`${method}Output`](
          A.FX.getSAF.call(
            this.game,
            this[_action_][target_key][target2_key][method]
          )
        );
      } else if (
        "string" === typeof this[_action_][target_key][target2_key] ||
        Array.isArray(this[_action_][target_key][target2_key]) ||
        "function" === typeof this[_action_][target_key][target2_key]
      ) {
        input.overrideOutput(
          A.FX.getSAF.call(this.game, this[_action_][target_key][target2_key])
        );
        return;
      }
    }

    return;
  };
})();