// throw.js
(function () {
/*global adventurejs A*/
"use strict";
/**
* @augments {adventurejs.Verb}
* @class throw
* @ajsnode game.dictionary.verbs.throw
* @ajsconstruct MyGame.createVerb({ "name": "throw", [...] });
* @ajsconstructedby adventurejs.Dictionary#createVerb
* @hideconstructor
* @ajsinstanceof Verb
* @ajsnavheading ManipulationVerbs
* @param {Object} parsedNoun One word user input string.
* @summary Verb meaning throw, as in "throw boulder at giant".
* @ajssynonyms throw, toss
* @tutorial Scripting_VerbSubscriptions
* @tutorial Verbs_VerbAnatomy
* @tutorial Verbs_VerbProcess
* @tutorial Verbs_ModifyVerbs
* @tutorial Verbs_WriteVerbs
* @classdesc
* <pre class="display border outline">
* <span class="input">> throw flugelhorn</span>
* You throw the jewel encrusted flugelhorn. It emits a sad little blat.
* </pre>
* <p>
* <strong>throw</strong> a {@link adventurejs.Tangible|Tangible}
* {@link adventurejs.Asset|Asset}. Requires that the Asset is
* in player's inventory.
* </p>
* @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
*/
A.Preverbs.throw = {
name: "throw",
prettyname: "throw",
past_tense: "threw",
synonyms: ["throw", "toss"],
/**
* @ajsverbstructures
* @memberof throw
*/
accepts_structures: [
"verb noun",
"verb noun preposition",
"verb noun preposition noun",
],
player_must_be: {
not_constrained: true,
},
/**
* @memberof throw
* @ajsverbphrase
* phrase1:
* {
* accepts_noun:true,
* requires_noun: true,
* noun_must_be:
* {
* //in_hands: true, // defer this check until after substance check
* matter: true,
* present_if_tangible: true,
* },
* },
*/
phrase1: {
accepts_noun: true,
requires_noun: true,
noun_must_be: {
matter: true,
present_if_tangible: true,
},
},
/**
* @memberof throw
* @ajsverbphrase
* phrase2:
* {
* accepts_noun:true,
* noun_must_be:
* {
* matter: true,
* present_if_tangible: true,
* },
* accepts_preposition: true,
* requires_preposition: true,
* },
*/
phrase2: {
accepts_noun: true,
noun_must_be: {
matter: true,
present_if_tangible: true,
},
accepts_preposition: true,
accepts_preposition_without_noun: true,
requires_preposition: true,
},
/**
* @memberof throw
* @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 currentRoom = this.game.getCurrentRoom();
var msg = "";
var containers;
var bodycontainers;
var results;
var inhands;
var direct_object_vessel;
var indirect_object_vessel;
// did player input something like "throw sand" ?
// if so it must come from a substance container that
// is either in hands, or in a reachable substance body
if (direct_object instanceof adventurejs.Substance) {
// get a list of available vessels
// this includes only things in inventory and nearby bodies of substance
containers = this.game.findSubstanceBodyOrHeld(direct_object.id);
// console.warn("containers", containers);
switch (containers.length) {
case 0:
this.game.debug(`F1447 | ${this.name}.js | no valid vessel found `);
msg += `There doesn't appear to be any ${
this.game.getAsset(direct_object.id).name
} to throw. `;
this.handleFailure(msg);
return null;
case 1:
// set container as direct_object
// and treat like "throw asset in container"
direct_object_vessel = this.game.getAsset(containers[0]);
input.setAssumed(1, true);
input.setVessel(1, direct_object_vessel);
break;
default:
this.game.debug(
`F1448 | ${this.name}.js | multiple containers found, disambiguate `
);
// disambiguate - need to set parsedNoun.matches
// save containers back to input for next turn disambiguation
input.setParsedNounMatchesQualified(1, containers);
this.game.parser.printNounDisambiguation({
parsedNoun: input.getParsedNoun(1),
nounIndex: 1,
});
return null;
} // switch containers.length
} // direct_object is substance // not substance
else {
// we bypassed the usual in_hands check to allow
// substance handling so we need to check that now
inhands = this.game.parser.selectInHands(direct_object.id);
if (!inhands.length) {
this.game.debug(
`F1601 | ${this.name}.js | ${direct_object.id} not in player's hands `
);
msg += `$(We're) not holding ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
}
if (input.hasStructure("verb noun preposition")) {
if (["up", "down"].indexOf(indirect_preposition) > -1) {
input.deletePhrase(2);
input.setStructure("verb noun");
indirect_preposition = false;
} else {
this.game.debug(
`F1956 | ${this.name}.js | no handling for ${this.name} ${direct_object.id} ${indirect_preposition} `
);
msg += `$(We) don't know how to ${this.name} ${direct_object.id} ${indirect_preposition}. `;
this.handleFailure(msg);
return null;
}
}
if (!direct_object.isDOV("throw")) {
this.game.debug(
`F1495 | ${this.name}.js | ${direct_object.id}.dov.throw.enabled is false `
);
msg += `$(We) can't throw ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
if (indirect_object) {
if (indirect_object.isIn(player)) {
this.game.debug(
`F1612 | ${this.name}.js | ${indirect_object.id}.isIn player `
);
msg += `$(We're) carrying ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// is indirect_object a substance?
// if so find a container
if (indirect_object instanceof adventurejs.Substance) {
// get a list of available
containers = this.game.findSubstanceContainers(indirect_object.id, [
"Present",
"Known",
"Visible",
]);
if (this.game.settings.throw_at_substance_prefers_bodies) {
// if only bodies of substance will do, use this
containers = this.game.parser.selectBodyOfSubstance(containers);
} else {
// if any vessel will do, use this
// presumes player is not trying to throw at a vessel they're holding
containers = this.game.parser.selectNotInInventory(containers);
}
switch (containers.length) {
case 0:
this.game.debug(
`F1444 | ${this.name}.js | no body of substance found `
);
msg += `There doesn't appear to be any ${
this.game.getAsset(indirect_object.id).name
} suitable for throwing ${indirect_preposition}. `;
this.handleFailure(msg);
return null;
case 1:
// save the found vessel back to the input object
indirect_object_vessel = this.game.getAsset(containers[0]);
input.setAssumed(2, true);
input.setVessel(2, indirect_object_vessel);
break;
default:
this.game.debug(
`F1445 | ${this.name}.js | multiple containers found, disambiguate `
);
// disambiguate - need to set parsedNoun.matches
// save containers back to input for next turn disambiguation
input.setParsedNounMatchesQualified(2, containers);
this.game.parser.printNounDisambiguation({
parsedNoun: input.getParsedNoun(2),
nounIndex: 2,
});
return null;
} // switch containers.length
} // substance
} // indirect_object
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 currentRoom = this.game.getCurrentRoom();
var player = this.game.getPlayer();
var msg = "";
var direct_object_vessel = this.game.getAsset(input.getVessel(1));
var indirect_object_vessel = this.game.getAsset(input.getVessel(2));
var dv, iv;
var results;
var can_contain;
var input_verb = input.input_verb;
this.game.debug(`F1449 | ${this.name}.js | print doSuccess`);
if (direct_object_vessel) {
dv = direct_object_vessel.getVesselAt(
direct_object_vessel.getAspectWithVessel()
);
}
if (indirect_object_vessel) {
iv = indirect_object_vessel.getVesselAt(
indirect_object_vessel.getAspectWithVessel()
);
}
// if thrown thing isn't substance, remove it from player
if (!(direct_object instanceof adventurejs.Substance)) {
// remove thing from player
results = player.onRemoveThatFromThis(direct_object);
if ("undefined" !== typeof results) return results;
}
// did player input "throw asset" without a target?
if (!indirect_object) {
// if player input something like "throw sand"
// then we chose a vessel for them that contains sand
// either in inventory or a body of substance
// and we're going to throw the sand, not the vessel
if (direct_object instanceof adventurejs.Substance) {
this.game.debug(
`F1602 | ${this.name}.js | no indirect object and direct object is substance `
);
msg += `$(We) sprinkle a handful of ${direct_object.name}`;
if (direct_object_vessel && !direct_object_vessel.$is("body")) {
msg += ` from ${direct_object_vessel.articlename}`;
}
msg += ` into the air. `;
if (dv.volume !== Infinity) {
dv.subtractVolume(this.game.settings.handful);
}
} // substance // not substance
else {
this.game.debug(`F1603 | ${this.name}.js | no indirect object `);
msg += `$(We) ${input_verb} ${direct_object.articlename}. `;
msg += direct_object.getDescription("throw");
// @TODO add logic for water rooms, anti-gravity
// set thing's new location to player's location
results = currentRoom.onMoveThatToThis(direct_object, "in");
if ("undefined" !== typeof results) return results;
} // not substance
} // no indirect_object
if (indirect_object) {
if (
direct_object instanceof adventurejs.Substance &&
indirect_object instanceof adventurejs.Substance
) {
// we're throwing substance from direct_object_vessel
// to indirect_object_vessel
// our target must be a body of substance so there's
// not going to be any mixing
// but we can empty the direct_object_vessel
if (direct_object_vessel.isIn(player)) {
this.game.debug(
`F1604 | ${this.name}.js | both objects are substances and player is holding substance vessel `
);
msg += `$(We) ${input_verb} ${direct_object.articlename} from ${direct_object_vessel.articlename} ${indirect_preposition} ${indirect_object.articlename}. `;
dv.empty();
} // from body to body
else {
this.game.debug(
`F1605 | ${this.name}.js | both objects are substance bodies `
);
msg += `$(We) scoop a handful of ${direct_object.articlename} ${indirect_preposition} ${indirect_object.articlename}. `;
}
} // both substances
else if (direct_object instanceof adventurejs.Substance) {
// we're throwing substance at asset
if (direct_object_vessel.isIn(player)) {
this.game.debug(
`F1606 | ${this.name}.js | direct object is substance held by player `
);
msg += `$(We) ${input_verb} ${direct_object.articlename} from ${direct_object_vessel.articlename} ${indirect_preposition} ${indirect_object.articlename}. `;
dv.empty();
} // from body to asset
else {
this.game.debug(
`F1608 | ${this.name}.js | direct object is substance in a body `
);
msg += `$(We) scoop a handful of ${direct_object.articlename} ${indirect_preposition} ${indirect_object.articlename}. `;
}
} // direct is substance
else if (indirect_object instanceof adventurejs.Substance) {
// we're throwing asset at substance
this.game.debug(
`F1609 | ${this.name}.js | indirect object is substance in a body `
);
msg += `$(We) ${input_verb} ${direct_object.articlename} ${indirect_preposition} ${indirect_object.articlename}. `;
// set thing's new location to vessel
// this might need more consideration for prepositions
// ie "throw asset over water" does it land on other side?
// though hopefully the hooks give enough opportunity for customization
// also might want to consider whether this asset can be placed in this vessel
// and whether throwing something in it means destroying the asset
results = indirect_object_vessel.onMoveThatToThis(
direct_object,
"in"
);
if ("undefined" !== typeof results) return results;
} // indirect is substance // two assets, neither substance
else {
// we're throwing asset at asset
// check preposition against iobj aspects
if (
["in", "on", "under", "behind"].indexOf(indirect_preposition) > -1
) {
if (
indirect_object.canContainAssetAt(
direct_object,
indirect_preposition
)
) {
can_contain = true;
}
}
if (can_contain) {
// if asset lands in other asset
results = indirect_object.onMoveThatToThis(
direct_object,
indirect_preposition
);
this.game.debug(
`F1610 | ${this.name}.js | both objects are tangible, indirect can contain direct `
);
msg += `$(We) ${input_verb} ${direct_object.articlename} neatly ${indirect_preposition} ${indirect_object.articlename}. `;
} else {
// if asset lands in room
results = currentRoom.onMoveThatToThis(direct_object, "in");
this.game.debug(
`F1611 | ${this.name}.js | both objects are tangible, direct lands in room `
);
msg += `$(We) ${input_verb} ${direct_object.articlename} ${indirect_preposition} ${indirect_object.articlename}. It falls to the floor. `;
}
if ("undefined" !== typeof results) return results;
}
} // indirect object
// print output
this.handleSuccess(msg, direct_object);
return true;
},
};
})(); // throw