Pre-release
AdventureJS Docs Downloads
Score: 0 Moves: 0
// 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;
  };
})();