#----------------------------------------------------------------------------
#Credits: This is an adaptation from a script created by shun (
http://simp.nobody.jp/)
#Also looked at Cybersam's work and Astro_mech and Mr.Mo's mouse script edits to 
#learn how onmouse events work.
#----------------------------------------------------------------------------
# TO USE:
# In each map event, put the name of the cursor you want to show as a comment.
# The comment must be the first event command. Make sure that you put the cursor
# in your Icons directory (name in comment and icon name must match exactly)
#----------------------------------------------------------------------------
module Input
  #--------------------------------------------------------------------------
  # ● get winAPIs
  #--------------------------------------------------------------------------
  #gsm = Win32API.new('user32', 'GetSystemMetrics', 'i', 'i')
  @mouse_status = [[0, 1], [0, 2], [0, 4]] #left, right, middle mouse
  @gaks = Win32API.new('user32', 'GetAsyncKeyState', 'i', 'i')
  @cursor_pos = Win32API.new('user32', 'GetCursorPos', 'p', 'i')
  @scr2cli = Win32API.new('user32', 'ScreenToClient', %w(l p), 'i')
  @client_rect = Win32API.new('user32', 'GetClientRect', %w(l p), 'i')
  @readini = Win32API.new('kernel32', 'GetPrivateProfileStringA', %w(p p p p l p), 'l')
  @findwindow = Win32API.new('user32', 'FindWindowA', %w(p p), 'l')
  show_cursor = Win32API.new('user32', 'ShowCursor', 'l', 'l')
  @last_pos = [0, 0].pack('ll')  
  @pos_x = @pos_y = 0
  @width = 0
  @height = 0
  n = (true ? 0 : 1)
  show_cursor.call(n)
  module_function
    
  #--------------------------------------------------------------------------
  # ● get the window
  #--------------------------------------------------------------------------
  def hwnd
    game_name = "\0" * 256
    @readini.call('Game', 'Title', '', game_name, 255, ".\\Game.ini")
    game_name.delete!("\0")
    h = @findwindow.call('RGSS Player', game_name)
    if h == 0
      n = 0
      while h == 0
        h = @findwindow.call('RGSS Player', "#{game_name} - #{n} FPS")
        n += 1
      end
    end
    return h
  end
  
  #--------------------------------------------------------------------------
  # ● get the global position of the mouse
  #--------------------------------------------------------------------------
  def global_pos
    pos = [0, 0].pack('ll')
    if @cursor_pos.call(pos) != 0
      return pos.unpack('ll')
    else
      return nil
    end
  end
   
  #--------------------------------------------------------------------------
  # ● Position of the mouse in the game
  #     catch_anywhere : get position if mouse is outside of game screen
  #--------------------------------------------------------------------------
  def pos(catch_anywhere = true)
         
    if (global_pos != @last_pos)
      
      @last_pos = *global_pos
      
      string = global_pos.to_s + " " + @last_pos.to_s
      $debug_string = string.to_s
      
      @pos_x, @pos_y = screen_to_client(*global_pos)
      @width, @height = client_size
      
    end
    
    if (@pos_x >= 0 and @pos_y >= 0 and @pos_x < @width and @pos_y < @height)  
      return @pos_x, @pos_y
    else
      return 0, 0
    end
    
  end
  
  #--------------------------------------------------------------------------
  # ● Position of the mouse on screen
  #     x : x coordinate
  #     y : y coordinate
  #--------------------------------------------------------------------------
  def screen_to_client(x, y)
    return nil unless x and y
    pos = [x, y].pack('ll')
    if @scr2cli.call(hwnd, pos) != 0
      return pos.unpack('ll')
    else
      return nil
    end
  end
  
  #--------------------------------------------------------------------------
  # ● Size of the game window
  #--------------------------------------------------------------------------
  def client_size
    rect = [0, 0, 0, 0].pack('l4')
    @client_rect.call(hwnd, rect)
    right, bottom = rect.unpack('l4')[2..3]
    return right, bottom
  end
  #--------------------------------------------------------------------------
  # ● Check to see if the mouse is over an event
  #--------------------------------------------------------------------------  
  def check_event(x, y)
    
    for event in $game_map.events.values
      # change icon if an event is encountered
      if (event.x == x or event.x == (x-1)) and (event.y == y or event.y == (y+1))
        if event.list && event.list[0].code == 108
            icon = event.list[0].parameters 
            icon = icon.to_s
            if icon == "Arrow2" || icon == "Arrow3" || icon == "Arrow4" || icon == "Arrow5" || icon == "Arrow6"
              $mouse_icon = icon.to_s
            end
        end
        break
      end
      
      # if even is not encountered, use default icon
      $mouse_icon = "Arrow" 
    end
  
  end   
  def icon_name(name)
    $msg = name.to_s
    $mouse_icon = name.to_s
  end
  
  #--------------------------------------------------------------------------
  # ● watch for left mouse actions
  #     id : Mouse (0:Left, 1:Right, 2:Center)
  #--------------------------------------------------------------------------
  def mouse_press?(id = 0)
    if $scene.is_a?(Scene_Map)
      # get the icon to display
      if @mouse_status[id][0] <= 0
        $hoverx = (pos[0] + $game_map.display_x / 4) / 32
        $hovery = (pos[1] + $game_map.display_y / 4) / 32
        icon = check_event($hoverx,$hovery)
      end  
      # move character when mouse is pressed
      if @mouse_status[id][0] > 0
        $mousex = pos[0] + $game_map.display_x / 4
        $mousey = pos[1] + $game_map.display_y / 4
        $move = 1
      end
      # don't move character if message window showing
      if $game_temp.message_window_showing
        $move = 0
      end
    end
    return @mouse_status[id][0] > 0
  end
  
  #--------------------------------------------------------------------------
  # ● Watch for mouse button actions (especially right mouse button)
  #     id : mouse (0:Left, 1:Right, 2:Center)
  #--------------------------------------------------------------------------
  def mouse_trigger?(id = 0)   
    return @mouse_status[id][0] == 1    
  end
  
  #--------------------------------------------------------------------------
  # ● Check to see if a mouse action was repeated
  #     id : mouse (0:Left, 1:Right, 2:Center)
  #--------------------------------------------------------------------------
  def mouse_repeat?(id = 0)
    if @mouse_status[id][0] <= 0
      return false
    else
      result = @mouse_status[id][0] % 5 == 1 and @mouse_status[id][0] % 5 != 2
      return result
    end
  end
  
  #--------------------------------------------------------------------------
  # ● Update the mouse
  #--------------------------------------------------------------------------
  def mouse_update
    for i in @mouse_status
      n = @gaks.call(i[1])
      if n == 0 or n == 1
        i[0] = (i[0] > 0 ? i[0] * -1 : 0)
      else
        i[0] = (i[0] > 0 ? i[0] + 1 : 1)
      end
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class << Input
  #--------------------------------------------------------------------------
  # ● Update old input calls
  #--------------------------------------------------------------------------
  alias old_update update unless $@
  def Input.update
    old_update
    mouse_update
    $mouse.update
  end
  #--------------------------------------------------------------------------
  # ● Update old input triggers
  #     num : A, B, C
  #--------------------------------------------------------------------------
  alias old_trigger? trigger? unless $@
  def Input.trigger?(num)
    return old_trigger?(num) if Input.pos(false) == nil
    case num
    when Input::A
      return (old_trigger?(num) or mouse_trigger?(2))
    when Input::B
      return (old_trigger?(num) or mouse_trigger?(1))
    when Input::C
      return (old_trigger?(num) or mouse_trigger?)
    else
      return old_trigger?(num)
    end
  end
  #--------------------------------------------------------------------------
  # ● Check to see if an old input call was repeated
  #     num : B
  #--------------------------------------------------------------------------
  alias old_repeat? repeat? unless $@
  def repeat?(num)
    return old_repeat?(num) if Input.pos(false) == nil
    if num == Input::B
      return (old_repeat?(num) or mouse_repeat?(1))
    else
      return old_repeat?(num)
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Game_Player < Game_Character
  #--------------------------------------------------------------------------
  # ● Move the player toward the mouse
  #--------------------------------------------------------------------------
  alias mouse_update update
  def update
   
    rx = $mousex - (@real_x / 4 + 16)
    ry = $mousey - (@real_y / 4 + 16)  
    
    # if an arrow key is pressed, stop path finding
    $move = 0 if Input.dir4 != 0
    
    # move to a specified area on the map, using the mouse
    if $move == 1
        unless moving? or $game_system.map_interpreter.running? or
           @move_route_forcing or $game_temp.message_window_showing or
           (rx.abs <= 16 and ry.abs <= 16)
          rad = -(Math.atan2(ry, rx) / Math::PI * 180)
          case rad
          when -157.5...-112.5
            move_lower_left
          when -112.5...-67.5
            move_down
          when -67.5...-22.5
            move_lower_right
          when -22.5...22.5
            move_right
          when 22.5...67.5
            move_upper_right
          when 67.5...112.5
            move_up
          when 112.5...157.5
            move_upper_left
          else
            move_left
          end
        end
        
        # if the path has been reached, stop moving
        if (rx.abs <= 16 and ry.abs <= 16)
          $move = 0
        end
        
    end
    
    #update the mouse
    mouse_update
    
  end
  
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Sprite_Mouse < Sprite
  #--------------------------------------------------------------------------
  # ● Initialize the mouse
  #--------------------------------------------------------------------------
  def initialize
    super
    self.bitmap = RPG::Cache.icon($mouse_icon.to_s)
    self.z = 10001
    self.ox, self.oy = [16, 0]
    self.visible = false
    self.src_rect.set(0, 0, 32, 32)
    update
  end
  #--------------------------------------------------------------------------
  # ● Dispose of the mouse
  #--------------------------------------------------------------------------
  def dispose
    if self.bitmap != nil
      self.bitmap.dispose
    end
    super
  end
  #--------------------------------------------------------------------------
  # ● Update the mouse
  #--------------------------------------------------------------------------
  def update
    super
    self.bitmap = RPG::Cache.icon($mouse_icon.to_s)    
    self.visible = true if self.visible == false and $scene != nil
    self.x, self.y = Input.pos
    if Input.mouse_press?
      self.src_rect.set(0, 0, 32, 32)     
    end
    return
  end
  
