// 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;
};
})();