# @taroxd metadata 1.0
# @require taroxd_core
# @display 用图片设置地图通行度
# @id collision
# @help 
#             会用 Parallaxes 文件夹下面的对应图片作为该地图的通行度。
#             图片上透明的点表示可以通行,不透明的点表示不能通行。
#             不处理地图循环的情况。

module Taroxd::Collision
  ENABLE_FLOAT_POSITION = false   # 是否允许坐标出现小数。可能会导致未知错误。

  # 人物判定点到图块左上角的距离
  X_OFFSET = 16
  Y_OFFSET = 16

  # position:
  #   行走到的最远位置的坐标(可为 x 坐标或 y 坐标)
  # status:
  #   nil: 完全无法行走
  #   false: 可以行走,但无法走过一格。此时 position 为浮点数
  #   true: 可以完全走过一格,此时 position 为整数
  PassageStatus = Struct.new :position, :status

  def self.passage_status(x, y, d)
    pos = nil
    bx = (x * 32 + X_OFFSET).round
    by = (y * 32 + Y_OFFSET).round

    is_x = d == 4 || d == 6
    current = is_x ? x : y

    if d == 2 || d == 6
      step = 1
      target = (current + 1).floor
    else
      step = -1
      target = (current - 1).ceil
    end

    lbound = (current * 32).round + step
    ubound = target * 32
    bitmap = $game_map.collision_bitmap
    lbound.step(ubound, step) do |i|
      if is_x
        bx = i + X_OFFSET
      else
        by = i + Y_OFFSET
      end

      if bitmap.get_pixel(bx, by).alpha == 0
        pos = i
      else
        break
      end
    end

    if pos
      if pos == ubound
        PassageStatus[pos / 32, true]
      else
        PassageStatus[pos / 32.0, false]
      end
    else
      PassageStatus[nil, nil]
    end
  end
end

RPG::Map.note_s :collision

class Game_Map
  def collision?
    @map.collision
  end

  def collision_bitmap
    @map.collision && Cache.parallax(@map.collision)
  end

  # preload bitmap in cache
  def_after :setup do |_|
    collision_bitmap
  end

  def_and :passable? do |x, y, d|
    Taroxd::Collision.passage_status(x, y, d).status
  end unless Taroxd::Collision::ENABLE_FLOAT_POSITION
end

class Game_CharacterBase
  def_chain :move_straight do |old, d, turn_ok = true|
    if $game_map.collision? && !(@through || debug_through?)
      @move_succeed = passable?(@x.round, @y.round, d)

      if @move_succeed
        pos = Taroxd::Collision.passage_status(@x, @y, d).position
        if pos
          set_direction(d)
          d == 4 || d == 6 ? @x = pos : @y = pos
          increase_steps
        else
          @move_succeed = false
        end
      end

      if !@move_succeed && turn_ok
        set_direction(d)
        check_event_trigger_touch_front
      end
    else
      old.call(d, turn_ok)
    end
  end

end if Taroxd::Collision::ENABLE_FLOAT_POSITION