#==============================================================================
# ** TDS Move Event With Player
#    Ver: 1.0
#------------------------------------------------------------------------------
#  * Description:
#  This script makes events move whenever the player moves, it also allows them
#  to mimic the player or do the opposite.
#------------------------------------------------------------------------------
#  * Features: 
#  Move when the player moves.
#  Mimic Player normal or opposite movements. (If the Player moves up event moves down)
#  Set custom mimic directions. (If the Player moves up event moves left)
#------------------------------------------------------------------------------
#  * Instructions:
#
#  To make an event move whenever the player moves add this to a comment in the
#  events page.
#
#    <Move_With_Player(: Steps)>
#
#    Steps = Amount of steps to move when the player moves. (Optional)
#    Example: <Move_With_Player> or <Move_With_Player: 3>
#
#------------------------------------------------------------------------------
#  Move Tags:
#    These tags provide optional functionality to the event when the player
#    moves. If none of these tags are used the event will move based on its
#    movement type.
#------------------------------------------------------------------------------
#
#  <Player_Move_Step_Wait(: Steps)>
#    ^ Amount of steps the player has to take before the event moves. (Optional)
#    ^ Example: <Player_Move_Step_Wait> or <Player_Move_Step_Wait: 2>
#
#  <Mimic_Player_Movement>
#    ^ Makes the event move in the same direction as the player.
#
#  <Reverse_Mimic_Player_Movement>
#    ^ Makes the event move in the opposite direction as the player.
#
#  <Custom_Mimic_Direction_DIR: DIR>
#    ^ If mimicking the player's movement it change directions based on these.
#    ^ DIR should be changed to any of these (UP, LEFT, RIGHT, DOWN)
#    ^ Example: <Custom_Mimic_Direction_UP: DOWN>
#
#  <Match_Player_Speed(: Offset)>
#    ^ Will match the event speed to the players speed when the player moves.
#    ^ Offset is the amount of speed to add or remove when matching speed. (Optional)
#    ^ Example: <Match_Player_Speed> or <Match_Player_Speed: -1>
#
#  <Player_Move_Wait>
#    ^ Will make the player unable to move until the event is done moving.
#------------------------------------------------------------------------------
#  * Notes:
#  None.
#------------------------------------------------------------------------------
# WARNING:
#
# Do not release, distribute or change my work without my expressed written 
# consent, doing so violates the terms of use of this work.
#
# If you really want to share my work please just post a link to the original
# site.
#
# * Not Knowing English or understanding these terms will not excuse you in any
#   way from the consequenses.
#==============================================================================
# * Import to Global Hash *
#==============================================================================
($imported ||= {})[:TDS_Move_Event_With_Player] = true


#==============================================================================
# ** Game_Temp
#------------------------------------------------------------------------------
#  This class handles temporary data that is not included with save data.
# The instance of this class is referenced by $game_temp.
#==============================================================================

class Game_Temp
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_reader :player_move_events  # Array of Events Following Player Movements
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------  
  alias tds_move_event_with_player_game_temp_initialize            initialize 
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize(*args, &block)
    # Run Original Method
    tds_move_event_with_player_game_temp_initialize(*args, &block)    
    # Initialize Player Move Events
    @player_move_events = []
  end
  #--------------------------------------------------------------------------
  # * Determine if Events are moving with the player
  #--------------------------------------------------------------------------
  def events_moving_with_player? ; !@player_move_events.empty? end
  #--------------------------------------------------------------------------
  # * Add Event Moving with Player
  #--------------------------------------------------------------------------
  def add_event_moving_with_player(event) ; @player_move_events << event if !@player_move_events.include?(event) end
  #--------------------------------------------------------------------------
  # * Remove Event Moving with Player
  #--------------------------------------------------------------------------
  def remove_event_moving_with_player(event) ; @player_move_events.delete(event) end
end


