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

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

  var p = adventurejs.Parser.prototype;

  /**
   * Get all gettable assets in current room.
   * @method adventurejs.Parser#selectAll
   * @memberOf adventurejs.Parser
   * @param {String} word
   * @returns {Array}
   */
  p.selectAll = function Parser_selectAll(word) {
    this.game.log("log", "high", "selectAll.js > received: " + word, "Parser");

    var currentRoom = this.game.getCurrentRoom();

    if (typeof word !== "string") {
      console.warn("selectAll received non-string", word);
      return [];
    }

    var roomObjects = this.game.getCurrentRoom().getListableContents();
    var playerObjects = this.game.getPlayer().getListableContents();
    var foundObjects = [];
    var exactMatch = false;

    /**
     * Word must exist in our lookup table.
     * Lookup table associates object IDs
     * with every word used by the game.
     *
     * Keywords represent multiple objects and it's possible
     * for a keyword to represent an object with the
     * exact name AND other objects with that word in their names.
     * Example: "desk" represents both "desk" and "desk drawer"
     * If there's an exact match, return that, otherwise return all matches.
     */
    var keys = Object.keys(this.game.world_lookup);

    while (keys.length > 0) {
      if (word === keys[0]) {
        for (var i = 0; i < this.game.world_lookup[keys[0]].IDs.length; i++) {
          var objectID = this.game.world_lookup[keys[0]].IDs[i];
          var object = this.game.getAsset(objectID);

          // exclude assets with no getRoomId from "all"
          // if( "undefined" === typeof object.getRoomId )
          // {
          //   continue;
          // }
          // exclude assets outside the room from "all"
          // if( object.getRoomId() !== currentRoom.id )
          // {
          //   continue;
          // }
          // no don't do these because selectAll is not for "all"
          // it's for getting all game objects

          // exclude scenery events
          if (object instanceof adventurejs.Zone) {
            continue;
          }

          // exclude all global objects from all
          // because there's nothing you can do to all globals
          // this cancels out the following global exit check
          // but was added at a later date, so leaving both in for now
          if (object.is.global) {
            //continue;
          }

          // exclude global exit if there is a local exit with its direction
          // selectPresent redundantly does this check
          if (
            object instanceof adventurejs.Exit &&
            object.is.global &&
            "undefined" !== typeof currentRoom.exits[object.direction]
          ) {
            continue;
          }

          // // never return exits from other rooms
          // // TODO will this be a problem with "ask about" ?
          // selectPresent redundantly does this check
          if (
            object instanceof adventurejs.Exit &&
            false === object.is.global &&
            object.getPlaceAssetId() !== currentRoom.id
          ) {
            continue;
          }

          /**
           * Always exclude player.
           * TODO: make this an option?
           */
          // commented this on 8/3/20 because it was preventing
          // using "me" or "myself"
          // not sure why I added it except I think it was breaking
          // something and player was appearing in "take all"
          // but that might have been a symptom of another bug that I fixed
          if (objectID === this.game._player) {
            //continue
          }

          // @todo EXAMINE THIS CODE
          // check if input is unparsed substance
          // if( object instanceof adventurejs.Substance )
          // {
          //   var containers = 0;
          //   for( var j = 0; j < roomObjects.length; j++ )
          //   {
          //     var roomObject = this.game.getAsset( roomObjects[j] );
          //     var aspect = roomObject.doesContainSubstance( object.id );
          //     if( false !== aspect )
          //     {
          //       console.warn( " - selectAll " + roomObject.id + ".doesContainSubstance( "+object.id+" ): " + roomObject.doesContainSubstance( object.id ) );

          //       // becomes for ex: bowl:in:water which can be handled by verbs
          //       // a result of asset:aspect:substance always means player asked for substance
          //       // and we found a container of that substance
          //       containers++;
          //       foundObjects.push( roomObject.id + ":" + aspect + ":" + object.id );
          //     }
          //   }
          //   if( 0 == containers )
          //   {
          //     foundObjects.push( object.id );
          //   }
          //   continue;
          // }

          //var objectID = this.game.world_lookup[ keys[0] ].IDs[i];

          let context = `selectAll.js > found world_lookup[ ${keys[0]} ].IDs[${objectID}]`;
          console.warn(context);
          if (!this.game.getInput().replacements[objectID]) {
            this.game.getInput().replacements[objectID] = {
              source: keys[0],
              context: context,
            };
          }

          foundObjects.push(objectID);
        }
      }
      keys.shift();
    }

    /**
     * Ideally, if there's an asset whose id is an exact match to the
     * input word, we'd like to return that. Chiefly we'd like this to
     * apply to substances, like "water" or "oil" or "milk", which are singular
     * in the sense that, while water may exist in multiple substances, there
     * is only one water asset. What this does is, if player inputs "take water",
     * it prevents the parser from returning something like:
     * "did you mean the sink's hot water handle or the sink's cold water handle?"
     *
     * In theory it seems like this could be applied to things other than
     * substances, but in practice, what happens is you run into cases like this:
     * there are objects called "plug" and "sink plug", and player inputs
     * "take plug" - and since "plug" is an exact match, "sink plug"
     * is always omitted from any list of possible matches.
     *
     * Have removed / reimplemented this a couple of times... still watching to
     * see if there are any unexpected side effects.
     */
    for (var i = 0; i < foundObjects.length; i++) {
      //console.warn( " - selectAll foundObjects[i]: " + foundObjects[i] );
      object = this.game.getAsset(foundObjects[i]);
      if (object.id === word && object instanceof adventurejs.Substance) {
        foundObjects = [word];
        break;
      }
    }

    this.game.log(
      "log",
      "high",
      "selectAll.js > return: " + foundObjects,
      "Parser"
    );
    return foundObjects;
  };
})();