#==============================================================================|
#  ** Script Info                                                              |
#------------------------------------------------------------------------------|
#  * Script Name                                                               |
#    DoubleX RMVXA Pixel Movement                                              |
#------------------------------------------------------------------------------|
#  * Functions                                                                 |
#    Lets users set the smallest number of pixel covered per move command      |
#------------------------------------------------------------------------------|
#  * Terms Of Use                                                              |
#    You shall keep this script's Script Info part's contents intact           |
#    You shalln't claim that this script is written by anyone other than       |
#    DoubleX or his aliases                                                    |
#    None of the above applies to DoubleX or his aliases                       |
#------------------------------------------------------------------------------|
#  * Prerequisites                                                             |
#    Abilities:                                                                |
#    1. Little RGSS3 scripting proficiency to fully utilize this script        |
#------------------------------------------------------------------------------|
#  * Instructions                                                              |
#    1. Open the script editor and put this script into an open slot between   |
#       Materials and Main, save to take effect.                               |
#------------------------------------------------------------------------------|
#  * Links                                                                     |
#    Script Usage 101:                                                         |
#    1. forums.rpgmakerweb.com/index.php?/topic/32752-rmvxa-script-usage-101/  |
#    2. rpgmakervxace.net/topic/27475-rmvxa-script-usage-101/                  |
#    This script:                                                              |
#    1. [url]http://pastebin.com/RPF8dDDR[/url]                                           |
#    Mentioned Patreon Supporters:                                             |
#    [url]https://www.patreon.com/posts/71738797[/url]                                    |
#------------------------------------------------------------------------------|
#  * Authors                                                                   |
#    DoubleX                                                                   |
#------------------------------------------------------------------------------|
#  * Changelog                                                                 |
#    v1.01a(GMT 1600 14-8-2015):                                               |
#    1. Lets users set a key/script call to set a char to have integer coors   |
#    2. Fixed event triggered by player touch not triggering bug               |
#    3. Fixed encounters simply not working bug                                |
#    4. Fixed the bullet through paper problem when moving diagonally          |
#    5. Found the origin of the starting map not passable bug with either      |
#       vehicle's starting positions being uninitialized by users              |
#    6. Increased this script's correctness, effectiveness and efficiency      |
#    7. Little RGSS3 scripting proficiency's needed to fully utilize the script|
#    v1.00a(GMT 1600 12-8-2015):                                               |
#    1. 1st version of this script finished                                    |
#==============================================================================|

#==============================================================================|
#  ** (v1.01a+)Script Call Info                                                |
#------------------------------------------------------------------------------|
#  * Character manipulations                                                   |
#    1. pixel_movement_nearest_tile                                            |
#       - Sets the x and y psotions of the char to be their nearest integers   |
#==============================================================================|

($doublex_rmvxa ||= {})[:Pixel_Movement] = "v1.01a"

#==============================================================================|
#  ** Script Configurations                                                    |
#     You only need to edit this part as it's about what this script does      |
#------------------------------------------------------------------------------|

module DoubleX_RMVXA

  module Pixel_Movement

    # Sets the global minimum pixel covered per move command as MIN_PIXEL_MOVE
    # It must return a natural number
    # If an object moves faster than MIN_PIXEL_MOVE per frame, that object's
    # original speed will be used instead
    # Errors might come if MIN_PIXEL_MOVE is increased during the game execution
    # If MIN_PIXEL_MOVE_VAR_ID is a natural number, the value of variable with
    # id MIN_PIXEL_MOVE_VAR_ID will be used instead of using MIN_PIXEL_MOVE
    MIN_PIXEL_MOVE = 1
    MIN_PIXEL_MOVE_VAR_ID = 0

    # (v1.01a+)Sets the key to set the player's x and y positions as their
    # nearest integers as NEAREST_TILE_KEY
    # It must return a symbol and should return a keymap binding symbol
    # Using a custom keymap binding script might help setting NEAREST_TILE_KEY
    # If NEAREST_TILE_KEY_VAR_ID is a natural number, the value of variable with
    # id NEAREST_TILE_KEY_VAR_ID will be used instead of using NEAREST_TILE_KEY
    NEAREST_TILE_KEY = :X
    NEAREST_TILE_KEY_VAR_ID = 0

