// remove.js
(function () {
/*global adventurejs A*/
"use strict";
/**
* @augments {adventurejs.Verb}
* @class remove
* @ajsnode game.dictionary.verbs.remove
* @ajsconstruct MyGame.createVerb({ "name": "remove", [...] });
* @ajsconstructedby adventurejs.Dictionary#createVerb
* @hideconstructor
* @ajsinstanceof Verb
* @ajsnavheading ManipulationVerbs
* @summary Verb meaning remove, as in "remove cap from toothpaste".
* @tutorial Scripting_VerbSubscriptions
* @tutorial Verbs_VerbAnatomy
* @tutorial Verbs_VerbProcess
* @tutorial Verbs_ModifyVerbs
* @tutorial Verbs_WriteVerbs
* @classdesc
* <pre class="display border outline">
* <span class="input">> remove hat from from</span>
* You try to remove the top hat from the singing frog. He leans
* neatly away without moving from his spot on the piano, causing you to
* miss and plunge hands first into the taut piano strings. You leap
* backwards with strings wrapped around you and crash into the drum
* set, trodding loudly upon the snare drum.
* The sudden cacophony draws the conductor, who whacks you about
* the head and shoulders with his baton and chases you into the
* stage curtains. You wrestle with the curtains, which tear and fall
* heavily down upon you. You climb to your feet, wrapped in twisted
* curtains and piano strings, one foot stuck in a drum, and find
* yourself on stage, bathed in spotlight, facing the shocked crowd.
* </pre>
* <p>
* <strong>Remove</strong> may be interpreted ambiguously. It tries to respond
* contextually depending on the properties of the objects provided.
* Remove may redirect to
* {@link untie},
* {@link detach}, or
* {@link take}.
* Remove may also remove items worn by the player or
* {@link adventurejs.NPC|NPCs}, automatically unzipping or unbuttoning them if needed.
* </p>
* @ajsverbreactions
* @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
*/
A.Preverbs.remove = {
name: "remove",
prettyname: "remove",
past_tense: "removed",
synonyms: ["remove"],
/**
* @ajsverbstructures
* @memberof remove
*/
accepts_structures: ["verb noun", "verb noun preposition noun"],
/**
* @memberof remove
* @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 remove
* @ajsverbphrase
* 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,
* accepts_these_prepositions: [ 'from' ],
* },
*/
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,
accepts_these_prepositions: ["from"],
},
/**
* @memberof remove
* @ajsverbparams
* with_params: {},
*/
with_params: {},
doTry: function () {
var input = this.game.getInput();
var player = this.game.getPlayer();
var direct_object = input.getAsset(1);
var indirect_object = input.getAsset(2);
var msg = "";
// if (!direct_object.isDOV("remove")) {
// this.game.debug(
// `F1923 | ${this.name}.js | ${direct_object.id}.dov.${this.name} not enabled `
// );
// msg += `$(We) can't ${this.name} ${direct_object.articlename}. `;
// this.handleFailure(msg);
// return null;
// }
// parsed sentence structure: verb noun
if (input.hasStructure("verb noun")) {
var parent = direct_object.getPlaceAsset();
input.setAsset(2, parent);
input.setPreposition(2, "from");
input.setAssumed(2);
input.setStructure("verb noun preposition noun");
indirect_object = parent;
}
// sentence structure: verb noun preposition noun
if (input.hasStructure("verb noun preposition noun")) {
// if direct_object is tied, redirect to untie
if (direct_object.dov.tie?.with_params.connections.length) {
this.game.debug(
`F1254 | ${this.name}.js | ${direct_object.id}.dov.tie, infer untie `,
);
this.game.dictionary.doVerb("untie");
return null;
}
// if direct_object is attached, redirect to detach
if (direct_object.isPlacedAtAspect("attached")) {
this.game.debug(
`F1254 | ${this.name}.js | ${direct_object.id} is attached, infer detach `,
);
this.game.dictionary.doVerb("detach");
return null;
}
// thing not in other thing
if (!direct_object.isIn(indirect_object)) {
this.game.debug(
`F1255 | ${this.name}.js | ${direct_object.id} place is not ${indirect_object.id} `,
);
msg += `${direct_object.Articlename} isn't in ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// if direct_object is worn & can be removed, take it off
if (
direct_object.is.worn &&
direct_object.isDOV("remove") &&
indirect_object.id === player.id
) {
return true;
}
// direct_object is worn by player but can't be removed
// handcuffs for instance
if (
direct_object.is.worn &&
!direct_object.isDOV("remove") &&
indirect_object.id === player.id
) {
this.game.debug(
`F1256 | ${this.name}.js | ${direct_object.id}.dov.remove.enabled is false `,
);
msg += `$(We) can't remove ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// direct_object is worn by other char but can't be removed
if (
direct_object.is.worn &&
indirect_object !== player.id &&
(!direct_object.isDOV("remove") || !indirect_object.isIOV("take"))
) {
this.game.debug(
`F1257 | ${this.name}.js | ${direct_object.id}.dov.remove is unset or ${indirect_object.id}.iov.take is unset`,
);
msg += `$(We) can't remove ${direct_object.articlename} from ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// worn by a character like a pet that you can take from?
// as in "remove collar from cat"
if (
direct_object.is.worn &&
indirect_object.id !== player.id &&
direct_object.isDOV("remove") &&
indirect_object.isIOV("take")
) {
// any conditions that would prevent removing clothing?
// none at the moment so just proceed to success
return true;
}
// try taking a thing from a character
// who can't be taken from
// authors will probably want some control over this interation
if (!indirect_object.isIOV("take")) {
this.game.debug(
`F1258 | ${this.name}.js | ${indirect_object.id}.iov.take is unset`,
);
msg += `$(We) can't take anything from ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
if (direct_object.is.worn && !direct_object.isDOV("remove")) {
// TODO article + noun or proper noun, depending on if is character
this.game.debug(
`F1259 | ${this.name}.js | ${direct_object.id}.dov.remove.enabled is false`,
);
msg += `$(We) can't remove ${direct_object.articlename} from ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
}
// if it's none of these things, redirect to take
this.game.debug(`F1260 | ${this.name}.js | infer take`);
this.game.dictionary.doVerb("take");
return null;
},
doSuccess: function () {
var input = this.game.getInput();
var player = this.game.getPlayer();
var direct_object = input.getAsset(1);
var indirect_object = input.getAsset(2);
var parent = direct_object.getPlaceAsset();
var msg = "";
var closedAnscestors = [];
var results;
this.game.debug(`F1261 | ${this.name}.js | print doSuccess`);
// open any containers if necessary
// we only do this for items nested in inventory
if (direct_object.isIn(player) && direct_object.areAnscestorsClosed()) {
closedAnscestors = direct_object.getClosedAnscestors();
for (var i = 0; i < closedAnscestors.length; i++) {
this.game.getAsset(closedAnscestors[i]).is.closed = false;
closedAnscestors[i] = this.game.getAsset(closedAnscestors[i]).name;
}
if (closedAnscestors.length > 0) {
msg += "$(We) open the ";
for (var i = 0; i < closedAnscestors.length; i++) {
if (
closedAnscestors.length > 2 &&
i < closedAnscestors.length - 2
) {
msg += ", ";
}
if (
closedAnscestors.length > 1 &&
i === closedAnscestors.length - 1
) {
msg += " and the ";
}
msg += closedAnscestors[i];
}
msg += ". ";
}
}
// if direct_object is worn, take it off
if (direct_object.is.worn && indirect_object.id == player.id) {
results = direct_object.unfasten();
msg += results ? `$(We) ${results}, then remove, ` : `$(We) remove `;
msg += `${direct_object.articlename}. `;
direct_object.is.worn = false;
}
// worn by a character like a pet that you can take from
// what if it's sexy sex? removing clothes from a partner
if (
direct_object.is.worn &&
indirect_object.id !== player.id &&
indirect_object.isIOV("take")
) {
results = direct_object.unfasten();
msg += results ? `$(We) ${results}, then remove, ` : `$(We) remove `;
msg += `${direct_object.articlename} from ${indirect_object.articlename}. `;
direct_object.is.worn = false;
}
if (indirect_object.id !== player.id && direct_object.takeable) {
// remove thing from its current container
results = parent.onRemoveThatFromThis(direct_object);
if ("undefined" !== typeof results) return results;
// add thing to player's contents
results = player.onMoveThatToThis(direct_object, "in");
if ("undefined" !== typeof results) return results;
}
// print output
this.handleSuccess(msg, direct_object);
return true;
},
};
})(); // remove