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

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

  var p = adventurejs.Parser.prototype;

  /**
   * Exclude from a list of assets all assets that are not visible to subject.
   * @method adventurejs.Parser#selectVisible
   * @memberOf adventurejs.Parser
   * @param {Array} list
   * @returns {Array}
   * @todo consider global darkness
   */
  p.selectVisible = function Parser_selectVisible(list) {
    if ("string" === typeof list) list = [list];
    if (!Array.isArray(list)) {
      this.game.log(
        "L1090",
        "error",
        "critical",
        ["[selectVisible.js] selectVisible() received non-array", list],
        "Parser"
      );
      return [];
    }
    this.game.log(
      "L1179",
      "log",
      "high",
      `[selectVisible.js] selectVisible() receive:\n${list}`,
      "Parser"
    );
    // we already know it's present
    var input = this.game.getInput();
    var subject = input.getSubject();
    var room = this.game.getRoom();
    var foundObjects = [];
    var roomObjects = [];
    var containers = [];

    for (var i = 0; i < list.length; i++) {
      var object = this.game.getAsset(list[i]); // may return substance

      if (!object) continue;

      // abstractions are always visible
      if (object.is.abstract) {
        foundObjects.push(list[i]);
        continue;
      }

      // global objects are always visible, barring darkness
      // @TODO probably some complexities to explore here,
      // like seeing sun, moon, sky from underground
      if (object.is.global) {
        foundObjects.push(list[i]);
        continue;
      }

      // if object is a plug, test against its parent
      if (object.isConnectedToAsset("plug", object.getPlaceAsset(), "to_dov")) {
        object = object.getPlaceAsset();
      }

      // check if input is unparsed substance
      if (object instanceof adventurejs.Substance) {
        // this version automatically returns substances as present
        // foundObjects.push( list[i] );
        // continue;

        // this version looks for substance containers
        if (!roomObjects.length) {
          roomObjects = [room.id].concat(room.getAllNestedContents());
        }
        for (var j = 0; j < roomObjects.length; j++) {
          var roomObject = this.game.getAsset(roomObjects[j]);
          if (!subject.knowsAbout(roomObject)) continue;
          var preposition = roomObject.containsSubstance(object.id);
          if (preposition) {
            // becomes for ex: bowl:in:water which can be handled by verbs
            if (!subject.knowsAbout(`${roomObject.id}|${preposition}|vessel`))
              continue;
            containers.push(
              roomObject.id + ":" + preposition + ":" + object.id
            );
          }
        }
        if (containers.length) {
          containers = this.selectVisible(containers);
          if (containers.length) {
            foundObjects = foundObjects.concat(containers);
          }
        }
        continue;
      }

      /*
				// TODO selectVisible

				get ambient light level
				- get light provided by all lightsources?
				get object's min_light_required_to_see

				hidden in a container - visible? or reachable?
				also consider container's opacity

      */

      if (object.is.hidden) {
        continue;
      }

      // if it has no parent, and it's not a room,
      // then it's not present in the world
      if (
        !object.hasClass("Substance") &&
        !object.getPlaceAsset() &&
        !(object instanceof adventurejs.Room)
      ) {
        continue;
      }

      /**
       * If object's anscestor is closed we'll consider it not visible
       * unless it's nested in subject inventory. We'll be nice and
       * let subject access their inventory without having to
       * open every damned container.
       *
       * In theory we could do the same for any nested & known objects,
       * but that could raise unpredictable problems in situations like taking
       * objects from NPCs, or inadvertently triggering custom functions.
       */
      //console.warn( 'selectVisible > areAnscestorsClosed()',object.areAnscestorsClosed() );
      if (
        !object.isWithin(subject) &&
        object.areAnscestorsClosed &&
        object.areAnscestorsClosed()
      ) {
        continue;
      }

      /**
       * Omit if any of object's
       * anscestors are unknown. It's possible for a known
       * object to be inside an unknown object, but this state
       * is unlikely to happen by accident, so we'll take unknown
       * anscestors to mean the object was deliberately hidden.
       */
      if (object.areAnscestorsUnknown && object.areAnscestorsUnknown()) {
        continue;
      }

      // TODO is parent transparent?
      // drain with plug
      // bottle with plug

      foundObjects.push(list[i]);
    }

    //console.log( "selectVisible returned " + JSON.stringify(foundObjects) );
    return foundObjects;
  };
})();