class Game_Interpreter
  #--------------------------------------------------------------------------
  # ● 指定した座標の位置まで移動するルートの設定
  #--------------------------------------------------------------------------
  def route_move_to_the_pointx(character_id,x,y,mode_id,wait_flag = false)
    character = character_id == 0 ? $game_player : $game_map.events[character_id]
    character.move_auto.set_init
    character.move_auto.move_id = 1
    character.move_auto.base_mode = mode_id
    
    character.move_auto.vars = [x,y]
    Fiber.yield while character.move_auto.move_id > 0 if wait_flag
  end 
  
  #--------------------------------------------------------------------------
  # ● 指定した座標の位置まで移動する
  #--------------------------------------------------------------------------
  def move_ex_point(character_id,x,y,mode_id,wait_flag = false)
    $game_map.refresh if $game_map.need_refresh
    route_move_to_the_pointx(character_id,x,y,mode_id,wait_flag)
  end  
  
  #--------------------------------------------------------------------------
  # ● 指定した変数の座標の位置まで移動する
  #--------------------------------------------------------------------------
  def move_ex_pointv(character_id,vid1,vid2,mode_id,wait_flag = false)
    $game_map.refresh if $game_map.need_refresh
    x = $game_variables[vid1]
    y = $game_variables[vid2]    
    route_move_to_the_pointx(character_id,x,y,mode_id,wait_flag)
  end    
  #--------------------------------------------------------------------------
  # ● 指定したキャラの座標の位置まで移動する
  #--------------------------------------------------------------------------
  def move_ex_character(character_id,eid,mode_id,wait_flag = false)
    $game_map.refresh if $game_map.need_refresh
    target = eid == 0 ? $game_player : $game_map.events[eid] 
    x = target.x
    y = target.y
    route_move_to_the_pointx(character_id,x,y,mode_id,wait_flag)
  end    
end  

class Game_Character < Game_CharacterBase

  def move_auto
    set_auto_move unless @move_auto
    @move_auto
  end  
  
  def move_auto=(m_auto)
    @move_auto = m_auto
  end  
  
  def update_move_auto_memory
#~     p @move_auto.route_memory_size
    @move_auto.init_route_memory if @move_auto.route_memory_size != $game_map.m_size
  end  
  #--------------------------------------------------------------------------
  # ● 停止時の更新
  #--------------------------------------------------------------------------
  alias tako435fbnupdate_stop update_stop
  def update_stop
    tako435fbnupdate_stop
    update_auto_move if @move_auto && @move_auto.move_id > 0
  end
  #--------------------------------------------------------------------------
  # ● ルートに沿った移動の更新
  #--------------------------------------------------------------------------
  def update_auto_move
    update_move_auto_memory

    if end_auto_move?
      clear_auto_move
    else
      process_auto_move
    end  

  end
  
  #--------------------------------------------------------------------------
  # ● auto_moveの作成
  #--------------------------------------------------------------------------
  def set_auto_move
    @move_auto = Auto_Move.new
  end     
  
  
  #--------------------------------------------------------------------------
  # ● auto_moveの初期化
  #--------------------------------------------------------------------------
  def clear_auto_move
    @move_auto.clear    
  end    
  
  #--------------------------------------------------------------------------
  # ● auto_moveの処理
  #--------------------------------------------------------------------------
  def process_auto_move
    move_to_the_point_ex(@move_auto.vars[0],@move_auto.vars[1] )
  end  
  #--------------------------------------------------------------------------
  # ● auto_moveの終了判定
  #--------------------------------------------------------------------------
  def end_auto_move?
    @x == @move_auto.vars[0] && @y == @move_auto.vars[1]
  end  
  #--------------------------------------------------------------------------
  # ● 指定したポイントに近づく
  #--------------------------------------------------------------------------
  def move_to_the_point_ex(x,y)
    sx = distance_x_from(x)
    sy = distance_y_from(y)
    z = y * $game_map.width + x
    px = @x
    py = @y    
    
    update_move_mode_ex(sx,sy)
    t_mode = @move_auto.move_mode == @move_auto.base_mode ? @move_auto.base_mode : set_move_mode(@direction)
    direction_w = direction_move_beside_wall(t_mode != 0 ? t_mode : @move_auto.base_mode)
    
    
    if @move_auto.move_mode == 0 

      process_move_toward_the_piont(sx,sy,t_mode)
    else
      move_beside_wall(t_mode)
    end  
    memorize_direction_w(px,py,direction_w) if direction_w != @direction && @move_auto.route_memory[z]  & 0b11110000 == 0 
  end    
  
  def update_move_mode_ex(sx,sy)
    if sx.abs + sy.abs < @move_auto.switch_point[0].abs + @move_auto.switch_point[1].abs    
      change_move_auto_mode_normal 
    end  
  end
  
  def set_move_mode(direction)
    return @move_auto.base_mode if !passable?(@x, @y, direction_hands(1 , 0, direction))
    return move_mode_conjugate(@move_auto.base_mode) if !passable?(@x, @y, direction_hands(2 , 0, direction))
    return 0
  end  
  
  def move_mode_conjugate(mode)
    if mode == 1
      return 2
    elsif mode == 2
      return 1
    else  
      return mode
    end  
  end  

  def direction_move_beside_wall(mode) 
    z = y * $game_map.width + x
    move_status = auto_move_point(mode) 
    
