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

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

	var p = adventurejs.Parser.prototype;

  /**
   * Exclude from a list of assets all assets that are not reachable by player.
   * @method adventurejs.Parser#selectReachable
   * @memberOf adventurejs.Parser
   * @param {Array} list 
   * @returns {Array}
   */
   p.selectReachable = function Parser_selectReachable(list) 
  {
    if("string" === typeof list) list = [list];
		if( !Array.isArray( list ) ) 
    {
      this.game.log( "warn", "critical", "selectReachable.js > received non-array", 'Parser' );
			return [];
    }

    var player = this.game.getPlayer();
    var nest_asset = player.getNestAsset();        
    var nest_ancestor = this.game.getAsset( player.getNestAnscestorId() );

    var foundObjects = [];
		for(var i = 0; i < list.length; i++) 
    {
      var object, object_parent, object_ancestor, object_ancestor;
      
      // check if input was already parsed by an earlier step
      // as substance:in:tangible in which case verify the tangible
      // var asset_aspect_substance = list[i].split(":"); // asset:aspect:substance
      // if( 3 === asset_aspect_substance.length )
      // {
      //   object = this.game.getAsset( asset_aspect_substance[2] );
      // }
			// else {
        object = this.game.getAsset( list[i] );
      // }

      if(!object) continue;

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

      // if object is a plug, test against its parent
      if( object.IOVisConnectedToAnything('plug') )
      {
        object = object.getPlaceAsset();
      }

      object_parent = object.getPlaceAsset();
      object_ancestor = this.game.getAsset( object.getAncestorId() );


      // check if input is unparsed substance
      // if( object instanceof adventurejs.Substance )
      // {
      //   console.warn( " - selectReachable " + object.id + " is substance" );
      //   if( 0 === roomObjects.length )
      // {
      //     roomObjects = currentRoom.getListableContents();
      //   }
      //   //console.warn( "roomObjects", roomObjects );
      //   for( var j = 0; j < roomObjects.length; j++ )
      // {
      //     var roomObject = this.game.getAsset( roomObjects[j] );
      //     var loc = roomObject.doesContainSubstance( object.id );
      //     if( false !== loc )
      // {
      //       console.warn( " - selectReachable " + roomObject.id + ".doesContainSubstance( "+object.id+" ): " + roomObject.doesContainSubstance( object.id ) );
      //       // becomes for ex: water:in:bowl which can be handled by verbs
      //       foundObjects.push( object.id + ":" + loc + ":" + roomObject.id );
      //     }
      //   }
      //   continue;
      // }

      // player is carrying it, ok
      //if( object.isIn( player ) ) { 
      if( object.isIn( player ) ) 
      { 
        foundObjects.push( list[i] );
        continue;
      }  

      // player is in it, ok
      if( player.isNested() 
      && object.id === nest_asset.id ) 
      {
        foundObjects.push( list[i] );
        continue;
      }  

      // if player is nested and trying to get up/down
      if( player.isNested() 
      && object.direction === "down"
      || object.direction === "up" ) 
      {
        foundObjects.push( list[i] );
        continue;
      }  
  
      // if player is in/on/under/behind something
      if( player.isNested() 

        // player is not nested in object
        && object.id !== nest_asset.id

        // it's not top of the nest
        && object.id !== nest_ancestor.id

        // it's not in inventory
        //&& object_ancestor.id !== player.id 

        // it's not nested in same container as player
        && object_parent.id !== nest_asset.id

        // it's not nested in same container as player
        && object_ancestor.id !== nest_ancestor.id

        // it's not explicitly reachable from thing player is nested in
        && !nest_asset.canPlayerReachThatFromThis( object )

        // it's not inside another thing that is 
        // explicitly reachable from thing player is nested in
        && !nest_asset.canPlayerReachThatFromThis( object_ancestor )

      ){
        console.warn( "reachable excluded", object.id );
        continue;
      }

      // is player on the floor, but object not on the floor?
      // this check might be too restrictive
      if( !player.isNested()
      && player.isOnFloor()
      && !(object instanceof adventurejs.Floor)
      && object.getPlaceAssetId() !== player.getPlaceAssetId() ) 
      {
        console.warn( "Exclude " + object.name + " because player is on the floor." );
        continue;
      }

      // is player at different y height?
      // figure out y overlap
      var range = object.getYRange();
      // is player close enough on y?
      if( player.position.y < range.min || player.position.y > range.max ) 
      {
        console.warn( "Exclude " + object.name + " because player at different y." );
        continue;
      }

			/*
				TODO
				on top of a tall object?
        behind glass?
        inside something that's closed?
			*/

			foundObjects.push( list[i] );
		}

    //console.warn( "selectReachable returned " + foundObjects );
		return foundObjects;
	}
  
}());