#==============================================================================
# ** Follow Trail v1.0.1                                           (2022-09-07)
#    by Wreon
#------------------------------------------------------------------------------
#  This script allows chasing events to follow the player's trail exactly,
#  including diagonal movement and jumping.
#  
#  Usage:
#    event.follow_player_movement - Follow the player's trail
#    event.watch_player_movement - Start recording the player's movement
#  
#  watch_player_movement is only necessary if follow_player_movement is called
#  after the player starts moving, for example an event that waits a bit before
#  chasing.
#  
#  Release v1.0.1:
#    -Fixed followers blocking movement
#  Release v1.0.0:
#    -Base release
#==============================================================================

# The maximum length of the movement record array before it cuts off to avoid
# memory leaks, although unlikely.
MOVEMENT_RECORD_MAX_LENGTH = 500

#==============================================================================
# ** Game_Player
#------------------------------------------------------------------------------
#  This class handles the player. It includes event starting determinants and
# map scrolling functions. The instance of this class is referenced by
# $game_player.
#==============================================================================

class Game_Player
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_reader   :movement_record          # Array of Movement Inputs
  attr_reader   :start_position           # Start Position on Map
  #--------------------------------------------------------------------------
  # * Move to Designated Position
  #--------------------------------------------------------------------------
  alias movement_record_moveto moveto
  def moveto(x, y)
    movement_record_moveto(x, y)
    @start_position = [@x, @y]
  end
  #--------------------------------------------------------------------------
  # * Start Recording Movement
  #--------------------------------------------------------------------------
  def start_recording_movement
    @movement_record = []
  end
  #--------------------------------------------------------------------------
  # * Move Straight
  #--------------------------------------------------------------------------
  alias movement_record_move_straight move_straight
  def move_straight(d, turn_ok = true)
    movement_record_move_straight(d, turn_ok)
    @movement_record.push([0, d, turn_ok]) if @move_succeed and @movement_record and @movement_record.length < MOVEMENT_RECORD_MAX_LENGTH
  end
  #--------------------------------------------------------------------------
  # * Move Diagonally
  #--------------------------------------------------------------------------
  alias movement_record_move_diagonal move_diagonal
  def move_diagonal(horz, vert)
    movement_record_move_diagonal(horz, vert)
    @movement_record.push([1, horz, vert]) if @move_succeed and @movement_record and @movement_record.length < MOVEMENT_RECORD_MAX_LENGTH
  end
  #--------------------------------------------------------------------------
  # * Jump
  #     x_plus : x-coordinate plus value
  #     y_plus : y-coordinate plus value
  #--------------------------------------------------------------------------
  alias movement_record_jump jump
  def jump(x_plus, y_plus)
    movement_record_jump(x_plus, y_plus)
    @movement_record.push([2, x_plus, y_plus]) if @movement_record and @movement_record.length < MOVEMENT_RECORD_MAX_LENGTH
  end
  #--------------------------------------------------------------------------
  # * Execute Player Transfer
  #--------------------------------------------------------------------------
  alias movement_record_perform_transfer perform_transfer
  def perform_transfer
    @movement_record = nil if transfer?
    movement_record_perform_transfer
  end
end

#==============================================================================
# ** Game_Event
#------------------------------------------------------------------------------
#  This class handles events. Functions include event page switching via
# condition determinants and running parallel process events. Used within the
# Game_Map class.
#==============================================================================

class Game_Event
  #--------------------------------------------------------------------------
  # * Move Toward Character
  #--------------------------------------------------------------------------
  def move_toward_target(x, y)
    sx = distance_x_from(x)
    sy = distance_y_from(y)
    if sx.abs > sy.abs
      move_straight(sx > 0 ? 4 : 6)
      move_straight(sy > 0 ? 8 : 2) if !@move_succeed && sy != 0
    elsif sy != 0
      move_straight(sy > 0 ? 8 : 2)
      move_straight(sx > 0 ? 4 : 6) if !@move_succeed && sx != 0
    end
  end
  #--------------------------------------------------------------------------
  # * Follow Player's Trail
  #--------------------------------------------------------------------------
  def follow_player_movement
    # Start recording the player's movements
    if !$game_player.movement_record then
      $game_player.start_recording_movement
    end
    # Get the player's start position
    player_start_pos = $game_player.start_position
    # Check if the event has reached the player's start point
    if @x == player_start_pos[0] and @y == player_start_pos[1] then
      @reached_start_pos = true
    end
    # Move to the player's start point first of all
    if !@reached_start_pos then
      # Removed due to issues: pathfind(@player_start_pos[0], @player_start_pos[1])
      previous_through = @through
      @through = true
      move_toward_target(player_start_pos[0], player_start_pos[1])
      @through = previous_through
    # Follow the player's movements
    else
      # Begin following the player from their first movement
      if !@player_movement_record_index then
        @player_movement_record_index = 0
      end
      # Follow the player's current movement
      current_movement = $game_player.movement_record[@player_movement_record_index]
      if current_movement then
        previous_through = @through
        @through = true
        # Move straight
        if current_movement[0] == 0 then
          move_straight(current_movement[1], current_movement[2])
        # Move diagonally
        elsif current_movement[0] == 1 then
          move_diagonal(current_movement[1], current_movement[2])
        # Jump
        elsif current_movement[0] == 2 then
          jump(current_movement[1], current_movement[2])
        end
        @through = previous_through
        @player_movement_record_index += 1
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Watch Player's Movement
  #--------------------------------------------------------------------------
  def watch_player_movement
    if !$game_player.movement_record then
      $game_player.start_recording_movement
    end
  end
end