// empty.js
(function () {
/*global adventurejs A*/
"use strict";
/**
* @augments {adventurejs.Verb}
* @class empty
* @ajsnode game.dictionary.verbs.empty
* @ajsconstruct MyGame.createVerb({ "name": "empty", [...] });
* @ajsconstructedby adventurejs.Dictionary#createVerb
* @hideconstructor
* @ajsinstanceof Verb
* @ajsnavheading ManipulationVerbs
* @summary Verb meaning empty asset of other assets and/or substances.
* @tutorial Scripting_VerbSubscriptions
* @tutorial Verbs_VerbAnatomy
* @tutorial Verbs_VerbProcess
* @tutorial Verbs_ModifyVerbs
* @tutorial Verbs_WriteVerbs
* @classdesc
* <pre class="display border outline">
* <span class="input">> empty satchel on desk</span>
* You empty the contents of the leather satchel on the desk.
* </pre>
* <p>
* <strong>Pour</strong> is a special case that also doubles
* for <strong>empty</strong>. Because
* {@link adventurejs.Aspect|Aspects} can contain both
* {@link adventurejs.Tangible|Tangibles} and
* {@link adventurejs.Substance|Substances}, pouring or emptying
* means that both the Tangibles and the Substances will fall out
* of the source {@link adventurejs.Asset|Asset}
* and into the destination Asset. If the target is a Tangible,
* depending on its capacity, it may not be able to hold all of the
* contents of the source Asset. In this case, excess Tangibles and
* Substances will overflow onto the floor.
* </p>
* @ajsverbreactions
* @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
*/
A.Preverbs.empty = {
name: "empty",
prettyname: "empty",
past_tense: "emptied",
synonyms: ["empty"],
/**
* @ajsverbstructures
* @memberof empty
*/
accepts_structures: ["verb noun", "verb noun preposition noun"],
/**
* @memberof empty
* @ajsverbphrase
* phrase1:
* {
* accepts_noun:true,
* requires_noun: true,
* noun_must_be:
* {
* known: true,
* matter: true,
* present_if_tangible: true,
* reachable_if_tangible: true,
* },
* },
*/
phrase1: {
accepts_noun: true,
requires_noun: true,
noun_must_be: {
known: true,
matter: true,
present_if_tangible: true,
reachable_if_tangible: true,
},
},
/**
* @memberof empty
* @ajsverbphrase
* phrase2:
* {
* accepts_noun:true,
* noun_must_be:
* {
* known: true,
* matter: true,
* present_if_tangible: true,
* reachable_if_tangible: true,
* },
* accepts_preposition:true,
* requires_preposition: true,
* },
*/
phrase2: {
accepts_noun: true,
noun_must_be: {
known: true,
matter: true,
present_if_tangible: true,
reachable_if_tangible: true,
},
accepts_preposition: true,
requires_preposition: true,
},
/**
* @memberof empty
* @ajsverbparams
* with_params: {},
*/
with_params: {},
doTry: function () {
var input = this.game.getInput();
var direct_object = input.getAsset(1);
var indirect_object = input.getAsset(2);
var indirect_preposition = input.getPreposition(2);
var player = this.game.getPlayer();
var substance = "";
var msg = "";
var empty_means_take_all;
var empty_means_unplug;
var empty_means_take_plug;
if (direct_object instanceof adventurejs.Tangible) {
// true of verb noun and verb noun preposition noun
// is direct_object closed?
if (direct_object.isDOV("open")) {
this.game.debug(
`F1741 | ${this.name}.js | ${direct_object.id}.is.closed `
);
msg += `${direct_object.Articlename} is closed. `;
this.handleFailure(msg);
return null;
}
// is direct_object empty?
if (
!direct_object.doesContainAnySubstance() &&
!direct_object.doesContainAnyAsset()
) {
this.game.debug(
`F1551 | ${this.name}.js | ${direct_object.id}.doesContainAnySubstance and .doesContainAnyAsset are false `
);
msg += `${direct_object.Articlename} is empty. `;
this.handleFailure(msg);
return null;
}
}
if (input.hasStructure("verb noun")) {
// empty knapsack
if (direct_object instanceof adventurejs.Substance) {
// can't empty a substance
this.game.debug(
`F1742 | ${this.name}.js | ${direct_object.id} is a substance rather than a container `
);
msg += `$(We) don't know how to empty ${direct_object.name}. `;
this.handleFailure(msg);
return null;
}
// already done closed and empty
// is it not takeable? we'll allow input
// like "empty drawer" to mean "take all from drawer"
if (!direct_object.isDOV("take")) {
if (direct_object.doesContainAnyAssetAt("in")) {
var takeable_assets = [];
for (var i = 0; i < direct_object.aspects.in.contents.length; i++) {
var asset = this.game.getAsset(
direct_object.aspects.in.contents[i]
);
if (asset.isDOV("take")) {
takeable_assets.push(asset);
}
if (takeable_assets.length) {
empty_means_take_all = true;
input.verb_params.empty_means_take_all = true;
input.verb_params.takeable_assets = takeable_assets;
}
}
}
if (
!empty_means_take_all
/* && !empty_means_unplug
&& !empty_means_take_plug */
) {
this.game.debug(
`F1744 | ${this.name}.js | ${direct_object.id}.dov.take.enabled is false and .aspects.in.contents is empty `
);
msg += `$(We) don't know how to empty ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
} else {
// find target - player parent / room
indirect_object = player.getNestOrPlaceAsset();
indirect_preposition = player.getNestOrPlacePreposition();
input.setAsset(2, indirect_object);
input.setPreposition(2, indirect_preposition);
input.setAssumed(2, true);
input.setStructure("verb noun preposition noun");
}
}
if (input.hasStructure("verb noun preposition noun")) {
// empty suitcase onto bed
// "empty water from bottle" is a thing you could say
// is target the floor? set to room
if (indirect_object instanceof adventurejs.Floor) {
indirect_object = this.game.getCurrentRoom();
input.setAsset(2, indirect_object);
}
if (!direct_object.isDOV("take")) {
// we don't handle "empty a onto b" where a is not carried
this.game.debug(
`F1745 | ${this.name}.js | ${direct_object.id}.dov.take.enabled is false `
);
msg += `$(We) don't know how to empty ${direct_object.articlename} ${indirect_preposition} ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// is direct_object in player?
// is it takeable? asking because "empty drawer" should mean take all from drawer
if (direct_object.isDOV("take") && !direct_object.isIn(player)) {
this.game.debug(
`F1743 | ${this.name}.js | ${direct_object.id}.place not in player `
);
msg += `$(We're) not carrying ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
} // verb noun preposition noun
return true;
},
doSuccess: function () {
var input = this.game.getInput();
var direct_object = input.getAsset(1);
var indirect_object = input.getAsset(2);
var indirect_preposition = input.getPreposition(2);
var player = this.game.getPlayer();
var msg = "";
var results;
var room = indirect_object instanceof adventurejs.Room;
var target_object, target_preposition;
var emptied_count = 0;
var transferred = [];
var spillover = [];
var overflow = false;
var substance_asset;
var empty_this = false;
var mixer;
this.game.debug(`F1746 | ${this.name}.js | print doSuccess `);
// parsed sentence structure: verb noun
if (input.hasStructure("verb noun")) {
if (input.verb_params.empty_means_take_all) {
// take all from direct object
var takeable_assets = input.verb_params.takeable_assets;
for (var i = 0; i < takeable_assets.length; i++) {
var asset = takeable_assets[i];
// remove thing from its current container
//results = asset_parent.onRemoveThatFromThis( direct_object );
results = asset.moveFrom(direct_object);
if ("undefined" !== typeof results) return results;
// add thing to player's contents
//results = player.onMoveThatToThis( direct_object, "in" );
results = asset.moveTo("in", player);
if ("undefined" !== typeof results) return results;
}
this.game.debug(`F1746 | ${this.name}.js | empty means take `);
msg += `$(We) take ${this.game.getPrintableObjectList({
objects: takeable_assets,
})} from ${direct_object.articlename}. `;
}
// if(input.verb_params.empty_means_unplug)
// {
// // unplug direct object
// }
// if(input.verb_params.empty_means_take_plug)
// {
// // take plug from direct object
// }
this.handleSuccess(msg, direct_object);
return true;
}
if (input.hasStructure("verb noun preposition noun")) {
this.game.debug(`F1747 | ${this.name}.js | empty means pour `);
msg += `$(We) empty ${direct_object.articlename}`;
if (
"under" === indirect_preposition ||
"behind" === indirect_preposition
) {
msg += ` ${indirect_preposition} ${indirect_object.articlename}`;
} else {
msg += ` over ${room ? "the floor" : indirect_object.articlename}`;
}
msg += `. `;
// handle substances
if (direct_object.hasVesselAtAspect("in")) {
if (0 < direct_object.aspects.in.vessel.getVolume()) {
// direct_object has substance
substance_asset = this.game.getAsset(
direct_object.aspects.in.vessel.substance_id
);
if (
room ||
"under" === indirect_preposition ||
"behind" === indirect_preposition
) {
// if indirect_object is room, substance just spills out
msg += `${substance_asset.Name} spills to the floor. `;
empty_this = true;
} else if (
"on" === indirect_preposition &&
!indirect_object.hasVesselAtAspect(indirect_preposition)
) {
// player said "pour on" and target has no on aspect
msg += `${substance_asset.Name} pours over ${indirect_object.articlename} and then drains away. `;
empty_this = true;
} else if (
indirect_object.hasVesselAtAspect(indirect_preposition)
) {
mixer = new adventurejs.SubstanceMixer(this.game.game_name).set({
source_input: direct_object.id,
source_aspect: "in",
source_substance_id:
direct_object.aspects.in.vessel.substance_id,
target_input: indirect_object.id,
target_aspect: indirect_preposition,
});
results = mixer.mix();
if (A.isFalseOrNull(results)) return results;
mixer.target_vessel.vessel_is_known = true;
msg += `${mixer.source_substance_asset.Name} pours from
${mixer.source_asset.articlename} ${indirect_preposition}
${
indirect_preposition === "in" || indirect_preposition === "on"
? " to"
: ""
}
${mixer.target_asset.articlename}`;
if (mixer.can_drain_target) {
msg += `, where it quickly drains away`;
} else if (mixer.did_overflow_target) {
msg += `, overflowing ${mixer.target_asset.articlename} with
${
mixer.did_mix_substances
? mixer.output_substance_asset.name
: mixer.source_substance_asset.name
}`;
} else if (mixer.did_fill_target) {
msg += `, filling ${mixer.target_asset.articlename} with
${
mixer.did_mix_substances
? mixer.output_substance_asset.name
: mixer.source_substance_asset.name
}`;
} else if (mixer.did_mix_substances) {
msg += `, resulting in ${mixer.output_substance_asset.name}`;
}
msg += `. `;
} else {
msg += `${substance_asset.Name} pours over ${indirect_object.articlename} and then spills to the floor. `;
empty_this = true;
}
}
if (
empty_this &&
isFinite(direct_object.aspects.in.vessel.getVolume())
) {
direct_object.aspects.in.vessel.setVolume(0);
}
} // handle substances
// handle physical assets
if (0 < direct_object.aspects.in.contents.length) {
for (
var i = direct_object.aspects.in.contents.length - 1;
i > -1;
i--
) {
var content_object = this.game.getAsset(
direct_object.aspects.in.contents[i]
);
target_object = indirect_object;
target_preposition = indirect_preposition;
overflow = false;
emptied_count++;
// if indirect_object is not the room, we need to check
// if it can hold each object
// if it can't, objects should fall to the floor
if (room) {
transferred.push(content_object);
} else {
if (
indirect_object.canContainAssetAt(
content_object,
indirect_preposition
)
) {
transferred.push(content_object);
} else {
target_object = this.game.getCurrentRoom();
target_preposition = "in";
spillover.push(content_object);
overflow = true;
}
}
// remove content_object from direct_object
results = direct_object.onRemoveThatFromThis(content_object);
if ("undefined" !== typeof results) return results;
// set content_object's target_object
// if no target_object was specified, set to player's parent
results = target_object.onMoveThatToThis(
content_object,
target_preposition
);
if ("undefined" !== typeof results) return results;
// msg += "and you succeed. ";
}
}
// print the results of physical assets
if (room) {
// everything falls to the floor
switch (emptied_count) {
case 0:
break;
case 1:
msg += "A single item tumbles out and falls to the floor. ";
break;
case 2:
msg += "Two items tumble out and fall to the floor. ";
break;
case 3:
msg += "Several items tumble out and fall to the floor. ";
break;
default:
msg += "A number of items tumble out and fall to the floor. ";
break;
}
} else {
var to_target =
indirect_preposition +
(indirect_preposition === "in" || indirect_preposition === "on"
? " to "
: " ") +
indirect_object.articlename;
switch (emptied_count) {
// some items are transferred to target, some may fall to the floor
case 0:
break;
case 1:
msg += `A single item tumbles ${to_target}`;
switch (spillover.length) {
case 0:
msg += ". ";
break;
case 1:
msg += " then falls to the floor. ";
break;
}
break;
case 2:
msg += `Two items tumble ${to_target}`;
switch (spillover.length) {
case 0:
msg += ". ";
break;
case 1:
msg += ", and one falls to the floor. ";
break;
case 2:
msg += " then fall to the floor. ";
break;
}
break;
case 3:
msg += `Several items tumble ${to_target}`;
switch (spillover.length) {
case 0:
msg += ". ";
break;
case 1:
msg += ", and one falls to the floor. ";
break;
case 2:
msg += ", and a couple of them fall to the floor. ";
break;
case 3:
msg += " then fall to the floor. ";
break;
}
break;
default:
msg += `A number of items tumble ${to_target}`;
switch (spillover.length) {
case 0:
msg += ". ";
break;
case 1:
msg += ", and one falls to the floor. ";
break;
case 2:
msg += ", and a couple of them fall to the floor. ";
break;
case 3:
msg += ", and several fall to the floor. ";
break;
default:
msg += " and some fall to the floor. ";
break;
}
break;
}
}
}
// print output
this.handleSuccess(msg, direct_object);
return true;
},
};
})(); // empty