// look.js
(function () {
/* global adventurejs A */
/**
* @augments {adventurejs.Verb}
* @class look
* @ajsnode game.dictionary.verbs.look
* @ajsconstruct MyGame.createVerb({ "name": "look", [...] });
* @ajsconstructedby adventurejs.Dictionary#createVerb
* @hideconstructor
* @ajsinstanceof Verb
* @ajsnavheading SensationVerbs
* @summary Verb meaning look at an asset.
* @tutorial Verbs_Subscriptions
* @tutorial AdvancedVerbs_VerbAnatomy
* @tutorial AdvancedVerbs_VerbProcess
* @tutorial AdvancedVerbs_ModifyVerbs
* @tutorial AdvancedVerbs_ModifyVerbs
* @classdesc
* <pre class="display border outline">
* <span class="ajs-player-input">> look behind moose head</span>
* You look behind the stuffed and mounted moose head. You find a brittle, age-stained business card for ACE TAXIDERMY. Written on the back of the card in a shaky cursive script is a name: ABRAHAM MANAHAN.
* </pre>
* <pre class="display border outline">
* <span class="ajs-player-input">> look in genie's bottle</span>
* You look in the genie's bottle. The bottle glass is dark green and smoky, almost opaque, but by turning the glass this way and that in the light, you can almost make out a dark powerful shape roiling inside it.
* </pre>
* <pre class="display border outline">
* <span class="ajs-player-input">> look on car roof</span>
* You look on the car roof. And a good thing you did, because you almost left the baby in its basket there.
* </pre>
* <pre class="display border outline">
* <span class="ajs-player-input">> look under left foot</span>
* You look under your left foot. In the immemorial time since you took up your position, an underground ecology has established there. Blind creatures lay revealed beneath your giant raised foot, and writhe away from the sunlight. An underground spring fills in the depression where your heel pressed into the earth.
* </pre>
* <strong>look</strong> can be used in a number of ways.
* <ul>
* <li><strong>look</strong> by itself returns a description of the room from
* room.descriptions.look, along with a list of things in the room. If those
* things have aspects, ex: asset.aspects.on.list_contents_in_room set to true, their
* contents will also be listed</li>
* <li><strong>look at asset</strong> returns a description of the asset from
* asset.descriptions.look</li>
* <li><strong>look at asset</strong> can be configured so that it returns
* different values depending on the subject's position. For example if subject
* is in a tree, "look at asset" will try to find a description at
* asset.descriptions.look["from tree"]</li>
* <li><strong>look in asset</strong>, used with "in" or any other preposition,
* will try to find a description at asset.descriptions[preposition]</li>
* <li><strong>look at asset through another asset</strong>, used with through or
* any other preposition, will try to find a description at
* asset.descriptions.look["through other asset"]</li>
* </ul>
* @ajsverbphases doBeforeTry, doAfterTry, doBeforeSuccess, doAfterSuccess
* @TODO "look at" doesn't make attached assets known as "examine" does
*/
A.Preverbs.look = {
name: "look",
prettyname: "look",
past_tense: "looked",
synonyms: ["look", "l"],
gerund: "looking",
/**
* @ajsverbstructures
* @memberof look
*/
accepts_structures: [
"verb", // look
"verb noun",
// look east
// look asset - politely accept this to mean look at asset
"verb preposition", // look up/down/in/out
"verb preposition noun",
// look in/under/at/through/etc asset
"verb noun preposition noun",
// look east through telescope
"verb preposition noun preposition noun",
// look at asset with binoculars
// look through binoculars at asset
// look at water in bucket
"verb preposition noun preposition noun preposition noun",
// look at water on slide with microscope
],
/**
* @ajsadverbs
* @memberof look
*/
accepts_adverbs: [
"carefully",
// "up",
// "down",
"left",
"right",
"back",
"backward",
"forward",
"towards",
"upstairs",
"downstairs",
"sideways",
"over",
"out",
], //, "in", "out"
/**
* @memberof look
* @ajsverbphrase
* phrase1:
* {
* accepts_noun:true,
* noun_must_be:
* {
* known: true,
* tangible: true,
* present: true,
* visible: true,
* singular: false,
* },
* accepts_preposition: true,
* accepts_preposition_without_noun: true,
* },
*/
phrase1: {
accepts_noun: true,
noun_must_be: { known: true, matter: true, present: true, visible: true },
accepts_preposition: true,
accepts_preposition_without_noun: true,
},
/**
* @memberof look
* @ajsverbphrase
* phrase2:
* {
* accepts_noun:true,
* noun_must_be:
* {
* known: true,
* tangible: true,
* present: true,
* visible: true,
* },
* accepts_preposition: true,
* requires_preposition: true,
* },
*/
phrase2: {
accepts_noun: true,
noun_must_be: {
known: true,
tangible: true,
present: true,
visible: true,
},
accepts_preposition: true,
requires_preposition: true,
},
/**
* @memberof look
* @ajsverbphrase
* phrase3:
* {
* accepts_noun:true,
* noun_must_be:
* {
* known: true,
* tangible: true,
* present: true,
* visible: true,
* },
* accepts_preposition: true,
* requires_preposition: true,
* },
*/
phrase3: {
accepts_noun: true,
noun_must_be: {
known: true,
tangible: true,
present: true,
visible: true,
},
accepts_preposition: true,
requires_preposition: true,
},
/**
* @memberof look
* @ajsverbparams
* with_params: {
* worn: false,
* held: false,
* },
*/
with_params: {
worn: false,
held: false,
must_be_worn: false,
must_be_held: false,
},
doTry: function () {
var input = this.game.getInput();
var subject = input.getSubject();
var adverb = input.getAdverb();
var room = this.game.getRoom();
var direct_object = input.getAsset(1);
var direct_preposition = input.getPreposition(1);
var direct_substance = input.getSubstance(1);
var direct_container;
var indirect_object = input.getAsset(2);
var indirect_preposition = input.getPreposition(2);
var indirect_substance = input.getSubstance(2);
var indirect_container;
var indirect_object2 = input.getAsset(3);
var indirect_preposition2 = input.getPreposition(3);
var indirect_substance2 = input.getSubstance(3);
var indirect_container2;
var msg = "";
var results;
var atcount = 0;
var wornoptics, lightemitters;
if (!subject.can.see) {
this.game.debug(
`D2135 | ${this.name}.js | ${subject.id}.can.see is unset`
);
msg += `{We} can't see anything. `;
this.handleFailure(msg);
return null;
}
// we're interpreting any version of "look asset" as "look at asset"
if (direct_object && !direct_preposition) {
// direct_preposition = "at";
// input.setPreposition(1, "at");
// input.updateStructure();
}
/**
* AUTOMATICALLY FIND VIEW MODIFIERS
* Is player wearing any viewports (like eyeglasses)?
* Are there any non-ambient light sources (flashlight, candle, etc)?
* Is player on a viewpoint (a nest from which the view is different)?
*/
// include adverb
if (adverb) {
input.pushViewModifier(adverb, null, "input");
}
// include any worn lenses
wornoptics = subject.getWornOptics();
for (let i = 0; i < wornoptics.length; i++) {
this.pushViewModifierAndDeletePhrase("through", wornoptics[i], "auto");
}
// include anything emitting light
lightemitters = room.findNestedAssetsWithProperty("is.emitting_light");
for (let i = 0; i < lightemitters.length; i++) {
let light = lightemitters[i];
if (
light.must.hold_to_see_with &&
!this.game.parser.selectInHands(light.id).length
) {
continue;
}
if (
light.must.wear_to_see_with &&
!this.game.parser.selectInHands(light.id).length
) {
continue;
}
this.pushViewModifierAndDeletePhrase("with", light, "auto");
}
// include subject nest
if (subject.isNested()) {
this.pushViewModifierAndDeletePhrase(
"from",
subject.getNestAsset(),
"auto"
);
}
// include current room
input.pushViewModifier("in", this.game.getRoom(), "auto");
// before we get into it, handle the special case of input such as
// "look east at mountains". Because directions resolve to nouns,
// we'll have parsed this as something like "look east_exit at mountains"
// which will throw errors that we need to compensate for
// @FUTURE we should be testing to see if the asset is visible at
// the specified direction, but we don't have a property for that
// so for now we're just going to print the asset's description
if (
input.hasStructure("verb noun preposition noun") &&
direct_object.direction /* &&
["at", "to"].includes(indirect_preposition) */
) {
input.deletePhrase(1);
direct_object = input.getAsset(1);
direct_preposition = input.getPreposition(1);
direct_substance = input.getSubstance(1);
direct_container;
indirect_object = null;
indirect_preposition = "";
indirect_substance = null;
}
/**
* PRE-PROCESS EACH INPUT PHRASE IN ISOLATION
* Usually we process verbs by sentence structure, but sentences
* using "look" may be constructed in a variety of ways, and
* the asset that we'd consider the direct object may not be
* in the first phrase.
* Verify that there's a target "at" object, and restructure
* if needed to ensure that view target is direct object.
* Then look for modifiers: viewports (like eyeglasses),
* light sources (like flashlights),
* viewpoints (nests from which the view is different),
* and containers (in the case of substances).
* If player has explicitly named modifiers that we've
* automatically accounted for, disregard that input.
*/
for (let phrase = input.getPhraseCount(); phrase > 0; phrase--) {
let prep = input.getPreposition(phrase);
let asset = input.getAsset(phrase);
let substance = input.getSubstance(phrase);
let nest;
// if player input "look at substance in container"
// we want to note it because we'll be treating
// "in container" as a view modifier and deleting that phrase
// but we may tailor the response if player explicitly
// named the container vs finding it automatically
if (
substance &&
input.getPhrase(phrase + 1) &&
input.getPreposition(phrase + 1) === "in"
) {
// console.warn("SUBSTANCE IN CONTAINER!!!");
input.verified_sentence[
`phrase${phrase}`
].player_specified_container = true;
}
switch (prep) {
case "at":
atcount++;
// are multiple prepositions "at" ?
// we don't handle any version of that
// alt unused method: if (A.hasDuplicates(prepositions, "at")) {
if (atcount > 1) {
this.game.debug(
`D1595 | ${this.name}.js | input includes multiple "at" targets `
);
msg += `That doesn't even make sense. `;
this.handleFailure(msg);
return null;
}
if (asset.hasClass("Tangible")) {
this.pushViewModifierAndDeletePhrase(
asset.getNestOrPlacePreposition(),
asset.getNestOrPlaceAsset(),
"auto"
);
}
break;
case "with":
// is asset a light source or a viewport?
if (asset.is.viewport) {
results = this.tryThroughViewport(asset);
if ("undefined" !== typeof results) return results;
this.pushViewModifierAndDeletePhrase("through", asset, "input");
} else if (asset.is.light_source && asset.is.on) {
// add asset to modifiers if it isn't already there
// if it's a viewport use "through"
results = this.tryWith(asset);
if ("undefined" !== typeof results) return results;
this.pushViewModifierAndDeletePhrase(
asset.is.viewport ? "through" : "with",
asset,
"input"
);
} else if (asset.is.light_source && !asset.is.on) {
// do nothing?
// you can still look at the thing
// though the (ex: unlit candle) will reveal nothing new
// delete phrase?
// I think leave it because if doSuccess sees it without
// it being a modifier, that's how it knows nothing new is revealed
} else {
// can "look with" asset?
results = this.tryWith(asset);
if ("undefined" !== typeof results) return results;
}
break;
case "through":
// is asset a viewport or has a through description?
if (asset.is.viewport) {
results = this.tryThroughViewport(asset);
if ("undefined" !== typeof results) return results;
// add asset to modifiers if it isn't already there
this.pushViewModifierAndDeletePhrase("through", asset, "input");
} else {
// can "look through" asset?
// is it right to ask this here when we're out of word sequence?
results = this.tryThroughDescription(asset);
if ("undefined" !== typeof results) return results;
}
break;
case "from":
// is subject nested within asset?
results = this.tryFrom(asset);
if ("undefined" !== typeof results) return results;
this.pushViewModifierAndDeletePhrase("from", asset, "input");
break;
case "in":
case "on":
case "under":
case "behind":
// we'll handle these next,
// in the normal parse-by-sentence-structure blocks
break;
default:
// ditto
break;
}
}
/**
* PARSE BY SENTENCE STRUCTURE
* The remainder of doTry follows standard verb handling.
*/
// sentence structure: verb
if (input.hasStructure("verb")) {
input.setPreposition(1, "at");
input.setAsset(1, room);
input.updateStructure();
return true;
} // verb
// sentence structure: verb preposition
if (input.hasStructure("verb preposition")) {
if (this.game.dictionary.getDirection(direct_preposition)) {
let exit = this.game.getExitFromDirection(direct_preposition);
// let exit = this.game.getRoom().exits[direct_preposition];
if (exit) exit = this.game.getAsset(exit);
if (exit) {
input.setAsset(1, exit);
input.setPreposition(1, "at");
input.setStructure("verb preposition noun");
}
return true;
}
this.game.debug(
`D1100 | ${this.name}.js | received preposition/${direct_preposition} with no noun, soft prompt noun1`
);
input.setSoftPrompt({ index: 1, type: "noun", noun1: true });
msg += `Look ${direct_preposition} what? `;
this.handleFailure(msg);
return null;
} // verb preposition
/**
* RESET LOCAL VARS
* though we initialized all our objects/prepositions
* at the beginning of doTry, it's likely that some
* or all of them were mutated during the modifier search
* and pre-processing by phrase.
*/
direct_object = input.getAsset(1);
direct_preposition = input.getPreposition(1);
direct_substance = input.getSubstance(1);
indirect_object = input.getAsset(2);
indirect_preposition = input.getPreposition(2);
indirect_substance = input.getSubstance(2);
indirect_object2 = input.getAsset(2);
indirect_preposition2 = input.getPreposition(2);
indirect_substance2 = input.getSubstance(2);
/**
* CHECK ORDER OF ASSETS IN SENTENCE STRUCTURE
* This check may be redundant after the modifier
* search and pre-processing, but we still need to
* verify that the view target is our direct object.
* If it's not, we need to reorder our phrases.
*/
let reordered = false;
if (
input.hasStructure("verb preposition noun preposition noun") &&
indirect_preposition === "at"
) {
// assuming player input something like
// look "through telescope at harbor" which is reasonable
// but we prefer "look at harbor through telescope"
input.swapPhrases(1, 2);
reordered = true;
}
if (
input.hasStructure(
"verb preposition noun preposition noun preposition noun"
) &&
indirect_preposition === "at"
) {
// assuming player input something like
// "look through telescope at boat in harbor" which is reasonable
// but we prefer "look at boat in harbor through telescope"
reordered = true;
// towers of hanoi
input.swapPhrases(1, 4);
input.swapPhrases(2, 1);
input.swapPhrases(3, 2);
input.swapPhrases(4, 3);
input.deletePhrase(4);
}
if (
input.hasStructure(
"verb preposition noun preposition noun preposition noun"
) &&
indirect_preposition2 === "at"
) {
// it seems unlikely that anyone would use this sentence structure
// but we'll still move "at asset" to direct object
reordered = true;
// towers of hanoi, again
input.swapPhrases(3, 4);
input.swapPhrases(2, 3);
input.swapPhrases(1, 2);
input.swapPhrases(4, 1);
input.deletePhrase(4);
}
if (reordered) {
// reset our local vars
this.game.debug(
`D1852 | ${this.name}.js | reordering phrases in sentence`
);
direct_object = input.getAsset(1);
direct_preposition = input.getPreposition(1);
direct_substance = input.getSubstance(1);
indirect_object = input.getAsset(2);
indirect_preposition = input.getPreposition(2);
indirect_substance = input.getSubstance(2);
indirect_object2 = input.getAsset(2);
indirect_preposition2 = input.getPreposition(2);
indirect_substance2 = input.getSubstance(2);
}
/**
* CHECK FOR SUBSTANCES
* Are any of our objects substances? If player input
* a substance, such as "look at sand", parser will have
* found a container and passed it along in the form of
* "asset:aspect:substance" such as "bucket:in:sand"
*/
if (direct_substance) {
// finding a direct_substance means player input something like
// "look at water" and the parser inferred a container as direct object
// we want to treat the substance as our direct object while still
// keeping a reference to the container
direct_container = direct_object;
direct_object = direct_substance;
}
if (indirect_substance) {
// finding an indirect_substance means player input something like
// "look at ducky in water" and the parser inferred a container as indirect object
// we want to treat the substance as our indirect object while still
// keeping a reference to the container
indirect_container = indirect_object;
indirect_object = indirect_substance;
}
if (indirect_substance2) {
// can't think of a case for this, but covering bases
indirect_container2 = indirect_object2;
indirect_object2 = indirect_substance2;
}
// verb enabled for direct object?
// seems unlikely that it wouldn't be, but anything's possible
if (!direct_object.isDOV(this.name)) {
this.game.debug(
`D2127 | ${this.name}.js | ${direct_object.id}.dov.${this.name}.enabled is false `
);
msg += `{We} can't ${this.name} ${
direct_preposition ? direct_preposition : ""
} ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// single use direct object?
// it seems unlikely you'd only be able to look at
// something once, but that's our universal pattern,
// which means we've committed to supporting it everywhere
// and maybe someone wants to make "you can only look once"
// the central conceit of their game
if (
direct_object.allowVerbOnce(this.name, "dov") &&
direct_object.didVerb(this.name, "dov")
) {
this.game.debug(
`D1659 | ${this.name}.js | ${direct_object.id}.dov.${this.name}.once and ${direct_object.id}.did.${this.name}.directly `
);
msg += `{We've} ${this.past_tense} ${
direct_preposition ? direct_preposition : "at"
} ${direct_object.articlename} enough. `;
this.handleFailure(msg);
return false;
}
// is direct object a substance?
if (direct_substance) {
this.game.debug(`D2142 | ${this.name}.js | found substance `);
// is indirect_object also a substance?
if (indirect_substance) {
// currently we don't handle "look at substance in substance"
// @FUTURE there might be situations where this makes sense
// such as a body of water with sand at its bottom "examine sand in water"
// or a colloidal suspension - or would that be a new substance?
this.game.debug(
`D1406 | ${this.name}.js | ${direct_object.id} and ${indirect_object.id} are both substances `
);
msg += `{We} can't see any ${direct_substance.name} in ${indirect_substance.name}. `;
this.handleFailure(msg);
return null;
} // indirect_substance
if (indirect_object) {
// if player input look at "substance in container"
// parser will have supplied a container that is not necessarily
// the same one specified by player
// so confirm that the specified container contains substance
// and if parser has supplied a different container, update that
if (indirect_preposition === "in") {
// if (["in","on","under","behind"].includes(indirect_preposition)) {
// though we pay lip service to storing substances
// in aspects other than "in", currently "in" is
// the only aspect that holds substances
let contained = indirect_object.containsSubstanceAt(
direct_substance.id,
indirect_preposition
);
if (!contained) {
// if player input "look at substance in container"
// and the container doesn't actually contain substance
// if neither contained nor described then we've got nothing to work with
this.game.debug(
`D1651 | ${this.name}.js | ${indirect_object.id}${
indirect_preposition ? ".aspects." + indirect_preposition : ""
} doesn't contain ${direct_substance.id} `
);
msg += `{We} can't see any ${direct_substance.name} ${
indirect_preposition ? indirect_preposition : "in"
} ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// did parser identify a different substance container
// from the one specified by player?
if (direct_container.id !== indirect_object.id) {
input.setContainer(1, indirect_object);
direct_container = indirect_object;
}
input.deletePhrase(2);
} // in
}
// if we get here, we have a substance and a container
input.pushViewModifier("in", direct_container, "auto"); // it's auto even if player specified container
return true;
} // substance
if (
input.hasStructure("verb preposition noun") &&
input.parsedNoun1.matches.direction
) {
if ("at" === direct_preposition) {
return true;
}
if (!direct_object.hasDescription(direct_preposition)) {
this.game.debug(
`D1587 | ${this.name}.js | ${direct_object.id}.descriptions.${direct_preposition} is unset`
);
msg += `{We} {don't} know how to ${this.name} ${direct_preposition} ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
return true;
}
// sentence structure: verb preposition noun
if (input.hasStructure("verb preposition noun")) {
// no blockers, pass to success
if ("at" === direct_preposition) {
return true;
}
if (
["in", "on", "under", "behind"].includes(direct_preposition) &&
!direct_object.hasAspectAt(direct_preposition)
) {
this.game.debug(
`D2141 | ${this.name}.js | ${direct_object.id}.aspects.${direct_preposition} is unset`
);
msg += `{We} {don't} see anything ${direct_preposition} ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// no aspect for this preposition
if (
!direct_object.hasDescription(direct_preposition) &&
!direct_object.hasAspectAt(direct_preposition)
) {
this.game.debug(
`D1017 | ${this.name}.js | ${direct_object.id}.aspects.${direct_preposition} is not defined`
);
msg += `{We} can't see anything ${direct_preposition} ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
return true;
} // verb noun / verb preposition noun
// sentence structure: verb noun preposition noun / verb preposition noun preposition noun
else if (
input.hasStructure("verb noun preposition noun") ||
input.hasStructure("verb preposition noun preposition noun")
) {
// "look at x with y" and "look at x through y" are the only
// versions of this we accept
// what about "look through window with telescope" ?
// this should get caught by sentence structure check
// in parseInput.js but leaving it here for now
if (!indirect_preposition) {
this.game.debug(`D1228 | ${this.name}.js | no indirect_preposition`);
msg += `{We} can't look ${direct_preposition} ${direct_object.articlename} ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
if (
indirect_preposition === "with" &&
indirect_object.hasQuirk("look_with_means_look_through")
) {
this.game.debug(
`D1848 | ${this.name}.js | direct_preposition 'with' means 'through'`
);
indirect_preposition = "through";
input.setPreposition(2, "through");
}
if (indirect_preposition === "with") {
results = this.tryWith(indirect_object);
if ("undefined" !== typeof results) return results;
} else if (indirect_preposition === "through") {
this.game.debug(
`D1849 | ${this.name}.js | direct_preposition 'through'`
);
results = this.tryThroughViewport(indirect_object);
if ("undefined" !== typeof results) return results;
results = this.tryThroughDescription(indirect_object);
if ("undefined" !== typeof results) return results;
} else if (indirect_preposition === "out") {
// try to treat "out" like "through"
this.game.debug(`D1387 | ${this.name}.js | direct_preposition 'out'`);
results = this.tryThroughViewport(indirect_object);
if ("undefined" !== typeof results) return results;
}
// from is a special case where subject
// must be nested in the object
else if (indirect_preposition === "from") {
this.game.debug(
`D1850 | ${this.name}.js | direct_preposition 'from'`
);
results = this.tryFrom(indirect_object);
if ("undefined" !== typeof results) return results;
} // from
// TRY > TWONOUNS > AT > NO INDIRECT ASPECT
// assume indirect preposition is aspect
// and check for it
else if (!indirect_object.hasAspectAt(indirect_preposition)) {
this.game.debug(
`D1226 | ${this.name}.js | ${indirect_object.id} has no ${indirect_preposition} aspect`
);
msg += `${direct_object.Articlename_is} not ${indirect_preposition} ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
}
// TRY > TWONOUNS > AT > NO PLACE
// if indirect_object has aspect, check if direct_object is in it
else if (
indirect_object.hasAspectAt(indirect_preposition) &&
!direct_object.isPlacedAtAspectAndAsset(
indirect_preposition,
indirect_object.id
)
) {
this.game.debug(
`D1225 | ${this.name}.js | ${direct_object.id} not ${indirect_preposition} ${indirect_object.id}`
);
msg += `${direct_object.Articlename_is} not ${indirect_preposition} ${indirect_object.articlename}. `;
this.handleFailure(msg);
return null;
} else if (
direct_preposition !== "at" &&
!direct_object.hasAspectAt(direct_preposition)
) {
this.game.debug(
`D1227 | ${this.name}.js | ${direct_preposition} is not at`
);
msg += `{We} can't look ${indirect_preposition} ${indirect_object.articlename} ${direct_preposition} ${direct_object.articlename}. `;
this.handleFailure(msg);
return null;
}
} // verb noun preposition noun / verb preposition noun preposition noun
return true;
},
doSuccess: function () {
var input = this.game.getInput();
var subject = input.getSubject();
var adverb = input.getAdverb();
var nest_asset = subject.getNestAsset();
var room = this.game.getRoom();
var msg = "";
var direct_object = input.getAsset(1);
var direct_preposition = input.getPreposition(1);
var direct_substance = input.getSubstance(1);
var direct_container;
var direct_container_preposition;
var player_specified_container =
input.verified_sentence.phrase1.player_specified_container;
var indirect_object = input.getAsset(2);
var indirect_preposition = input.getPreposition(2);
var indirect_substance = input.getSubstance(2);
var indirect_container;
var indirect_object2 = input.getAsset(3);
var indirect_preposition2 = input.getPreposition(3);
var indirect_substance2 = input.getSubstance(3);
var indirect_container2;
if (subject.id !== this.game.getPlayer().id) {
msg += `${subject.articlename} glances
${
direct_object && direct_object.hasClass("Room")
? "around"
: direct_object
? "towards " + direct_object.articlename
: "around"
}. `;
return this.handleSuccess(msg);
}
if (direct_substance) {
direct_container = direct_object;
direct_object = direct_substance;
direct_container_preposition = direct_container.getVessel().preposition;
}
if (indirect_substance) {
indirect_container = indirect_object;
indirect_object = indirect_substance;
}
if (indirect_substance2) {
indirect_container2 = indirect_object2;
indirect_object2 = indirect_substance2;
}
// room?
if (direct_object.id === room.id) {
this.game.printRoom({ verbose: true });
return this.handleSuccess(msg);
}
// global?
else if (direct_object.is.global) {
msg += this.game.getGlobalAssetDescription(direct_object);
} // is.global
// direction?
else if (direct_object.direction || direct_object.hasClass("Exit")) {
msg +=
this.game.getModifiedDescription({
asset: direct_object,
identifier: direct_preposition,
fallback_base: true,
}) ||
`{We} see a passage leading ${direct_object.direction}${
direct_object.destination && direct_object.is.used
? " to the " + direct_object.destination
: ""
}. `;
} // direction
// substance
else if (direct_substance) {
// did player specify the container?
// if not, identify the container we chose
if (!player_specified_container) {
if (direct_container.is.reservoir) {
// if it's a reservoir print it as an inference, because duh
// this.game.print(
// `(in ${direct_container.articlename})`,
// "inference"
// );
msg += `{We} consider the ${direct_substance.name} of ${direct_container.articlename}. `;
} else {
// otherwise prepend output to indicate what we found
msg += `{We} see some ${direct_substance.name} ${direct_container_preposition} ${direct_container.articlename}. `;
}
}
// if player input "look in water" convert to "look at water"
if ("in" === direct_preposition) {
direct_preposition = "at";
}
if ("at" === direct_preposition) {
msg += this.game.getModifiedDescription({
asset: direct_object,
identifier: direct_preposition,
fallback_base: true,
});
// also make known the contents of its container
subject.knowAspect(
direct_container,
direct_container_preposition,
true
);
if (
!direct_container.hasClass("Room") &&
direct_container.aspects[direct_container_preposition]
.list_contents_in_examine
) {
msg += direct_container.getPrintableListOfContentsAt(
direct_container_preposition,
{ exclude_substance: true }
);
}
} else {
this.game.debug(
`D1048 | ${this.name}.js | not at, ${direct_preposition} ${direct_substance.id}`
);
msg += this.game.getModifiedDescription({
asset: direct_substance,
identifier: direct_preposition,
fallback_base: true,
});
subject.knowAspect(
direct_container,
direct_container_preposition,
true
);
if (!direct_container.hasClass("Room")) {
msg += direct_container.getPrintableListOfContentsAt(
direct_container_preposition,
{ caller: "examine", exclude_substance: true }
);
}
if (!msg) {
msg += `Looking ${adverb ? adverb : ""} ${
direct_preposition ? direct_preposition : "at"
} ${direct_object.articlename} doesn't reveal anything notable. `;
}
}
}
// tangible / general conditions
else {
if (
"in" === direct_preposition &&
direct_object.isDOV("close") &&
direct_object.is.closed &&
1 >= direct_object.appearance.opacity
) {
// closed things need to be open or transparent to see inside
msg +=
this.game.getModifiedDescription({
asset: direct_object,
identifier: direct_preposition,
}) ||
`{We} can't see into ${direct_object.articlename} while it's closed. `;
}
if ("at" === direct_preposition) {
msg += this.game.getModifiedDescription({
asset: direct_object,
identifier: direct_preposition,
fallback_base: true,
});
// if it's tangible, also print a complete aspect list
this.game.log(
"L1330",
"log",
"high",
`[${this.name}.js] at: print ${direct_object.id}.aspects`,
"Verbs"
);
for (let item in direct_object.aspects) {
let aspect = direct_object.aspects[item];
if (
aspect.name === "in" &&
direct_object.isDOV("open") &&
direct_object.is.closed &&
direct_object.appearance.opacity >= 1
) {
// it's closed and opaque
continue;
}
if (aspect.know_contents_with_parent) {
subject.knowAspect(direct_object, aspect, true);
}
if (!aspect.list_contents_in_examine) {
continue;
}
msg += direct_object.getPrintableListOfContentsAt(aspect.name, {});
} // for
// at
} else if (
direct_object.hasAspectAt(direct_preposition) ||
direct_object.hasDescription(direct_preposition)
) {
this.game.debug(
`D1051 | ${this.name}.js | not at, hasAspectAt || hasDescription`
);
msg += this.game.getModifiedDescription({
asset: direct_object,
identifier: direct_preposition,
fallback_base: false,
});
if (direct_object.hasAspectAt(direct_preposition)) {
subject.knowAspect(direct_object, direct_preposition, true);
msg +=
(direct_object.getPrintableListOfContentsAt &&
direct_object.getPrintableListOfContentsAt(direct_preposition, {
caller: "examine",
exclude_substance: true,
})) ||
``;
}
} else {
msg +=
(direct_object.getPrintableListOfContents &&
direct_object.getPrintableListOfContents({
caller: "examine",
})) ||
`Looking ${adverb ? adverb : ""} ${
direct_preposition ? direct_preposition : "at"
} ${direct_object.articlename} doesn't reveal anything notable. `;
}
// anything written on it?
if (direct_object.appearance.scribbles) {
msg += `A few scribbles have been drawn on it. `;
}
if (
direct_object.written_strings.length &&
direct_object.append_written_strings_to_description
) {
if (1 === direct_object.written_strings.length) {
msg += `A line of text has been written on it in ${
this.game.settings.apply_color_classes_to_written_strings
? direct_object.written_strings[0].color
: ""
} ${direct_object.written_strings[0].class.toLowerCase()}: `;
msg += `<br> <span class="${direct_object.written_strings[0].class.toLowerCase()} ${
direct_object.written_strings[0].color
}">"${direct_object.written_strings[0].data}"</span>`;
} else {
msg += `Several lines of text have been written on it: `;
for (var i = 0; i < direct_object.written_strings.length; i++) {
msg += `<br> <span class="string ${direct_object.written_strings[i].class.toLowerCase()} ${
this.game.settings.apply_color_classes_to_written_strings
? direct_object.written_strings[i].color
: ""
}">"${direct_object.written_strings[i].data}"</span>`;
}
}
msg = msg.trim();
msg += `. `;
}
// anything typed on it?
if (
direct_object.typed_strings.length &&
direct_object.append_typed_strings_to_description
) {
if (1 === direct_object.typed_strings.length) {
msg += `A line of text has been typed on it: `;
msg += `<br> "${direct_object.typed_strings[0]}"`;
} else {
msg += `Several lines of text have been typed on it: `;
for (var i = 0; i < direct_object.typed_strings.length; i++) {
msg += `<br> "${direct_object.typed_strings[i]}"`;
}
}
}
// anything drawn on it?
if (direct_object.drawn_things?.length) {
if (direct_object.drawn_things.length === 1) {
msg += `${A.capitalize(direct_object.drawn_things[0].data)} has been drawn there in ${
this.game.settings.apply_color_classes_to_drawn_things
? direct_object.drawn_things[0].color
: ""
} ${direct_object.drawn_things[0].class.toLowerCase()}. `;
} else {
msg += `Some things been drawn there: `;
for (let i = 0; i < direct_object.drawn_things.length; i++) {
if (i > 0 && i < direct_object.drawn_things[i].length - 1) {
msg += ", ";
}
if (
direct_object.drawn_things[i].length > 1 &&
i === direct_object.drawn_things[i].length - 1
) {
msg += " and ";
}
msg += `a ${direct_object.drawn_things[i].data}`;
}
msg += ". ";
}
}
// connections
if (direct_object.isConnectedToAnything("tie", "to_iov")) {
// tie this to that
let objects = {
objects: direct_object.getVerbConnections("tie", "to_iov"),
};
msg += `${direct_object.Articlename_is} tied to `;
msg += this.game.getPrintableObjectList(objects);
msg += direct_object.isWithin(subject)
? `, while {we} hold an end of it`
: ``;
msg = msg.trim();
msg += `. `;
// @TODO draw distinction between carrying vs holding
} else if (direct_object.isConnectedToAnything("tie", "to_dov")) {
// tie that to this
let connections = direct_object.getVerbConnections("tie", "to_dov");
for (let r = 0; r < connections.length; r++) {
let rope = this.game.getAsset(connections[r]);
msg += `Tied to ${direct_object.articlename} is a ${rope.name}`;
if (1 < rope.getVerbConnectionCount("tie", "to_iov")) {
let objects = {
objects: rope.getVerbConnections("tie", "to_iov"),
exclusions: direct_object.id,
};
msg += `, which is also tied to ${this.game.getPrintableObjectList(
objects
)}`;
}
msg += rope.isWithin(subject)
? `, while {we} hold an end of it`
: ``;
msg = msg.trim();
msg += `. `;
}
}
} // general tangible
if (input.view_modifiers.length) {
let intro = "";
let outro = "";
let middle = "";
let count = 0;
let adverb_modifier = "";
for (let i = 0; i < input.view_modifiers.length; i++) {
let modifier = input.view_modifiers[i];
if (modifier.type === "input" && !modifier.used) {
if (modifier.adverb) {
adverb_modifier = modifier.identifier;
continue;
}
let comma = count === 0 ? "" : ",";
count++;
middle += comma;
middle += ` ${modifier.identifier} ${
modifier.asset ? modifier.asset.articlename : ""
}`;
middle += comma;
}
}
intro += `Looking ${adverb_modifier ? adverb_modifier : ""} `;
intro += `${direct_preposition ? direct_preposition : "at"} `;
intro += `${direct_object.articlename}`;
outro += " reveals nothing new. ";
if (count > 1) middle = ", " + middle;
if (middle) msg = intro + middle + outro + msg;
}
if (!msg) {
// fallback in case there is absolutely no description
this.game.debug(`D1031 | ${this.name}.js | no description found`);
msg += `Looking ${adverb ? adverb : ""} ${
direct_preposition ? direct_preposition : "at"
} ${direct_object.articlename} doesn't reveal anything notable. `;
}
return this.handleSuccess(msg);
}, // doSuccess
tryThroughViewport: function (asset) {
var msg = "";
// @todo If item is in inventory, not worn, see if it can be
// worn, allow it, then take it out on doSuccess.
if (asset.must.wear_to_look_through && !asset.is.worn) {
this.game.debug(
`D1015 | ${this.name}.js | ${asset.id}.must.wear_to_look_through and ${asset.id}.is.worn is false`
);
msg += `{We're} not wearing ${asset.articlename}. `;
this.handleFailure(msg);
return null;
}
// @todo If item is in inventory, not in hands, see if it can be
// taken, allow it, then take it out on doSuccess.
if (
asset.must.hold_to_see_through &&
!this.game.parser.selectInHands(asset.id).length
) {
this.game.debug(
`D1014 | ${this.name}.js | ${asset.id}.must.hold_to_see_through and ${asset.id} is not held`
);
msg += `{We're} not holding ${asset.articlename}. `;
this.handleFailure(msg);
return null;
}
},
tryThroughDescription: function (asset) {
var msg = "";
if (!asset.hasDescription("through")) {
this.game.debug(
`D1851 | ${this.name}.js | ${asset.id}.descriptions.through not found`
);
if (1 < asset.appearance.opacity) {
msg += `Though ${asset.articlename} is
${
asset.appearance.opacity > 0.5 ? "translucent" : "transparent"
},
{we} can't ${this.name} through it. `;
} else {
msg += `{We} can't ${this.name} through ${asset.articlename}. `;
}
this.handleFailure(msg);
return null;
}
},
tryWith: function (asset) {
var msg = "";
// can subject look with this object?
if (!asset.isIOV("look")) {
this.game.debug(
`D1224 | ${this.name}.js | ${asset.id}.iov.look.enabled is false`
);
msg += `{We} can't look with ${asset.articlename}. `;
this.handleFailure(msg);
return null;
}
// @todo If item is in inventory, not worn, see if it can be
// worn, allow it, then take it out on doSuccess.
if (asset.must.wear_to_look_with && !asset.is.worn) {
this.game.debug(
`D1845 | ${this.name}.js | ${asset.id}.must.wear_to_look_with and ${asset.id}.is.worn is false`
);
msg += `{We're} not wearing ${asset.articlename}. `;
this.handleFailure(msg);
return null;
}
// @todo If item is in inventory, not in hands, see if it can be
// taken, allow it, then take it out on doSuccess.
if (
asset.must.hold_to_see_with &&
!this.game.parser.selectInHands(asset.id).length
) {
this.game.debug(
`D2140 | ${this.name}.js | ${asset.id}.must.hold_to_see_with and ${asset.id} is not held`
);
msg += `{We're} not holding ${asset.articlename}. `;
this.handleFailure(msg);
return null;
}
},
tryFrom: function (asset) {
var msg = "";
// is subject nested in the object? that's the only way to look from it
// if so just let it go so we can print that
if (
asset.id === this.game.getInput().getSubject().getNestOrPlaceAsset().id
) {
return;
} else {
this.game.debug(
`D1016 | ${this.name}.js | subject not nested within ${asset.id}`
);
msg += `{We're} not ${asset.default_aspect} ${asset.articlename}. `;
this.handleFailure(msg);
return null;
}
},
// view modifiers such as lenses and light sources are saved
// to the input object for use with getModifiedDescription()
pushViewModifierAndDeletePhrase: function (identifier, asset, type) {
let input = this.game.getInput();
for (let m = 0; m < input.view_modifiers.length; m++) {
// it's possible that this asset was already found
// in which case we only want to update the type
// exclude adverbs
if (
input.view_modifiers[m].asset &&
asset.id === input.view_modifiers[m].asset.id
) {
input.view_modifiers[m].type = type;
return;
}
}
for (let phrase = input.getPhraseCount(); phrase > 0; phrase--) {
let inputprep = input.getPreposition(phrase);
let inputasset = input.getAsset(phrase);
if (inputprep === identifier && inputasset?.id === asset.id) {
input.deletePhrase(phrase);
// though we may have already found it automatically,
// note that player input it
type = "input";
}
}
if (identifier) {
input.pushViewModifier(identifier, asset, type);
}
},
};
})();