Pre-release
Adventure.js Docs Downloads
Score: 0 Moves: 0
// qualifyParsedNoun.js

(function () {
  /*global adventurejs A*/
  "use strict";

  var p = adventurejs.Parser.prototype;

  /**
   * Exclude nouns found by parseNoun that don't meet qualifications for verb found by parseVerb.
   * @memberOf adventurejs.Parser
   * @method adventurejs.Parser#qualifyParsedNoun
   * @param {Object} params
   * @returns {adventurejs.parsedNoun}
   */
  p.qualifyParsedNoun = function Parser_qualifyParsedNoun(params) {
    this.game.log("log", "high", "qualifyParsedNoun.js > BEGIN", "Parser");
    //console.warn( "qualifyParsedNoun params: ", params );
    var input = this.game.getInput();
    var parsedNoun = params.parsedNoun;
    var parsedVerb = params.parsedVerb;
    var nounIndex = params.nounIndex;
    var player = this.game.getPlayer();
    var output_class = "";
    // var roomObjects = this.game.getCurrentRoom().getListableContents();
    // var playerObjects = player.getListableContents();
    var msg = "";
    var prettyverb = this.dictionary.verbs[parsedVerb].prettyname;

    var i, index, query, msg;
    var mustBe =
      this.dictionary.verbs[parsedVerb]["phrase" + nounIndex].noun_must_be;

    if (mustBe.known) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.known receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      let qualified_id, unparsed_input;
      if (1 === parsedNoun.matches.qualified.length) {
        qualified_id = parsedNoun.matches.qualified[0];
      }
      parsedNoun.matches.qualified = this.selectKnown(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        /**
         * Try to get original player input for this object.
         * Player might have entered a partial name for this.
         * Since player doesn't know this object, if they input
         * a partial name, we might accidentally reveal too
         * much information if we return the full name.
         * ex player asks for "sword" and we return "cursed bronze sword"
         * Now player knows there is a cursed bronze sword.
         */
        if ("undefined" !== typeof qualified_id) {
          unparsed_input =
            this.game.getInput().replacements[qualified_id].source;
        }
        if ("undefined" !== typeof unparsed_input) {
          this.game.debug(
            `F1056 | qualifyParsedNoun.js | ${parsedVerb} phrase ${nounIndex}.noun.mustBe.known`
          );
          msg += `$(We) don't know of any ${unparsed_input}. `;
        } else {
          this.game.debug(
            `F1057 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.known`
          );

          // This response doesn't read well if player has asked for a substance.
          // msg += "$(We) don't know of anything matching that description. ";

          // This response is a little too anonymous.
          // msg += "$(We) don't see any of that here. ";

          // This response is sketchy because player input might have been substituted
          // with a list of possible matches.
          msg += `$(We) don't know of any ${A.deserialize(parsedNoun.input)}. `;
        }
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none known ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > known " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.present) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.present receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      let qualified_id, unparsed_input;
      if (1 === parsedNoun.matches.qualified.length) {
        qualified_id = parsedNoun.matches.qualified[0];
      }
      parsedNoun.matches.qualified = this.selectPresent(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        if (!parsedNoun.matches.qualified.length) {
          this.game.debug(
            `F1067 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.present`
          );
          // try to get original player input for this object
          if ("undefined" !== typeof qualified_id) {
            unparsed_input =
              this.game.getInput().replacements[qualified_id].source;
          }
          if ("undefined" !== typeof unparsed_input) {
            msg += `There doesn't appear to be any ${unparsed_input} present. `;
          } else {
            msg += `There doesn't appear to be any ${parsedNoun.deserialized_input} present. `;
          }
        }
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none present ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > present " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.present_if_tangible) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.present receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      let qualified_id, unparsed_input;

      if (!parsedNoun.matches.qualified.length) {
        qualified_id = parsedNoun.matches.qualified[0];
      }

      parsedNoun.matches.qualified = this.selectPresentIfTangible(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        if (!parsedNoun.matches.qualified.length) {
          this.game.debug(
            `F1596 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.present_if_tangible`
          );
          // try to get original player input for this object
          if ("undefined" !== typeof qualified_id) {
            unparsed_input =
              this.game.getInput().replacements[qualified_id].source;
          }
          if ("undefined" !== typeof unparsed_input) {
            msg += `There doesn't appear to be any ${unparsed_input} present. `;
          } else {
            msg += `There doesn't appear to be any ${parsedNoun.deserialized_input} present. `;
          }
        }
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none present_if_tangible ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > present " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.direction) {
      if (false === parsedNoun.matches.direction) {
        this.game.debug(
          `F1054 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.direction`
        );
        msg += `It appears that $(we) meant to specify a direction, but that wasn't recognized as such. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none direction ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > direction " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_direction) {
      if (parsedNoun.matches.direction) {
        this.game.debug(
          `F1055 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_direction`
        );
        msg += `$(We) can't ${prettyverb} a direction. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_direction ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_direction " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_global) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_global receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotGlobal(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1058 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_global`
        );
        msg += `$(We) can't ${input.input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_global ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_global " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_scenery) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_scenery receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotScenery(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1059 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_scenery`
        );
        msg += `$(We) can't ${input.input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_scenery ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_scenery " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_exit) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_exit receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotExit(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1060 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_exit`
        );
        msg += `$(We) can't ${input.input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_exit ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_exit " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.intangible) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.intangible receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectIntangible(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1061 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.intangible`
        );
        msg += `No intangible "${parsedNoun.deserialized_input}" to ${prettyverb}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none intangible ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > intangible " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_substance) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_substance receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotSubstance(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1062 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_substance`
        );
        msg += `$(We) need to specify a source. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_substance ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_substance " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.matter) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.matter receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectMatter(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1534 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.matter`
        );
        msg += `$(We) can't ${prettyverb} ${parsedNoun.deserialized_input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none matter ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > matter " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.tangible) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.tangible receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectTangible(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1063 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.tangible`
        );
        msg += `$(We) don't see any ${parsedNoun.deserialized_input} to ${prettyverb}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none tangible ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > tangible " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    // if(mustBe.tangible_or_substance)
    // {
    //   this.game.log( "log", "high", "qualifyParsedNoun.js > mustBe.tangible_or_substance receives: " + parsedNoun.matches.qualified , 'Parser' );
    //   parsedNoun.matches.qualified = this.selectTangibleOrSubstance( parsedNoun.matches.qualified );
    //   if( !parsedNoun.matches.qualified.length )
    //   {
    //     this.game.debug(` | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.tangible_or_substance`);
    //     msg += `$(We) don't see any "${parsedNoun.deserialized_input}" $(we) can ${this.dictionary.verbs[ parsedVerb ].prettyname}. `;
    //     if(msg) this.game.print( msg, output_class );
    //     this.game.log( "log", "high", "qualifyParsedNoun.js > none tangible_or_substance " , 'Parser' );
    //     return false;
    //   }
    //   this.game.log( "log", "high", "qualifyParsedNoun.js > tangible_or_substance " + parsedNoun.matches.qualified , 'Parser' );
    // }

    if (mustBe.global_substance) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.global_substance receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectGlobalSubstance(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1064 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.global_substance`
        );
        msg += `$(We) can't ${prettyverb} that. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none global_substance ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > tangible " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.substance) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.substance receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectSubstance(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1065 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.substance`
        );
        msg += `$(We) can't ${prettyverb} that. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none substance ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > substance " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.character) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.character receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      let qualified_id;
      if (1 === parsedNoun.matches.qualified.length)
        qualified_id = parsedNoun.matches.qualified[0];
      parsedNoun.matches.qualified = this.selectCharacter(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1066 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.character`
        );

        let prep = this.game.getInput().getPreposition(nounIndex) || "";
        let dobj = "";
        if (nounIndex === 2)
          dobj = this.game.getInput().getAsset(1)?.articlename || "";
        if ("undefined" !== typeof qualified_id) {
          msg += `$(We) can't ${prettyverb} ${dobj} ${prep} ${
            this.game.getAsset(qualified_id).articlename
          }. `;
        }
        // otherwise offer generic response
        else {
          msg += `$(We) don't know of anyone named "${parsedNoun.deserialized_input}". `;
        }

        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none character",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > character " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.player_parent) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.player_parent receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      let qualified_id;
      if (1 === parsedNoun.matches.qualified.length)
        qualified_id = parsedNoun.matches.qualified[0];
      parsedNoun.matches.qualified = this.selectPlayerParent(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1069 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.player_parent`
        );
        // if we'd already narrowed qualified list down to
        // one object we can use its name in the response
        if ("undefined" !== typeof qualified_id) {
          msg += `$(We're) not on ${
            this.game.getAsset(qualified_id).articlename
          }. `;
        }
        // otherwise offer generic response
        else {
          msg += `$(We're) not on that. `;
        }
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none player_parent ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > player_parent " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_player_parent) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_player_parent receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotPlayerParent(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1071 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_player_parent`
        );
        // if there was one unambiguous reference to parent
        // we can use its name in the response
        if (parsedNoun.matches.unambiguous) {
          msg += `$(We're) already on ${
            this.game.world[parsedNoun.matches.unambiguous].articlename
          }. `;
        }
        // otherwise offer generic response
        else {
          msg += `$(We're) already on that. `;
        }
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_player_parent ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_player_parent " +
          parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.singular) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.singular receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectSingular(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1073 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.singular`
        );
        msg += `$(We'll) have to do that one at a time. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none singular ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > singular " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.in_inventory_if_takeable) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.in_inventory_if_takeable receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      let qualified_id;
      if (1 === parsedNoun.matches.qualified.length)
        qualified_id = parsedNoun.matches.qualified[0];
      parsedNoun.matches.qualified = this.selectInInventoryIfTakeable(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1074 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.in_inventory_if_takeable`
        );
        if ("undefined" !== typeof qualified_id) {
          var object = this.game.world[qualified_id];
          msg += `$(We're) not carrying ${object.articlename}. `;
        } else {
          let it = parsedNoun.deserialized_input;
          msg += `$(We're) not carrying any${
            it === "all" ? "thing" : " " + it
          }. `;
        }

        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none in_inventory_if_takeable ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > in_inventory_if_takeable " +
          parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.in_inventory) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.in_inventory receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      let qualified_id;
      if (1 === parsedNoun.matches.qualified.length)
        qualified_id = parsedNoun.matches.qualified[0];
      parsedNoun.matches.qualified = this.selectInInventory(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1075 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.in_inventory`
        );
        if ("undefined" !== typeof qualified_id) {
          var object = this.game.world[qualified_id];
          msg += `$(We're) not carrying ${object.articlename}. `;
        } else {
          let it = parsedNoun.deserialized_input;
          msg += `$(We're) not carrying any${
            it === "all" ? "thing" : " " + it
          }. `;
        }

        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none in_inventory ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > in_inventory " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.in_hands) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.in_hands receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectInHands(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1076 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.in_hands`
        );
        msg += `$(We're) not holding any ${parsedNoun.deserialized_input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none in_hands ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > in_hands " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_in_hands) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_in_hands receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotInHands(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1077 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_in_hands`
        );
        msg += `$(We're) carrying the ${parsedNoun.deserialized_input}. `;

        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_in_hands ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_in_hands " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.held) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.held receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectHeld(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1716 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.held`
        );
        msg += `$(We're) not holding any ${parsedNoun.deserialized_input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none held ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > held " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_in_inventory) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_in_inventory receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotInInventory(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1078 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_in_inventory`
        );
        msg += `$(We're) carrying the ${parsedNoun.deserialized_input}. `;

        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_in_inventory ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_in_inventory " +
          parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.worn) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.worn receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectWorn(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1079 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.worn`
        );
        msg += `$(We're) not wearing any ${parsedNoun.deserialized_input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none is.worn ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > is.worn " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.not_worn) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_worn receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotWorn(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1080 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_worn`
        );
        msg += `$(We're) wearing the ${parsedNoun.deserialized_input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_worn ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_worn " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if ("all" === parsedNoun.input && mustBe.not_worn_if_all) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_worn_if_all receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotWornIfAll(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1081 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_worn_if_all`
        );
        msg += `$(We're) not carrying anything. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_worn_if_all ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_worn_if_all " +
          parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if ("all" === parsedNoun.input && mustBe.not_nested_inventory_if_all) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.not_nested_inventory_if_all receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectNotNestedInventoryIfAll(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1082 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.not_nested_in_inventory_if_all`
        );
        msg += `$(We're) not carrying anything. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none not_nested_inventory_if_all ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > not_nested_inventory_if_all " +
          parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.visible) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.visible receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectVisible(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1083 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.visible`
        );
        msg += `$(We) can't see any ${parsedNoun.deserialized_input}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none visible ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > visible " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.reachable) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.reachable receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectReachable(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1084 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.reachable`
        );
        msg += `$(We) can't reach the ${parsedNoun.deserialized_input}`;
        if (player.isNested()) {
          msg += ` from your position ${player.getPostureGerund()} ${player.getNestPreposition()} ${
            player.getNestAsset().articlename
          }`;
        } else if (player.posture !== "stand") {
          msg += ` while ${player.getPostureGerund()}`;
          msg += `${player.isOnFloor() ? " on the floor" : ""}`;
        }
        msg += `. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none reachable ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > reachable " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.reachable_if_tangible) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.reachable_if_tangible receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectReachableIfTangible(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1176 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.reachable`
        );
        msg += `$(We) can't reach the ${parsedNoun.deserialized_input}`;
        if (player.isNested()) {
          msg += ` from your position ${player.getPostureGerund()} ${player.getNestPreposition()} ${
            player.getNestAsset().articlename
          }`;
        }
        msg += `. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none reachable ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > reachable_if_tangible " +
          parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.takeable) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.takeable receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectTakeable(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length && "all" === parsedNoun.input) {
        this.game.debug(
          `F1085 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.takeable`
        );
        msg += `There's nothing takeable in reach. `;
        this.game.print(msg, output_class);
        return false;
      }
      if (!parsedNoun.matches.qualified.length) {
        var thatOrThem = "that";
        if (parsedNoun.input.split("&").length > 1) {
          thatOrThem = "them";
        }
        if (parsedNoun.isPlural || parsedNoun.isGroup) {
          thatOrThem = "them";
        }
        this.game.debug(
          `F1086 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.takeable`
        );
        msg += `$(We) can't take ${thatOrThem}. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none takeable ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > takeable " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    if (mustBe.extant) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > mustBe.extant receives: " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.matches.qualified = this.selectExtant(
        parsedNoun.matches.qualified
      );
      if (!parsedNoun.matches.qualified.length) {
        this.game.debug(
          `F1310 | qualifyParsedNoun.js | ${parsedVerb} phrase${nounIndex}.noun.mustBe.extant`
        );
        msg += `Was there any ${parsedNoun.deserialized_input}? $(We) can't recall. `;
        this.game.print(msg, output_class);
        this.game.log(
          "log",
          "high",
          "qualifyParsedNoun.js > none visible ",
          "Parser"
        );
        return false;
      }
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > known " + parsedNoun.matches.qualified,
        "Parser"
      );
    }

    // check qualified for exact match(es)
    if (1 < parsedNoun.matches.qualified.length) {
      var exactMatches = [];
      for (i = 0; i < parsedNoun.matches.qualified.length; i++) {
        var object = this.game.getAsset(parsedNoun.matches.qualified[i]);
        if (object.id === parsedNoun.serialized_input) {
          exactMatches.push(object.id);
          continue;
        }
        for (var s = 0; s < object.synonyms.length; s++) {
          if (object.synonyms[s] === parsedNoun.serialized_input) {
            exactMatches.push(object.id);
            continue;
          }
        }
      }
      // copy exactMatches back to qualified
      if (0 < exactMatches.length) {
        parsedNoun.matches.qualified = exactMatches.splice(0);
      }
    }

    // can we narrow by class?
    var ajsclass = A.propercase(parsedNoun.serialized_input.toLowerCase());
    if (1 < parsedNoun.matches.qualified.length && adventurejs[ajsclass]) {
      var classMatches = [];
      for (i = 0; i < parsedNoun.matches.qualified.length; i++) {
        var object = this.game.getAsset(parsedNoun.matches.qualified[i]);
        if (object instanceof adventurejs[ajsclass]) {
          classMatches.push(object.id);
          continue;
        }
      }
      // copy classMatches back to qualified
      if (0 < classMatches.length) {
        parsedNoun.matches.qualified = classMatches.splice(0);
      }
    }

    /**
     *
     * If there are multiple qualified, check them all
     * for verb_hooks methods.
     *
     * If present, move them to the end of the queue.
     * This is to minimize the chances of awkward output on
     * interacting with multiple objects, for example:
     * "You take x. You take y. Oh no, taking y
     * transported you to the nether realms! You take z."
     *
     * It's possible that an author might want control over
     * this, so for instance picking up an explosive
     * preceeds all other things. Author can swap order.
     *
     * Set with:
     * game.settings.move_verb_hooks_to_end_of_queue
     */
    // @TODO this block no longer works since moving verb_hooks into verb subscriptions
    // if( 1 < parsedNoun.matches.qualified.length
    // && this.game.settings.enqueue_assets_with_verb_hooks.order === 1 )
    // {
    //   for( i = parsedNoun.matches.qualified.length - 2; i > -1; i--)
    //   {
    //     var asset = this.game.getAsset( parsedNoun.matches.qualified[i] );
    //     if( asset && asset.verb_hooks[parsedVerb] )
    //     {
    //       parsedNoun.matches.qualified = parsedNoun.matches.qualified.concat(
    //         parsedNoun.matches.qualified.splice( i, 1 )
    //       );
    //     }
    //   }
    // }

    /**
     * Samesies, but moves objects with custom verb responses to
     * beginning of queue.
     *
     * Set with:
     * game.settings.move_verb_hooks_to_end_of_queue
     */
    // @TODO this block no longer works since moving verb_hooks into verb subscriptions
    // if( 1 < parsedNoun.matches.qualified.length
    // && this.game.settings.enqueue_assets_with_verb_hooks.order === -1 )
    // {
    //   for( i = parsedNoun.matches.qualified.length - 2; i > -1; i--)
    //   {
    //     var asset = this.game.getAsset( parsedNoun.matches.qualified[i] );
    //     if( asset && asset.verb_hooks[parsedVerb] )
    //     {
    //       parsedNoun.matches.qualified = parsedNoun.matches.qualified.concat(
    //         parsedNoun.matches.qualified.splice( i, 1 )
    //       );
    //     }
    //   }
    // }

    /**
     * If there's only one qualified match, we make a shortcut
     * reference at parsedNoun.qualified_object_id, mostly for use with
     * singular verbs.
     */
    parsedNoun.matches.qualifiedIndex = 0;
    if (1 === parsedNoun.matches.qualified.length) {
      this.game.log(
        "log",
        "high",
        "qualifyParsedNoun.js > found singular qualified " +
          parsedNoun.matches.qualified,
        "Parser"
      );
      parsedNoun.qualified_object_id = parsedNoun.matches.qualified[0];
    }

    this.game.log(
      "log",
      "high",
      "qualifyParsedNoun.js > return " + parsedNoun.matches.qualified,
      "Parser"
    );
    this.game.log("log", "high", "qualifyParsedNoun.js > END", "Parser");
    return parsedNoun;
  };
})();