# Velvet Isis' Vision Script
#-------------------------------------------------------------------------------
# This is not entirely my own work. Parts are based on the following scripts:
#   Tracer stealth system - Prof. Meow Meow Converted to VXA by LiTTleDRAgo
#	  Jet10985's stealth script (which was inspired by Touchfuzzy)
#	  The Infamous Bon Bon's Direction Based Line of Sight Events
# This script takes bits from each of these and merges them into a simple but 
# functional Line of Sight Script
#-------------------------------------------------------------------------------

#-------------------------------------------------------------------------------
# Directions:  To make an event able to 'see' use the event command 'Script...'
#   under tab 3 of the Event Commands and type in 
#
#   sentinel
#
#   That's it, no ' no " just the word sentinel, all lower case.  They must also
#   be set to parallell process.
#   
#   Then for what they do once they see the Player, have a new page with the 
#   Condition: self-switch A is on.  The default is A, but you can change it
#   below. If you want the event to return to normal if the Player exits it's
#   field of vision, make sure to put the sentinel script on this page as well.
#
#-------------------------------------------------------------------------------


#-------------------------------------------------------------------------------
#  Things you can edit
#-------------------------------------------------------------------------------

module VIS
    CAMO_THRESHOLD = 50 
      #A character needs this much Camo to NOT be seen.
			#You can either do this with terrain tags, a variable, or sneaking. 

    CAMO_VARIABLE = 7	
      #This is which game variable controls Camo.  If, for instance, you wanted
      #an event to add or take away Camo you would adjust the variable listed 
      #here.
      
    SNEAK_CAMO = 50 
      #This is how much Camo sneaking provides.  Sneaking is done by holding 
      #down the 'A' button, which is actually the 'SHIFT' button.

    FOV_WIDTH = 2	
      #This is how many squares to the left AND right an event can 'see'.
      #This does not take into account the path in front of the event
			#itself, so for instance, using 2 gives a total of 5 squares 
			#left to right. (2 1 0 1 2)
    FOV_LENGTH = 5	
      #This is how many squares in front of itself an event can 'see'.
      #Nothing weird here, just the straight number.
    
    FOUND_SELFSWITCH = "A" 
      #This is which self switch becomes true when the Player is spotted.
      #Be sure to keep the " " around the letter.

    TERRAIN_CAMOS = { 1 => 60} 
      #These are how much Camo a Terrain Tag gives when standing on it.
      #These go across all maps.  Use the format: terrain_id => camo
      #So right now terrain tag 1 has a Camo value of 60.
    
    TERRAIN_CAMOS.default = 0
      #This is the default camo of any undefined terrain above.    
end

#-------------------------------------------------------------------------------
#   You probably shouldn't edit things below here, but I'm not gonna judge.
#   I mean, that's how I learned to do things, was by putzin' around with 
#   other people's scripts.  I mean if you change stuff the script might not
#   work, but you live and you learn, and that's how you get better
#-------------------------------------------------------------------------------


#-------------------------------------------------------------------------------
#   Terrain Tag Camoflage
#-------------------------------------------------------------------------------
class Game_Map  
  def xy_camo(x, y)
    ter = terrain_tag(x, y)
    ter_c = terrain_camos(ter)
    ter_c
  end
  
  def terrain_camos(ter)
    (@map_terrain_camos ||= {})[@map_id] ||= VIS::TERRAIN_CAMOS
    @map_terrain_camos[ @map_id ][ ter ]
  end
end
  

#-------------------------------------------------------------------------------
#  Player Camoflage
#-------------------------------------------------------------------------------
class Game_Player
  
  alias altered_speed real_move_speed
    def real_move_speed
      altered_speed
      @move_speed - (dash? ? 1 : 0)
    end 
  
  def camouflage
    snk = 0
      if Input.press?(:A)
        snk = VIS::SNEAK_CAMO
      end
    camo = 0
    camo += snk
    camo += $game_map.xy_camo(self.x, self.y)
    camo += $game_variables[VIS::CAMO_VARIABLE]
  end
end

#-------------------------------------------------------------------------------
#  Actual Vision Scripting
#-------------------------------------------------------------------------------
class Game_Character

  #-------------------------#
  # Local Variables         #
  #-------------------------#
    attr_accessor :thresh
    
  #-------------------------#
  # Initialize              #
  #-------------------------#
    alias vision_initialize initialize unless $@
      def initialize
        vision_initialize
        @thresh = VIS::CAMO_THRESHOLD
      end
  
  #-------------------------------#
  # Define Field of Vision        #
  #-------------------------------#
  def fov? # This is the static Field of Vision
      w = VIS::FOV_WIDTH
      l = VIS::FOV_LENGTH
      ex = self.x
      ey = self.y
      px = $game_player.x      
      py = $game_player.y
      if @direction == 2 && ey < py ||
        @direction == 8 && ey > py
        if (ey - py).abs <= l && (ex - px).abs <= w
          return true
        end
      end
      if @direction == 4 && ex > px ||
        @direction == 6 && ex < px
        if (ey - py).abs <= w && (ex - px).abs <= l
          return true
        end
      end
    end
  
  #-------------------------------#
  # Camo Threshold                #
  #-------------------------------#
    def camo_threshold(x)
      for event in $game_map.events.values
      @thresh = x
      end
    end