#==============================================================================|
#  ** Script Implementations                                                   |
#     You need not edit this part as it's about how this script works          |
#------------------------------------------------------------------------------|
#  * Script Support Info:                                                      |
#    1. Prerequisites                                                          |
#       - Basic knowledge of pixel movement                                    |
#       - Some RGSS3 scripting proficiency to fully comprehend this script     |
#    2. Method documentation                                                   |
#       - The 1st part describes why this method's rewritten/aliased for       |
#         rewritten/aliased methods or what the method does for new methods    |
#       - The 2nd part describes what the arguments of the method are          |
#       - The 3rd part informs which version rewritten, aliased or created this|
#         method                                                               |
#       - The 4th part informs whether the method's rewritten or new           |
#       - The 5th part describes how this method works for new methods only,   |
#         and describes the parts added, removed or rewritten for rewritten or |
#         aliased methods only                                                 |
#       Example:                                                               |
# #--------------------------------------------------------------------------| |
# #  Why rewrite/alias/What this method does                                 | |
# #--------------------------------------------------------------------------| |
# # *argv: What these variables are                                            |
# # &argb: What this block is                                                  |
# def def_name(*argv, &argb) # Version X+; Rewrite/New                         |
#   # Added/Removed/Rewritten to do something/How this method works            |
#   def_name_code                                                              |
#   #                                                                          |
# end # def_name                                                               |
#------------------------------------------------------------------------------|

    #--------------------------------------------------------------------------|
    #  Helper methods simplifying the uses of the configuration value          |
    #--------------------------------------------------------------------------|

    def self.min_pixel_move
      return MIN_PIXEL_MOVE if MIN_PIXEL_MOVE_VAR_ID <= 0
      $game_variables[MIN_PIXEL_MOVE_VAR_ID]
    end # min_pixel_move

    def self.nearest_tile_key # v1.01a+
      return NEAREST_TILE_KEY if NEAREST_TILE_KEY_VAR_ID <= 0
      $game_variables[NEAREST_TILE_KEY_VAR_ID]
    end # nearest_tile_key

  end # Pixel_Movement

end # DoubleX_RMVXA

class Game_Map # Edit

  def x_with_direction(x, d) # Rewrite
    # Rewritten
    return x + DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 if d == 6
    return x - DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 if d == 4
    x
    #
  end # x_with_direction

  def y_with_direction(y, d) # Rewrite
    # Rewritten
    return y + DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 if d == 2
    return y - DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0 if d == 8
    y
    #
  end # y_with_direction

  def round_x_with_direction(x, d) # Rewrite
    round_x(x_with_direction(x, d)) # Rewritten
  end # round_x_with_direction

  def round_y_with_direction(y, d) # Rewrite
    round_y(y_with_direction(y, d)) # Rewritten
  end # round_y_with_direction

  def valid?(x, y) # Rewrite
    x >= 0 && x <= width - 1 && y >= 0 && y <= height - 1 # Rewritten
  end # valid?

  #----------------------------------------------------------------------------|
  #  Uses a unit bounding square to detect overlapped tiles instead            |
  #----------------------------------------------------------------------------|
  alias layered_tiles_flag_pixel_movement? layered_tiles_flag?
  def layered_tiles_flag?(x, y, bit, &argb)
    # Rewritten
    (x == (x = x.to_i) ? [x] : [x, x + 1]).each { |xi|
      (y == (y = y.to_i) ? [y] : [y, y + 1]).each { |yi|
        return true if layered_tiles_flag_pixel_movement?(x, y, bit, &argb)
      }
    }
    false
    #
  end # layered_tiles_flag?

end # Game_Map

