// tokenizeCommands.js
(function () {
/* global AdventureJS A */
var p = AdventureJS.Parser.prototype;
/**
* Look for an NPC directive in the form of
* input that begins with a character name.
* The name may or may not be followed by
* a comma, as in "Conan, give me the ax"
*
* If the input starts with one word followed by a comma, we
* always take it to mean that a character has been addressed
* and issue a success or failure depending on circumstances.
* ie: "roger, make shrubbery"
*
* If we find a character directive, we save
* a record of the target character back to the input.
* @memberOf AdventureJS.Parser
* @method AdventureJS.Parser#tokenizeCommands
* @param {String} input Player input.
* @returns {String|Boolean}
*/
p.tokenizeCommands = function Parser_tokenizeCommands(input) {
this.game.log(
"L1610",
"log",
"high",
`[tokenizeCommands.js] tokenizeCommands() receive: ${input}`,
"Parser"
);
let this_turn = this.input_history[0];
let player = this.game.getPlayer();
// OLD
// look for first word ending in ", " comma and space
// const pattern = /^([A-Za-z.'. ]+?),\s/;
// const match = input.match(pattern);
// if (!match) {
// return input;
// }
// const name = match[1]; // Captures the name before the comma
// const remaining = input.slice(match[1].length + 2, input.length);
// const parsed_noun = this.parseNoun(name);
// NEW
const input_array = input.split(/\s+/);
const word_count = input_array.length;
console.warn({ word_count });
if (word_count.length < 2) {
return input; // one word can't be a directive
}
let word1 = input_array[0];
let word2 = input_array[1];
let comma;
if (word1.endsWith(",")) {
word1 = word1.slice(0, -1);
comma = true; // likely to be a directive
}
input_array.splice(0, 1); // remove word1
const remaining = input_array.join(" ");
const parsed_noun = this.parseNoun(word1);
let word2_is_verb;
if (word2) word2_is_verb = this.parseVerb(word2);
console.warn({ comma, word2_is_verb });
// if we didn't find a comma and the next
// word isn't a verb we have no reason to
// think this is a directive so just resume parse
if (!comma && !word2_is_verb) return input;
let char;
let chars = [];
let msg = "";
let debug = "";
// if the first word is followed by a comma then we
// understand it to be a directive even if we don't
// find a character
if (comma) {
switch (parsed_noun.matches.qualified.length) {
case 0:
// no asset found
msg = `{We} {don't} know of anyone named ${word1}. `;
debug = "not found";
break;
case 1:
// found an asset
char = this.game.getAsset(parsed_noun.matches.qualified[0]);
if (!char) {
msg = `{We} {don't} know of anyone named ${word1}. `;
debug = "not found";
break;
} else if (!player.knowsAbout(char)) {
msg = `{We} {don't} know of anyone named ${word1}. `;
debug = "not known";
break;
} else if (!char.hasClass("Character")) {
msg = char.is.present
? `${char.Article_name} ignores {us}. `
: `{We} {don't} see any ${word1} here. `;
debug = "not a character";
break;
} else {
if (!char.is.present) {
msg = `{We} {don't} see ${char.article_name} here. `;
debug = "not present";
break;
}
}
break;
default:
// found multiple assets
// can we find a singular character?
for (let i = 0; i < parsed_noun.matches.qualified.length; i++) {
let asset = this.game.getAsset(parsed_noun.matches.qualified[i]);
if (asset.hasClass("Character") && asset.is.present) {
chars.push(asset);
}
}
switch (chars.length) {
case 0:
msg = `No one named ${word1} is present. `;
debug = `not found`;
break;
case 1:
char = chars[0];
break;
default:
msg = `{We'll} have to be more specific. `;
debug = `not unique`;
break;
}
break;
}
}
// if no comma was found we have no particular reason to
// think the first noun is a character but we're testing
// just to be sure.
else if (word2_is_verb) {
switch (parsed_noun.matches.qualified.length) {
case 0:
// no asset found
// no need to debug or print, just return input
// if it's an error it'll be handled elsewhere
return input;
case 1:
// found an asset
char = this.game.getAsset(parsed_noun.matches.qualified[0]);
if (!char || !char.hasClass("Character")) {
// no character asset found
// no need to debug or print, just return input
// if it's an error it'll be handled elsewhere
return input;
} else if (!player.knowsAbout(char)) {
msg = `{We} {don't} know of anyone named ${word1}. `;
debug = "not known";
break;
} else if (!char.is.present) {
msg = `{We} {don't} see ${char.article_name} here. `;
debug = "not present";
break;
}
break;
default:
// found multiple assets
// are any of them characters?
for (let i = 0; i < parsed_noun.matches.qualified.length; i++) {
let asset = this.game.getAsset(parsed_noun.matches.qualified[i]);
if (asset.hasClass("Character") && asset.is.present) {
chars.push(asset);
}
}
// are they all characters?
if (chars.length === parsed_noun.matches.qualified.length) {
switch (chars.length) {
case 1:
char = chars[0];
break;
default:
msg = `{We'll} have to be more specific. `;
debug = `not unique`;
break;
}
}
break;
}
}
if (msg) {
// any msg means we failed to identify a target character
this.game.log(
"L1596",
"warn",
"high",
`[tokenizeCommands.js] ${word1} is ${debug}`,
"Parser"
);
this.game.debug(`D1178`, `tokenizeCommands.js `, ` ${word1} is ${debug}`);
this.game.print(msg);
return false;
}
if (char) {
this_turn.setSubject(char);
// return remaining;
input = remaining;
}
this.game.log(
"L1706",
"log",
"high",
`[tokenizeCommands.js] tokenizeCommands() return: ${input}`,
"Parser"
);
return input;
};
})();