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  