#~     printf("%b\n" ,move_status)
    if move_status == 0b011111
      direction_hands(mode , 1, @direction)
    elsif @move_auto.route_memory[z]  & 0b11110000 != 0
#~       printf("%b\n" ,@move_auto.route_memory[z])
      get_memorized_direction(z)
      
    elsif move_status & 0b010010 == 0b000010 
      direction_hands(mode , 0, @direction)
    elsif move_status & 0b010011 == 0b010011 
      @direction  
    elsif move_status & 0b010101 == 0b010100 
      direction_hands(mode , 1, @direction) 
    elsif move_status & 0b000011 == 0b000001 
      @direction  
    elsif move_status & 0b000010 == 0b000010 
      direction_hands(mode , 0, @direction)
    elsif move_status & 0b000100 == 0b000100
      direction_hands(mode , 1, @direction)
    elsif move_status & 0b001000 == 0b001000
      reverse_dir(@direction)
    elsif move_status & 0b000011 ==  0b000011
      direction_hands(mode , 0, @direction)
    elsif move_status & 0b000001 == 0b000001  
      @direction
    else
      @direction
    end  
    
  end
  def move_beside_wall(mode)
    z = y * $game_map.width + x
    direction = direction_move_beside_wall(mode)
    if !check_memorized_route_cycle(@x,@y,direction)
      memorize_route(@x,@y,direction)
      @move_auto.route_memory[z] &= 0b00001111 if @move_auto.route_memory[z]  & 0b11110000 != 0
      move_straight(direction)
      
    else

      direction = direction_move_beside_wall(move_mode_conjugate(mode))
      delete_route_memory(z ,direction)

      move_straight(direction)      
    end  
    
  end  
 
  
  def memorize_route(x,y,direction)
    z = y * $game_map.width + x
    @move_auto.route_memory[z] |= route_memory_value(direction)
  end
  
  def check_memorized_route_cycle(x,y,direction)
    value = route_memory_value(direction)
    z = y * $game_map.width + x
    @move_auto.route_memory[z] & route_memory_value(direction) != 0
  end  
 
  
  def route_memory_value(direction)
    case direction
    when 2; 0b00000001
    when 4; 0b00000010
    when 6; 0b00000100
    when 8; 0b00001000  
    end  
  end  
  
  def delete_route_memory(z ,direciton)
    @move_auto.route_memory[z] & ~route_memory_value(direction)
  end  
   
  def memorize_direction_w(x,y,direction)
    z = y * $game_map.width + x
    @move_auto.route_memory[z] |= route_memory_value(direction) << 4
  end  
  
  def get_memorized_direction(z)
    [2,4,6,8].each do |d| 
      return d if @move_auto.route_memory[z] >> 4 & route_memory_value(d) == route_memory_value(d)
    end
    return 0  
  end
  
  def process_move_toward_the_piont(sx,sy,mode)
    if sx.abs > sy.abs
      return move_straight(sx > 0 ? 4 : 6) if passable?(@x, @y, (sx > 0 ? 4 : 6))
      return move_straight(sy > 0 ? 8 : 2) if passable?(@x, @y, (sy > 0 ? 8 : 2)) && sy != 0
    elsif sy != 0
      return move_straight(sy > 0 ? 8 : 2) if passable?(@x, @y, (sy > 0 ? 8 : 2))
      return move_straight(sx > 0 ? 4 : 6) if passable?(@x, @y, (sx > 0 ? 4 : 6)) && sx != 0
    end     
    start_auto_move(sx,sy,mode)
  end    
  
  
  def start_auto_move(sx,sy,mode)
    @move_auto.move_mode = mode
    @move_auto.switch_point = [sx,sy]
    @move_auto.switch_axis = sx.abs > sy.abs ? 0 : 1
      
    move_beside_wall(mode)    
  end
  
  def change_move_auto_mode_normal
    @move_auto.move_mode = 0
    @move_auto.switch_point = [0,0]  
    @move_auto.switch_axis = 0
  end  

  
  def direction_right_hand(direction)
    case direction
    when 2 ; 4
    when 4 ; 8
    when 6 ; 2
    when 8 ; 6
    end        
  end  
  
  def direction_left_hand(direction)
    reverse_dir(direction_right_hand(direction))     
  end   
  
  def direction_hands(mode , hand_id,direction)
    (hand_id + mode) % 2 == 1 ? direction_right_hand(direction) : direction_left_hand(direction)
  end  
  
  
  def auto_move_point(mode)
    d = @direction
    value = 0b000000 

    b_point = point_the_back
    value |= 0b000001 if passable?(@x, @y, d)
    value |= 0b000010 if passable?(@x, @y, direction_hands(mode , 0, d))
    value |= 0b000100 if passable?(@x, @y, direction_hands(mode , 1, d))
    value |= 0b001000 if passable?(@x, @y, reverse_dir(d)) 
    value |= 0b010000 if passable?(b_point[0], b_point[1], direction_hands(mode , 0 ,@direction))
    value |= 0b100000 if passable?(b_point[0], b_point[1], direction_hands(mode , 1 ,@direction))
    return value
  end  
  
  def point_the_back
    case @direction
    when 2 ; [@x , @y - 1]
    when 4 ; [@x + 1 , @y] 
    when 6 ; [@x - 1 , @y]
    when 8 ; [@x , @y + 1]
    end  
  end  