#------------------------------------------------------------------------------  


  #-------------------------------#
  # Determine if Player is seen   #
  #-------------------------------#
  def viewable?
    viewable = true
    ex = self.x
    ey = self.y
    px = $game_player.x
    py = $game_player.y
    dx = (ex - px).abs
    dy = (ey - py).abs
    m = ((ey - py).to_f / (ex - px).to_f)
        
  #----------------------------------#
  # Player in the Field of Vision?   #
  #----------------------------------#
    if fov?
  #-----------------------------#
  # Check Camouflage            #
  #-----------------------------#
      camo = $game_player.camouflage
      if camo < @thresh
  #-----------------------------#
  # Check for any Obstructions  #
  #-----------------------------#
        if (dx > dy)
          dx.times { |x|
            case
            when (ex > px)
              viewable = false if !$game_map.passable?(
                (ex - x), 
                ((-m * (x)) + ey - 0.1).round, 
                @direction) || 
              $game_map.events_xy_nt(
                (ex - x - 1),
                ((-m * (x + 1)) + ey - 0.1).round).any?
            when (ex < px)
              viewable = false if !$game_map.passable?(
                (ex + x),
                ((m * (x)) + ey - 0.1).round,
                @direction) ||
              $game_map.events_xy_nt(
                (ex + x + 1),
                ((m * (x + 1)) + ey - 0.1).round).any?
            end}
        elsif (dx < dy)
          (dy).times { |y|
            case
            when (ey > py)
              viewable = false if !$game_map.passable?(
                (((y) / -m) + ex - 0.1).round,
                (ey - y),
                @direction) ||
              $game_map.events_xy_nt(
                (((y + 1) / -m) + ex - 0.1).round,
                (ey - y - 1)).any?
            when (ey < py)
              viewable = false if !$game_map.passable?(
                (((y) / m) + ex - 0.1).round,
                (ey + y),
                @direction) ||
              $game_map.events_xy_nt(
                (((y + 1) / m) + ex - 0.1).round,
                (ey + y + 1)).any?
            end}
        elsif (dx = dy)
          dx.times { |x|
            case 
            when (ex > px)
              viewable = false if !$game_map.passable?(
                (ex - x), 
                ((-m * (x)) + ey - 0.1).round, 
                @direction) || 
              $game_map.events_xy_nt(
                (ex - x - 1),
                ((-m * (x + 1)) + ey - 0.1).round).any?
            when (ex < px)
              viewable = false if !$game_map.passable?(
                (ex + x),
                ((m * (x)) + ey - 0.1).round,
                @direction) ||
              $game_map.events_xy_nt(
                (ex + x + 1),
                ((m * (x + 1)) + ey - 0.1).round).any?
            end}
        end
  #---------------------------------------#
  # Check for any Obstructions if dy == 0 #
  #---------------------------------------#
        if dy == 0
          dx.times { |x|
            case
            when (ex < px)
              viewable = false if !$game_map.passable?((ex + x), ey, @direction) ||
              $game_map.events_xy_nt((ex + x + 1), ey).any?
            when (ex > px)
              viewable = false if !$game_map.passable?((ex - x), ey, @direction) ||
              $game_map.events_xy_nt((ex - x - 1), ey).any?
            end}
        end
  #---------------------------------------#
  # Check for any Obstructions if dx == 0 #
  #---------------------------------------#
        if dx == 0
          dy.times { |y|
            case
            when (ey < py)
              viewable = false if !$game_map.passable?(ex, (ey + y), @direction) ||
              $game_map.events_xy_nt(ex, (ey + y + 1)).any?
            when (ey > py)
              viewable = false if !$game_map.passable?(ex, (ey - y), @direction) ||
              $game_map.events_xy_nt(ex, (ey - y - 1)).any?
            end}
        end
  #--------------------------#
  # * Returns false if !fov? #
  #--------------------------#
      else
      viewable = false
      end
    else
      viewable = false
    end
    return viewable
  end   
      
  def sentinel
    if self.viewable?
      set_self_switch(VIS::FOUND_SELFSWITCH, true)
    else
      set_self_switch(VIS::FOUND_SELFSWITCH, false)
    end
  end
  
  #-----------------------------#
  # Get Self Switch             #
  #-----------------------------#
    def get_self_switch(switch)
      key = [@map_id, @id, switch]
      return $game_self_switches[key]
    end
  #-----------------------------#
  # Set Self Switch             #
  #-----------------------------#
    def set_self_switch(switch,true_false)
      key = [@map_id, @id, switch]
      $game_self_switches[key] = true_false
      $game_map.need_refresh = true
    end  
  
end

class Game_Interpreter

  def camouflage
    get_character(-1).camouflage
  end
  
  def fov?
    get_character(0).fov?
  end
  
  def camo_threshold(x)
    get_character(0).camo_threshold(x)
  end
  
  def viewable?
    get_character(0).viewable?
  end
  
  def sentinel
    get_character(0).sentinel
  end

end