class Game_CharacterBase # Edit

  #----------------------------------------------------------------------------|
  #  New private instance variables                                            |
  #----------------------------------------------------------------------------|
  # @pixel_movement_diff: The movement distance of the current frame
  # @pixel_movement_dist: The accumulated movement distance

  #----------------------------------------------------------------------------|
  #  Uses a unit bounding square to detect character collisions instead        |
  #----------------------------------------------------------------------------|
  def pos?(x, y) # Rewrite
    # Rewritten to regard just touching as edges as colliding
    x + 1 >= @x && x <= @x + 1 && y + 1 >= @y && y <= @y + 1
    #
  end # pos?

  #----------------------------------------------------------------------------|
  #  Uses a unit bounding square to detect character collisions instead        |
  #----------------------------------------------------------------------------|
  def pos_nt?(x, y) # Rewrite
    # Rewritten to regard just touching the edges as not colliding
    !@through && x + 1 > @x && x < @x + 1 && y + 1 > @y && y < @y + 1
    #
  end # pos_nt?

  #----------------------------------------------------------------------------|
  #  Uses a unit bounding square to detect character collisions instead        |
  #----------------------------------------------------------------------------|
  def passable?(x, y, d) # Rewrite
    x2 = $game_map.round_x_with_direction(x, d)
    y2 = $game_map.round_y_with_direction(y, d)
    # Rewritten to check if all overlapped tiles are valid and passable as well
    xs = x2 == (x2i = x2.to_i) ? [x2i] : [x2i, x2i + 1]
    ys = y2 == (y2i = y2.to_i) ? [y2i] : [y2i, y2i + 1]
    xs.each { |xi|
      ys.each { |yi| return false unless $game_map.valid?(xi, yi) }
    }
    return true if @through || debug_through?
    (x == (x = x.to_i) ? [x] : [x, x + 1]).each { |xi|
      (y == (y = y.to_i) ? [y] : [y, y + 1]).each { |yi|
        return false unless map_passable?(xi, yi, d)
      }
    }
    rd = reverse_dir(d)
    xs.each { |xi|
      ys.each { |yi| return false unless map_passable?(xi, yi, rd) }
    }
    #
    !collide_with_characters?(x2, y2)
  end # passable?

  #----------------------------------------------------------------------------|
  #  Prevents an event from being falsely considered as colliding with itself  |
  #----------------------------------------------------------------------------|
  def collide_with_events?(x, y) # Rewrite
    return true if is_a?(Game_Event)
    ($game_map.events_xy_nt(x, y) - [self]).any? { |e| e.normal_priority? }
  end # collide_with_events?

  def move_straight(d, turn_ok = true) # Rewrite
    @move_succeed = passable?(@x, @y, d)
    if @move_succeed
      set_direction(d)
      @x = $game_map.round_x_with_direction(@x, d)
      @y = $game_map.round_y_with_direction(@y, d)
      @real_x = $game_map.x_with_direction(@x, reverse_dir(d))
      @real_y = $game_map.y_with_direction(@y, reverse_dir(d))
      # Rewritten to prevent character from being locked into impassable places
      set_pixel_movement_min
      last_x = @real_x
      last_y = @real_y
      pixel_movement_straight(last_x, last_y, d) unless passable?(@x, @y, d)
      @pixel_movement_diff = ((@x - last_x) ** 2 + (@y - last_y) ** 2) ** 0.5
      @pixel_movement_dist += @pixel_movement_diff
      while @pixel_movement_dist >= 1
        increase_steps
        @pixel_movement_dist -= 1
      end
      #
    elsif turn_ok
      set_direction(d)
      check_event_trigger_touch_front
    end
  end # move_straight

  def move_diagonal(horz, vert) # Rewrite
    @move_succeed = diagonal_passable?(@x, @y, horz, vert)
    if @move_succeed
      @x = $game_map.round_x_with_direction(@x, horz)
      @y = $game_map.round_y_with_direction(@y, vert)
      @real_x = $game_map.x_with_direction(@x, reverse_dir(horz))
      @real_y = $game_map.y_with_direction(@y, reverse_dir(vert))
      # Rewritten to prevent character from being locked into impassable places
      set_pixel_movement_min
      set_pixel_movement_diagonal(horz, vert)
      @pixel_movement_diff = ((@x - @real_x) ** 2 + (@y - @real_y) ** 2) ** 0.5
      @pixel_movement_dist += @pixel_movement_diff
      while @pixel_movement_dist >= 1
        increase_steps
        @pixel_movement_dist -= 1
      end
      #
      increase_steps
    end
    set_direction(horz) if @direction == reverse_dir(horz)
    set_direction(vert) if @direction == reverse_dir(vert)
  end # move_diagonal

  alias init_private_members_pixel_movement init_private_members
  def init_private_members(*argv, &argb)
    init_private_members_pixel_movement(*argv, &argb)
    @pixel_movement_diff = @pixel_movement_dist = 0 # Added
  end # init_private_members

  #----------------------------------------------------------------------------|
  #  Checks if events collide with the players as well                         |
  #----------------------------------------------------------------------------|
  alias collide_with_characters_pixel_movement? collide_with_characters?
  def collide_with_characters?(x, y)
    return true if $game_player != self && $game_player.pos_nt?(x, y) # Added
    collide_with_characters_pixel_movement?(x, y)
  end # collide_with_characters?

  #----------------------------------------------------------------------------|
  #  Sets the number of pixel covered per frame to be at least that of the char|
  #----------------------------------------------------------------------------|
  def set_pixel_movement_min # New
    dpf = distance_per_frame
    if @x > @real_x
      @x = [@real_x + dpf, $game_map.width - 1].min if @x < @real_x + dpf
    elsif @x < @real_x
      @x = [@real_x - dpf, 0].max if @x > @real_x - dpf
    end
    if @y > @real_y
      @y = [@real_y + dpf, $game_map.height - 1].min if @y < @real_y + dpf
    elsif @y < @real_y
      @y = [@real_y - dpf, 0].max if @y > @real_y - dpf
    end
  end # set_pixel_movement_min

  #----------------------------------------------------------------------------|
  #  Prevents the character from being locked into an impassable place         |
  #----------------------------------------------------------------------------|
  # last_x : The real x coordinate right before moving straight
  # last_y : The real y coordinate right before moving straight
  # d: The movement direction
  def pixel_movement_straight(last_x, last_y, d) # New
    mpm = DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0
    # Uses a binary search to find the point making the char to become passable
    while (@x - last_x).abs > mpm || (@y - last_y).abs > mpm
      @real_x = (@x + last_x) / 2
      @real_y = (@y + last_y) / 2
      if passable?(@real_x, @real_y, d)
        last_x = @real_x
        next last_y = @real_y
      end
      @x = @real_x
      @y = @real_y
    end
    #
    @real_x = @x
    @real_y = @y
  end # pixel_movement_straight

  #----------------------------------------------------------------------------|
  #  Fixes the bullet through paper problem when moving diagonally             |
  #----------------------------------------------------------------------------|
  # horz: The horizontal direction component
  # vert: The vertical direction component
  def set_pixel_movement_diagonal(horz, vert) # New
    # Sets the maximum number of pixels covered that are still passable
    mpm = DoubleX_RMVXA::Pixel_Movement.min_pixel_move / 32.0
    xi = @real_x
    yi = @real_y
    xs = (@x - @real_x) / (@x - @real_x).abs
    ys = (@y - @real_y) / (@y - @real_y).abs
    while xi * xs <= @x * xs && yi * ys <= @y * ys && 
    diagonal_passable?(xi, yi, horz, vert)
      xi += mpm * xs
      yi += mpm * ys
    end
    @x = xi
    @y = yi
    #
  end # set_pixel_movement_diagonal

  #----------------------------------------------------------------------------|
  #  Tries to set the real x and y positions to be their nearest integers      |
  #----------------------------------------------------------------------------|
  def pixel_movement_nearest_tile # v1.01a+; New
    test_x = ((@x * 2).to_i + 1) / 2
    test_y = ((@y * 2).to_i + 1) / 2
    [2, 4, 6, 8].each { |d| return unless passable?(test_x, test_y, d) }
    @x = test_x
    @y = test_y
  end # pixel_movement_nearest_tile