end  

class Auto_Move
  attr_accessor :move_id
  attr_accessor :base_mode
  attr_accessor :move_mode
  attr_accessor :vars
  attr_accessor :switch_point
  attr_accessor :switch_axis 
  attr_accessor :route_memory
  attr_accessor :route_memory_size
  def initialize
    set_init
  end  
  

  def set_init
    set_start
    init_route_memory
  end  
  
  def clear 
    set_start
    clear_route_memory    
  end  
  
  def set_start
    @move_id = 0
    @base_mode = 1
    @move_mode = 0
    @vars = [0,0]
    @switch_point= [0 ,0]
    @switch_axis = 0    
  end
  

  def init_route_memory
    @route_memory_size = $game_map.m_size
    @route_memory = [0b00000000] * @route_memory_size
  end 
  
  def clear_route_memory
    @route_memory_size = 1
    @route_memory = [0b00000000] 
  end   
 
end 

class Game_Map
  
  def width
    @map.width
  end  
  
  def height
    @map.height
  end  
    
  def m_size
    width * height
  end  
end  
 
class Game_Player < Game_Character
  #--------------------------------------------------------------------------
  # ● 移動可能判定
  #--------------------------------------------------------------------------
  alias tako123b4movable? movable?
  def movable?
    return false if move_auto.move_id > 0
    tako123b4movable? 
  end
end  