end
$mouse = Sprite_Mouse.new
class Window_Selectable < Window_Base
  #--------------------------------------------------------------------------
  # ● Initialize the mouse
  #--------------------------------------------------------------------------
  alias mouse_initialize initialize
  def initialize(x, y, width, height)
    mouse_initialize(x, y, width, height)
    @scroll_wait = 0
  end
  #--------------------------------------------------------------------------
  # ● Update the mouse
  #--------------------------------------------------------------------------
  alias mouse_update update
  def update
    mouse_update
    mouse_operation if self.active
  end
  #--------------------------------------------------------------------------
  # ○ Perform mouse operations
  #--------------------------------------------------------------------------
  def mouse_operation
    mx = Input.pos[0] - (self.x - self.ox + 16)
    my = Input.pos[1] - (self.y - self.oy + 16)
    width = self.width / @column_max - 32
    height = 32
    for index in 0...@item_max
      x = index % @column_max * (width + 32)
      y = index / @column_max * 32
      if mx > x and
         mx < x + width and
         my > y and
         my < y + height
        mouse_cursor(index)
        break
      end
    end
  end
  #--------------------------------------------------------------------------
  # ○ Track the position of the mouse cursor
  #--------------------------------------------------------------------------
  def mouse_cursor(index)
    return if @index == index
    @scroll_wait -= 1 if @scroll_wait > 0
    row1 = @index / @column_max
    row2 = index / @column_max
    bottom = self.top_row + (self.page_row_max - 1)
    if row1 == self.top_row and row2 < self.top_row
      return if @scroll_wait > 0
      @index = [@index - @column_max, 0].max
      @scroll_wait = 4
    elsif row1 == bottom and row2 > bottom
      return if @scroll_wait > 0
      @index = [@index + @column_max, @item_max - 1].min
      @scroll_wait = 4
    else
      @index = index
    end
    $game_system.se_play($data_system.cursor_se)
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Window_MenuStatus < Window_Selectable
  def mouse_operation   
    return if @index < 0
    mx = Input.pos[0] - (self.x - self.ox + 16)
    my = Input.pos[1] - (self.y - self.oy + 16)
    x = 0
    width = self.width - 32
    height = 96
    for index in 0...@item_max
      y = index * 116
      if mx > x and
          mx < x + width and
          my > y and
          my < y + height
        mouse_cursor(index)
        break
      end
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Window_Target < Window_Selectable
  def mouse_operation
    return if @index <= -1
    mx = Input.pos[0] - (self.x - self.ox + 16)
    my = Input.pos[1] - (self.y - self.oy + 16)
    x = 0
    width = self.width - 32
    height = 96
    for index in 0...@item_max
      y = index * 116
      if mx > x and
          mx < x + width and
          my > y and
          my < y + height
        mouse_cursor(index)
        break
      end
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Window_NameInput < Window_Base
  #--------------------------------------------------------------------------
  # ● Update the position of the mouse
  #--------------------------------------------------------------------------
  alias mouse_update update
  def update
    mouse_update
    mouse_operation if self.active
  end
  #--------------------------------------------------------------------------
  # ● Perform mouse operations
  #--------------------------------------------------------------------------
  def mouse_operation
    last_index = @index
    mx = Input.pos[0] - (self.x - self.ox + 16)
    my = Input.pos[1] - (self.y - self.oy + 16)
    width = 28
    height = 32
    for index in 0...180
      x = 4 + index / 5 / 9 * 152 + index % 5 * 28
      y = index / 5 % 9 * 32
      if mx > x and
          mx < x + width and
          my > y and
          my < y + height
        @index = index
        break
      end
    end
    x = 544
    y = 9 * 32
    width = 64
    if mx > x and
        mx < x + width and
        my > y and
        my < y + height
      @index = 180
    end
    $game_system.se_play($data_system.cursor_se) unless @index == index
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Window_Message < Window_Selectable
  #--------------------------------------------------------------------------
  # ● Perform mouse operations
  #--------------------------------------------------------------------------
  def mouse_operation
    mx = Input.pos[0] - (self.x - self.ox + 16)
    my = Input.pos[1] - (self.y - self.oy + 16)
    x = 8
    width = 128 
    height = 32
    for index in 0...@item_max
      y = ($game_temp.choice_start + index) * 32
          
      if mx > x and mx < x + width and my > y and my < y + height
        mouse_cursor(index)
        break
      end
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Window_PartyCommand < Window_Selectable
  def mouse_operation
    mx = Input.pos[0] - (self.x - self.ox + 16)
    my = Input.pos[1] - (self.y - self.oy + 16)
    y = 0
    width = 128
    height = 32
    for index in 0...@item_max
      x = 160 + index * 160
      if mx > x and
          mx < x + width and
          my > y and
          my < y + height
        mouse_cursor(index)
        break
      end
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Window_MenuPosition < Window_Selectable
  def mouse_operation
    mx = Input.pos[0] - (self.x - self.ox + 16)
    my = Input.pos[1] - (self.y - self.oy + 16)
    y = 0
    width = self.contents.width / @item_max - 10
    height = 32
    for index in 0...@item_max
      x = self.contents.width / (@item_max) * index + 4
      if mx > x and
         mx < x + width and
         my > y and
         my < y + height
        mouse_cursor(index)
        break
      end
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Arrow_Base < Sprite
  alias mouse_update update
  def update
    mouse_update
    mouse_operation
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Arrow_Enemy < Arrow_Base
  def mouse_operation
    mx, my = Input.pos
    for index in 0...$game_troop.enemies.size
      enemy = $game_troop.enemies[index]
      bitmap = RPG::Cache.battler(enemy.battler_name, 0)
      width = bitmap.width
      height = bitmap.height
      x = enemy.screen_x - width / 2
      y = enemy.screen_y - height
      if mx > x and
          mx < x + width and
          my > y and
          my < y + height
        break if @index == index
        @index = index
        $game_system.se_play($data_system.cursor_se)
        break
      end
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Arrow_Actor < Arrow_Base
  def mouse_operation 
    mx, my = Input.pos
    for index in 0...$game_party.actors.size
      index = $game_party.actors.size - index - 1
      actor = $game_party.actors[index]
      bitmap = RPG::Cache.battler(actor.battler_name, 0)
      width = bitmap.width
      height = bitmap.height
      x = actor.screen_x - width / 2
      y = actor.screen_y - height
      if mx > x and
          mx < x + width and
          my > y and
          my < y + height
        break if @index == index
        @index = index
        $game_system.se_play($data_system.cursor_se)
        break
      end
    end
  end
end
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
class Scene_File
  #--------------------------------------------------------------------------
  # ● Update the mouse
  #--------------------------------------------------------------------------
  alias mouse_update update
  def update
    mouse_update
    save = false
    mx, my = Input.pos
    x = 0
    width = (save ? 160 : 640)
    height = 104
    for index in 0...4
      y = 64 + index % 4 * 104
      if mx > x and
          mx < x + width and
          my > y and
          my < y + height
        break if @file_index == index
        @savefile_windows[@file_index].selected = false
        @file_index = index
        @savefile_windows[@file_index].selected = true
        $game_system.se_play($data_system.cursor_se)
        break
      end
    end
  end
end