end # Game_CharacterBase

class Game_Player < Game_Character # v1.01a+; Edit

  def update # Rewrite
    last_real_x = @real_x
    last_real_y = @real_y
    last_moving = moving?
    move_by_input
    super
    update_scroll(last_real_x, last_real_y)
    update_vehicle
    # Rewritten
    unless $game_map.interpreter.running?
      moving? ? pixel_movement_update : update_nonmoving(last_moving)
    end
    #
    @followers.update
    # Added
    return unless Input.trigger?(DoubleX_RMVXA::Pixel_Movement.nearest_tile_key)
    pixel_movement_nearest_tile
    #
  end # update

  # last_moving: The moving flag at the last frame
  def update_nonmoving(last_moving) # Rewrite
    # Rewritten
    return if last_moving && check_touch_event
    movable? && Input.trigger?(:C) && (get_on_off_vehicle || check_action_event)
    #
  end # update_nonmoving

  alias move_by_input_pixel_movement move_by_input
  def move_by_input
    # Added
    @pixel_movement_diff = ((@x - @real_x) ** 2 + (@y - @real_y) ** 2) ** 0.5
    #
    move_by_input_pixel_movement
  end # move_by_input

  alias encounter_progress_value_pixel_movement encounter_progress_value
  def encounter_progress_value
    encounter_progress_value_pixel_movement * @pixel_movement_diff # Rewritten
  end # encounter_progress_value

  def moving? # New
    @pixel_movement_diff != 0
  end # moving?

  def pixel_movement_update # New
    $game_party.on_player_walk
    check_touch_event || update_encounter
  end # pixel_movement_update

end # Game_Player

#------------------------------------------------------------------------------|

#==============================================================================|