Pre-release
AdventureJS Docs Downloads
Score: 0 Moves: 0
// splitInput.js

(function () {
  /* global adventurejs A */

  var p = adventurejs.Parser.prototype;

  /**
   * Calls split by periods and enqueues the results.
   * @memberOf adventurejs.Parser
   * @method adventurejs.Parser#splitInput
   * @param {String} input
   * @returns {String}
   *
   * @TODO multi-turn handling for instructions given to NPCs
   * ex: Roger, go east then drop lamp
   *
   */
  p.splitInput = function Parser_splitInput(input) {
    this.game.log(
      "L1605",
      "log",
      "high",
      `[splitInput.js] splitInput() receive: ${input}`,
      "Parser"
    );

    const game = this.game;
    const subject = this.input_history[0].subject;

    const isAbbrev = function (word) {
      if (!word) return false;
      return game.dictionary.getAbbreviation(word.toLowerCase());
    };
    const isAsset = function (word) {
      if (!word) return false;
      return "undefined" !== typeof game.world_lookup[word.toLowerCase()];
    };
    const isVerb = function (word) {
      if (!word) return false;
      if (word.endsWith(".")) {
        word = word.slice(0, -1);
      }
      return null !== game.dictionary.getVerb(word);
    };
    const isDirection = function (word) {
      if (!word) return false;
      if (word.endsWith(".")) {
        word = word.slice(0, -1);
      }
      return false !== game.dictionary.getDirection(word);
    };

    const this_turn = this.input_history[0];
    const last_turn = this.input_history[1];

    const sentences = [];
    const words = input.trim().split(" ");
    let current = [];

    for (let i = 0; i < words.length; i++) {
      let word = words[i];
      let boundary = false;
      this.game.log(
        "L1609",
        "log",
        "high",
        `[splitInput.js] splitInput() found word: ${word}`,
        "Parser"
      );

      // try to get next word
      const word_is_verb = isVerb(word);
      const next_word = words[i + 1]?.toLowerCase();
      const next_word_is_verb = isVerb(next_word);
      const next_word_is_direction = isDirection(next_word);

      // two periods? means abbreviation AND we converted from then
      if (word.endsWith("..")) {
        word = word.replace("..", ".");
        boundary = true;
      }

      const lower = word.toLowerCase();
      const is_abbrev = isAbbrev(lower);
      const is_assets = isAsset(lower);

      // no next word = end of sentence regardless of anything else
      if (!next_word) {
        if (word.endsWith(".") && !is_abbrev && !is_assets) {
          // strip trailing periods
          word = word.slice(0, -1);
        }
        boundary = true;
      }

      if (word.endsWith(".") && next_word_is_verb) {
        if (!is_abbrev && !is_assets) {
          // strip trailing periods
          word = word.slice(0, -1);
        }
        boundary = true;
      }

      if (boundary) {
        current.push(word);
        sentences.push(current.join(" "));
        current = [];
        continue;
      }

      // no boundary
      // does word end with period?
      if (word.endsWith(".")) {
        // is it an abbreviation or an asset id?
        if (is_abbrev || is_assets) {
          // let it pass as is unless next word is verb
          current.push(word);
          continue;
        } else {
          // we think it's a sentence boundary
          word = word.slice(0, -1);
          current.push(word);
          sentences.push(current.join(" "));
          current = [];
          continue;
        }
      }

      // if we haven't operated on the word yet, just push it
      current.push(word);
    }

    // --------------------------------------------------

    if (1 === sentences.length) {
      // single clause found, use input as is

      // did player enter "again" ?
      // if so, copy last turn into this turn
      if (this.game.dictionary.testVerbSynonyms(input, "again")) {
        input = last_turn.input;
        this_turn.input = input;
      }
      // else input = sentences[0];
    } else if (sentences.length > 1) {
      // player entered multiple clauses

      // is first item in queue "again"?
      // replace with last turn
      if (this.game.dictionary.testVerbSynonyms(sentences[0], "again")) {
        sentences[0] = last_turn.input;
      }

      // is any other item in queue "again"?
      // replace with the turn preceding it in the queue
      for (var i = 1; i < sentences.length; i++) {
        if (this.game.dictionary.testVerbSynonyms(sentences[i], "again")) {
          sentences[i] = sentences[i - 1];
        }
      }

      // use the first one now
      input = sentences.shift();

      // queue up the rest for subsequent turns
      for (var i = 0; i < sentences.length; i++) {
        this.input_queue.push({
          input: sentences[i],
          normalized_input: sentences[i],
          printInput: true,
          quote_tokens: this_turn.quote_tokens,
          raw_input: this_turn.raw_input,
          subject: subject,
        });
      }
    }

    this.game.log(
      "L1606",
      "log",
      "high",
      `[splitInput.js] splitInput() return: ${input}`,
      "Parser"
    );
    return input;
  };
})();