class Particle
  def initialize(viewport, bitmap)
    @sprite = Sprite.new(viewport)
    @sprite.bitmap = bitmap
    @sprite.ox = bitmap.width / 2
    @sprite.oy = bitmap.height / 2
    @light = Sprite.new(viewport)
    @light.bitmap = RPG::Cache.light("light")
    @light.ox = @light.bitmap.width / 2
    @light.oy = @light.bitmap.height / 2
    @light.z -= 1
    @light.blend_type = 3
    @light.tone = Tone.new(512, 512, 512)
    @light_power = 1.0
    self.x = rand(Graphics.width)
    self.y = rand(Graphics.height)
  end

  def light_scale
    @light.zoom_x
  end
  def light_scale=(val)
    @light.zoom_x = @light.zoom_y = val
  end

  # Link various things to the sprite
  def x
    @x
  end
  def x=(val)
    @x = val
    width = [@sprite.bitmap.width * @sprite.zoom_x, @light.bitmap.width * @light.zoom_x].max
    if @x < -width
      @x = Graphics.width + width
    elsif @x > Graphics.width + width
      @x = -width
    end
    @light.x = @sprite.x = @x
  end
  def y
    @y
  end
  def y=(val)
    @y = val
    height = [@sprite.bitmap.height * @sprite.zoom_y, @light.bitmap.height * @light.zoom_y].max
    if @y < -height
      @y = Graphics.height + height
    elsif @y > Graphics.height + height
      @y = -height
    end
    @light.y = @sprite.y = @y
  end
  def scale
    @sprite.zoom_x
  end
  def scale=(val)
    @sprite.zoom_x = val
    @sprite.zoom_y = val
  end
  def opacity
    @sprite.opacity
  end
  def opacity=(val)
    @sprite.opacity = val
    val = val.clamp(0.0, 200.0)
    @light.modulate.set(val * @light_power, val * @light_power, val * @light_power)
  end
  def dispose
    @sprite.dispose
    @sprite = nil
  end
end

class Particle_Firefly < Particle
  @@bitmap = RPG::Cache.picture('firefly')

  def initialize(viewport)
    super(viewport, @@bitmap)
    @phase = rand(120)
    @wavelength = rand(120..240)
    @vx = rand(0.2..1.5) * (rand(2) * 2 - 1)
    @vy = rand(0.2..1.5) * (rand(2) * 2 - 1)
    @light_power = 1.0
    self.light_scale = 0.2
    self.scale = rand(0.02..0.08)
    @sprite.blend_type = 1
  end

  def update
    self.x += @vx
    self.y += @vy
    self.opacity = Math.sin((@phase / @wavelength.to_f) * Math::PI) * 255
    @phase = (@phase + 1) % @wavelength
  end
end

# A layer of moving particle objects, useful for fireflies and shrimp
class ParticleLayer
  def initialize(viewport, klass, count)
    @particles = Array.new(count)
    count.times do |i|
      @particles[i] = klass.new(viewport)
    end
    @last_map_x = $game_map.display_x / 4
    @last_map_y = $game_map.display_y / 4
  end

  def update
    return unless @particles
    map_x = $game_map.display_x / 4
    map_y = $game_map.display_y / 4
    @particles.each do |p|
      p.x += @last_map_x - map_x
      p.y += @last_map_y - map_y
      p.update
    end
    @last_map_x = map_x
    @last_map_y = map_y
  end

  def dispose
    return unless @particles
    @particles.each do |p|
      p.dispose
    end
    @particles = nil
  end
end

class Particle_Shrimp < Particle
  @@bitmap = RPG::Cache.picture('shrimp')
  TAU = Math::PI * 2

  def initialize(viewport)
    super(viewport, @@bitmap)
    @angle = rand(0..TAU)
    @speed = rand(0.2..4.0)
    self.light_scale = 0.2
    self.scale = rand(0.04..0.08)
  end

  def update
    case rand(0..10)
    when 0..1
      @angle += rand(-TAU / 8..TAU / 8)
    when 2
      @speed += rand(1.0..5.0)
      @speed = 5.0 if @speed > 5.0
    when 3..4
      @speed -= rand(1.0..2.0)
      @speed = 0.2 if @speed < 0.2
    else
      # no-op
    end
    vx = Math.cos(@angle) * @speed
    vy = Math.sin(@angle) * @speed
    self.x += vx
    self.y += vy
  end
end