#==============================================================================
# ** 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 < Game_Character
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------  
  alias tds_move_event_with_player_game_player_increase_steps   increase_steps
  alias tds_move_event_with_player_game_player_movable?         movable?
  alias tds_move_event_with_player_game_player_perform_transfer perform_transfer  
  #--------------------------------------------------------------------------
  # * Increase Steps
  #--------------------------------------------------------------------------
  def increase_steps(*args, &block)
    # If Normal Walk
    if normal_walk?
      # Move Events that move with the player
      $game_map.events.values.each {|e| e.move_with_player if e.move_with_player?}
    end
    # Run Original Method
    tds_move_event_with_player_game_player_increase_steps(*args, &block)
  end
  #--------------------------------------------------------------------------
  # * Determine if Movement is Possible
  #--------------------------------------------------------------------------
  def movable?(*args, &block)
    # Return False if there are events moving with the player
    return false if $game_temp.events_moving_with_player?
    # Run Original Method
    tds_move_event_with_player_game_player_movable?(*args, &block)
  end  
  #--------------------------------------------------------------------------
  # * Execute Player Transfer
  #--------------------------------------------------------------------------
  def perform_transfer(*args, &block)    
    # Clear Game Temp Events Moving with Player Array if Moving to a new map
    $game_temp.player_move_events.clear if transfer? and @new_map_id != $game_map.map_id
    # Run Original Method
    tds_move_event_with_player_game_player_perform_transfer(*args, &block)    
  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 < Game_Character
  #--------------------------------------------------------------------------
  # * Constants (Structs)
  #--------------------------------------------------------------------------
  # Move With Player Settings
  Move_With_Player_Settings = Struct.new(:active, :steps, :original_steps,
  :step_wait, :original_step_wait, :mimic, :reverse_mimic, :custom_mimic,
  :match_speed, :match_speed_offset, :wait, :waiting, :direction, :speed)  
  #--------------------------------------------------------------------------
  # * Alias Listing
  #--------------------------------------------------------------------------  
  alias tds_move_event_with_player_game_event_update_self_movement update_self_movement
  alias tds_move_event_with_player_game_event_clear_page_settings  clear_page_settings
  alias tds_move_event_with_player_game_event_setup_page_settings  setup_page_settings
  #--------------------------------------------------------------------------
  # * Determine if Event should move along with player
  #--------------------------------------------------------------------------
  def move_with_player? ; @move_with_player.active end  
  #--------------------------------------------------------------------------
  # * Update During Autonomous Movement
  #--------------------------------------------------------------------------
  def update_self_movement(*args, &block)    
    # Update Move With Player Movement if Moving with Player
    return update_move_with_player_movement if move_with_player? 
    # Run Original Method
    tds_move_event_with_player_game_event_update_self_movement(*args, &block)
  end
  #--------------------------------------------------------------------------
  # * Update Move With Player Movement
  #--------------------------------------------------------------------------
  def update_move_with_player_movement
    # If not moving and Waiting Flag is true and there are no remaining steps
    if !moving? and @move_with_player.waiting and @move_with_player.steps <= 0
      # Remove Self to Array of Events Moving With Player 
      $game_temp.remove_event_moving_with_player(self)
      # Set Move with Player Waiting flag to false
      @move_with_player.waiting = false
    end
    
    # Return if Moving or Move with Player remaining steps is 0 or less
    return if moving? or @move_with_player.steps <= 0 or @move_with_player.step_wait > 0
    # Decrease Move With Player Remaining Steps Counter    
    @move_with_player.steps -= 1
    # Reset Move With Player Step Wait      
    @move_with_player.step_wait = @move_with_player.original_step_wait
    
    # If Matching Player Movement Speed
    if @move_with_player.match_speed
      # Set Move Speed Adjusted by Offset
      @move_speed = (@move_with_player.speed + @move_with_player.match_speed_offset)
    end
    
    # If Mimicking Player Movement
    if @move_with_player.mimic 
      # Get Player Direction
      direction = @move_with_player.direction
      # If Move With Player Custom Mimic Hash is not empty and Has Custom Direction
      if !@move_with_player.custom_mimic.empty? and @move_with_player.custom_mimic.has_key?(direction)
        # Set Direction
        direction = @move_with_player.custom_mimic[@move_with_player.direction]
      end
      # Move in the in direction
      return move_straight(direction)
    end
    
    # Move in Opposite Direction If Mimicking Player Movement in Reverse
    return move_straight(reverse_dir(@move_with_player.direction)) if @move_with_player.reverse_mimic
    
    # Move Type Case
    case @move_type
    when 1 ; move_type_random
    when 2 ; move_type_toward_player
    when 3
      # Update Move Route
      update_routine_move
      # Update Move Route if at Last Command (Prevents stop)
      update_routine_move if @move_route.list[@move_route_index].code == 0
    end    
  end
  #--------------------------------------------------------------------------
  # * Update During Autonomous Movement
  #--------------------------------------------------------------------------
  def move_with_player
    # Return if Move With Player Step Wait is more than 0
    return @move_with_player.step_wait -= 1 if @move_with_player.step_wait > 0
     # Return if moving or Have Steps Remaining
    return if moving? or @move_with_player.steps > 0
    # Reset Move With Player Steps
    @move_with_player.steps = @move_with_player.original_steps
    # Set Move With Player Direction (Direction when the player moved)
    @move_with_player.direction = $game_player.direction
    # Set Move With Player Speed
    @move_with_player.speed = $game_player.real_move_speed
    # If Wait flag is true
    if @move_with_player.wait
      # Add Self to Array of Events Moving With Player 
      $game_temp.add_event_moving_with_player(self) 
      # Set Move with player waiting flag
      @move_with_player.waiting = true
    end
  end
  #--------------------------------------------------------------------------
  # * Clear Event Page Settings
  #--------------------------------------------------------------------------
  def clear_page_settings(*args, &block)
    # Run Original Method
    tds_move_event_with_player_game_event_clear_page_settings(*args, &block)
    # Clear Move With Player Page Settings
    clear_move_with_player_page_settings
  end
  #--------------------------------------------------------------------------
  # * Clear Event Page Move with Player Settings
  #--------------------------------------------------------------------------
  def clear_move_with_player_page_settings
    # Create Move with Player Settings Struct
    @move_with_player = Move_With_Player_Settings.new
    # Set Move With Player Active Flag to false
    @move_with_player.active = false
    
    # Move With Player Speed Match Flag & Offset
    @move_with_player.match_speed = false ; @move_with_player.match_speed_offset = 0
    
    # Set Move With Player Mimic Flags
    @move_with_player.mimic = @move_with_player.reverse_mimic  = false
    # Clear Move With Player Custom Mimic Hash
    @move_with_player.custom_mimic = {}

    # Move With Player Step & Original Step values
    @move_with_player.steps = @move_with_player.original_steps = 0
    # Set Move With Player Step Wait & Original Step Wait values        
    @move_with_player.step_wait = @move_with_player.original_step_wait = 0    
    
    # Set Move With Player Diection & Speed
    @move_with_player.direction = 0 ; @move_with_player.speed = 0
    # Set Move With Player Wait and Waiting Flags
    @move_with_player.wait = @move_with_player.waiting = false
    # Remove Self to Array of Events Moving With Player 
    $game_temp.remove_event_moving_with_player(self)    
  end
  #--------------------------------------------------------------------------
  # * Set Up Event Page Settings
  #--------------------------------------------------------------------------
  def setup_page_settings(*args, &block)
    # Run Original Method
    tds_move_event_with_player_game_event_setup_page_settings(*args, &block)
    # Setup Page Move With Player Settings
    setup_page_move_with_player_settings
  end
  #--------------------------------------------------------------------------
  # * Set Up Event Page Move With Player Settings
  #--------------------------------------------------------------------------
  def setup_page_move_with_player_settings
    # Clear Move With Player Page Settings
    clear_move_with_player_page_settings
    # Get All Page Comment Text
    comment_text = @list.select {|c| [108, 408].include? (c.code)}.collect {|c| c.parameters}.join
    # Return if Comment Text is empty
    return if comment_text.empty?    
    # Set Move With Player Active Flag to true if Text Flag exist
    @move_with_player.active = true if comment_text =~ /<Move_With_Player[:]?\s?(-?\d+)?>/i        
    # Set Move with Player Steps (Amount of steps to take per player move)
    @move_with_player.original_steps = $1.nil? ? 1 : $1.to_i

    # Return if Move With Player Flag is false
    return if !@move_with_player.active
    
    # Match Comment Text for Step Wait Values
    comment_text[/<Player_Move_Step_Wait: (\d+)>/i]
    @move_with_player.step_wait = @move_with_player.original_step_wait = $1.nil? ? 0 : $1.to_i
     
    # Set Move With Player Match Speed Flag to true if Text Flag exists    
    @move_with_player.match_speed = true if comment_text =~ /<Match_Player_Speed[:]?\s?(-?\d+)?>/i
    # Set Move With Player Match Speed offset
    @move_with_player.match_speed_offset = $1.nil? ? 0 : $1.to_i    

    # Set Move with Player Mimic Flag to true if Text Flag exist
    @move_with_player.mimic = true if comment_text =~ /<Mimic_Player_Movement>/i
    # Set Move with Player Reverse Mimic Flag to true if Text Flag exist
    @move_with_player.reverse_mimic = true if comment_text =~ /<Reverse_Mimic_Player_Movement>/i
    
    # Match Comment Text for Custom Mimic Direction
    comment_text.scan(/<Custom_Mimic_Direction_(UP|DOWN|LEFT|RIGHT): (UP|DOWN|LEFT|RIGHT)>/i) {|dir|
      # Go Through Directions
      dir.each {|s| 
        # Convert Direction names to numbers
        s.gsub!(/DOWN/i){"2"} ; s.gsub!(/LEFT/i){"4"} ; s.gsub!(/RIGHT/i){"6"}
        s.gsub!(/UP/i){"8"}
      }
      # Set Move With Player Custom Mimic Direction
      @move_with_player.custom_mimic[dir.at(0).to_i] = dir.at(1).to_i
    }    
    
    # Set Move With Player Wait flag to true if Text Flag exist
    @move_with_player.wait = true if comment_text =~ /<Player_Move_Wait>/i
  end
end