# Particle Engine, Peter O., 2007-11-03 # Based on version 2 by Near Fantastica, 04.01.06 # In turn based on the Particle Engine designed by PinkMan class Particle_Engine def initialize(viewport = nil, map = nil) @map = (map) ? map : $game_map @viewport = viewport @effect = [] @disposed = false @firsttime = true @effects = { # PinkMan's Effects "fire" => Particle_Engine::Fire, "smoke" => Particle_Engine::Smoke, "teleport" => Particle_Engine::Teleport, "spirit" => Particle_Engine::Spirit, "explosion" => Particle_Engine::Explosion, "aura" => Particle_Engine::Aura, # BlueScope's Effects "soot" => Particle_Engine::Soot, "sootsmoke" => Particle_Engine::SootSmoke, "rocket" => Particle_Engine::Rocket, "fixteleport" => Particle_Engine::FixedTeleport, "smokescreen" => Particle_Engine::Smokescreen, "flare" => Particle_Engine::Flare, "splash" => Particle_Engine::Splash, # By Peter O. "starteleport" => Particle_Engine::StarTeleport } end def dispose return if disposed? @effect.each do |particle| next if particle.nil? particle.dispose end @effect.clear @map = nil @disposed = true end def disposed? return @disposed end def add_effect(event) @effect[event.id] = pbParticleEffect(event) end def remove_effect(event) return if @effect[event.id].nil? @effect[event.id].dispose @effect.delete_at(event.id) end def realloc_effect(event, particle) type = pbEventCommentInput(event, 1, "Particle Engine Type") if type.nil? particle&.dispose return nil end type = type[0].downcase cls = @effects[type] if cls.nil? particle&.dispose return nil end if !particle || !particle.is_a?(cls) particle&.dispose particle = cls.new(event, @viewport) end return particle end def pbParticleEffect(event) return realloc_effect(event, nil) end def update if @firsttime @firsttime = false @map.events.values.each do |event| remove_effect(event) add_effect(event) end end @effect.each_with_index do |particle, i| next if particle.nil? if particle.event.pe_refresh event = particle.event event.pe_refresh = false particle = realloc_effect(event, particle) @effect[i] = particle end particle&.update end end end class ParticleEffect attr_accessor :x, :y, :z def initialize @x = 0 @y = 0 @z = 0 end def update; end def dispose; end end class ParticleSprite attr_accessor :x, :y, :z, :ox, :oy, :opacity, :blend_type attr_reader :bitmap def initialize(viewport) @viewport = viewport @sprite = nil @x = 0 @y = 0 @z = 0 @ox = 0 @oy = 0 @opacity = 255 @bitmap = nil @blend_type = 0 @minleft = 0 @mintop = 0 end def dispose @sprite&.dispose end def bitmap=(value) @bitmap = value if value @minleft = -value.width @mintop = -value.height else @minleft = 0 @mintop = 0 end end def update w = Graphics.width h = Graphics.height if !@sprite && @x >= @minleft && @y >= @mintop && @x < w && @y < h @sprite = Sprite.new(@viewport) elsif @sprite && (@x < @minleft || @y < @mintop || @x >= w || @y >= h) @sprite.dispose @sprite = nil end if @sprite @sprite.x = @x if @sprite.x != @x @sprite.x -= @ox @sprite.y = @y if @sprite.y != @y @sprite.y -= @oy @sprite.z = @z if @sprite.z != @z @sprite.opacity = @opacity if @sprite.opacity != @opacity @sprite.blend_type = @blend_type if @sprite.blend_type != @blend_type @sprite.bitmap = @bitmap if @sprite.bitmap != @bitmap end end end class ParticleEffect_Event < ParticleEffect attr_accessor :event def initialize(event, viewport = nil) @event = event @viewport = viewport @particles = [] @bitmaps = {} end def setParameters(params) @randomhue, @leftright, @fade, @maxparticless, @hue, @slowdown, @ytop, @ybottom, @xleft, @xright, @xgravity, @ygravity, @xoffset, @yoffset, @opacityvar, @originalopacity = params end def loadBitmap(filename, hue) key = [filename, hue] bitmap = @bitmaps[key] if !bitmap || bitmap.disposed? bitmap = AnimatedBitmap.new("Graphics/Fogs/" + filename, hue).deanimate @bitmaps[key] = bitmap end return bitmap end def initParticles(filename, opacity, zOffset = 0, blendtype = 1) @particles = [] @particlex = [] @particley = [] @opacity = [] @startingx = self.x + @xoffset @startingy = self.y + @yoffset @screen_x = self.x @screen_y = self.y @real_x = @event.real_x @real_y = @event.real_y @filename = filename @zoffset = zOffset @bmwidth = 32 @bmheight = 32 @maxparticless.times do |i| @particlex[i] = -@xoffset @particley[i] = -@yoffset @particles[i] = ParticleSprite.new(@viewport) @particles[i].bitmap = loadBitmap(filename, @hue) if filename if i == 0 && @particles[i].bitmap @bmwidth = @particles[i].bitmap.width @bmheight = @particles[i].bitmap.height end @particles[i].blend_type = blendtype @particles[i].y = @startingy @particles[i].x = @startingx @particles[i].z = self.z + zOffset @opacity[i] = rand(opacity / 4) @particles[i].opacity = @opacity[i] @particles[i].update end end def x; return ScreenPosHelper.pbScreenX(@event); end def y; return ScreenPosHelper.pbScreenY(@event); end def z; return ScreenPosHelper.pbScreenZ(@event); end def update if @viewport && (@viewport.rect.x >= Graphics.width || @viewport.rect.y >= Graphics.height) return end selfX = self.x selfY = self.y selfZ = self.z newRealX = @event.real_x newRealY = @event.real_y @startingx = selfX + @xoffset @startingy = selfY + @yoffset @__offsetx = (@real_x == newRealX) ? 0 : selfX - @screen_x @__offsety = (@real_y == newRealY) ? 0 : selfY - @screen_y @screen_x = selfX @screen_y = selfY @real_x = newRealX @real_y = newRealY if @opacityvar > 0 && @viewport opac = 255.0 / @opacityvar minX = (opac * (-@xgravity.to_f / @slowdown).floor) + @startingx maxX = (opac * (@xgravity.to_f / @slowdown).floor) + @startingx minY = (opac * (-@ygravity.to_f / @slowdown).floor) + @startingy maxY = @startingy minX -= @bmwidth minY -= @bmheight maxX += @bmwidth maxY += @bmheight if maxX < 0 || maxY < 0 || minX >= Graphics.width || minY >= Graphics.height # echo "skipped" return end end particleZ = selfZ + @zoffset @maxparticless.times do |i| @particles[i].z = particleZ if @particles[i].y <= @ytop @particles[i].y = @startingy + @yoffset @particles[i].x = @startingx + @xoffset @particlex[i] = 0.0 @particley[i] = 0.0 end if @particles[i].x <= @xleft @particles[i].y = @startingy + @yoffset @particles[i].x = @startingx + @xoffset @particlex[i] = 0.0 @particley[i] = 0.0 end if @particles[i].y >= @ybottom @particles[i].y = @startingy + @yoffset @particles[i].x = @startingx + @xoffset @particlex[i] = 0.0 @particley[i] = 0.0 end if @particles[i].x >= @xright @particles[i].y = @startingy + @yoffset @particles[i].x = @startingx + @xoffset @particlex[i] = 0.0 @particley[i] = 0.0 end if @fade == 0 if @opacity[i] <= 0 @opacity[i] = @originalopacity @particles[i].y = @startingy + @yoffset @particles[i].x = @startingx + @xoffset @particlex[i] = 0.0 @particley[i] = 0.0 end elsif @opacity[i] <= 0 @opacity[i] = 250 @particles[i].y = @startingy + @yoffset @particles[i].x = @startingx + @xoffset @particlex[i] = 0.0 @particley[i] = 0.0 end calcParticlePos(i) if @randomhue == 1 @hue += 0.5 @hue = 0 if @hue >= 360 @particles[i].bitmap = loadBitmap(@filename, @hue) if @filename end @opacity[i] = @opacity[i] - rand(@opacityvar) @particles[i].opacity = @opacity[i] @particles[i].update end end def calcParticlePos(i) @leftright = rand(2) if @leftright == 1 xo = -@xgravity.to_f / @slowdown else xo = @xgravity.to_f / @slowdown end yo = -@ygravity.to_f / @slowdown @particlex[i] += xo @particley[i] += yo @particlex[i] -= @__offsetx @particley[i] -= @__offsety @particlex[i] = @particlex[i].floor @particley[i] = @particley[i].floor @particles[i].x = @particlex[i] + @startingx + @xoffset @particles[i].y = @particley[i] + @startingy + @yoffset end def dispose @particles.each do |particle| particle.dispose end @bitmaps.values.each do |bitmap| bitmap.dispose end @particles.clear @bitmaps.clear end end class Particle_Engine::Fire < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 1, 20, 40, 0.5, -64, Graphics.height, -64, Graphics.width, 0.5, 0.10, -5, -13, 30, 0]) initParticles("particle", 250) end end class Particle_Engine::Smoke < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 0, 80, 20, 0.5, -64, Graphics.height, -64, Graphics.width, 0.5, 0.10, -5, -15, 5, 80]) initParticles("smoke", 250) end end class Particle_Engine::Teleport < ParticleEffect_Event def initialize(event, viewport) super setParameters([1, 1, 1, 10, rand(360), 1, -64, Graphics.height, -64, Graphics.width, 0, 3, -8, -15, 20, 0]) initParticles("wideportal", 250) @maxparticless.times do |i| @particles[i].ox = 16 @particles[i].oy = 16 end end end class Particle_Engine::Spirit < ParticleEffect_Event def initialize(event, viewport) super setParameters([1, 0, 1, 20, rand(360), 0.5, -64, Graphics.height, -64, Graphics.width, 0.5, 0.10, -5, -13, 30, 0]) initParticles("particle", 250) end end class Particle_Engine::Explosion < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 1, 20, 0, 0.5, -64, Graphics.height, -64, Graphics.width, 0.5, 0.10, -5, -13, 30, 0]) initParticles("explosion", 250) end end class Particle_Engine::Aura < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 1, 20, 0, 1, -64, Graphics.height, -64, Graphics.width, 2, 2, -5, -13, 30, 0]) initParticles("particle", 250) end end class Particle_Engine::Soot < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 0, 20, 0, 0.5, -64, Graphics.height, -64, Graphics.width, 0.5, 0.10, -5, -15, 5, 80]) initParticles("smoke", 100, 0, 2) end end class Particle_Engine::SootSmoke < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 0, 30, 0, 0.5, -64, Graphics.height, -64, Graphics.width, 0.5, 0.10, -5, -15, 5, 80]) initParticles("smoke", 100, 0) @maxparticless.times do |i| @particles[i].blend_type = rand(6) < 3 ? 1 : 2 end end end class Particle_Engine::Rocket < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 0, 60, 0, 0.5, -64, Graphics.height, -64, Graphics.width, 0.5, 0, -5, -15, 5, 80]) initParticles("smoke", 100, -1) end end class Particle_Engine::FixedTeleport < ParticleEffect_Event def initialize(event, viewport) super setParameters([1, 0, 1, 10, rand(360), 1, -Graphics.height, Graphics.height, 0, Graphics.width, 0, 3, -8, -15, 20, 0]) initParticles("wideportal", 250) @maxparticless.times do |i| @particles[i].ox = 16 @particles[i].oy = 16 end end end # By Peter O. class Particle_Engine::StarTeleport < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 1, 10, 0, 1, -Graphics.height, Graphics.height, 0, Graphics.width, 0, 3, -8, -15, 10, 0]) initParticles("star", 250) @maxparticless.times do |i| @particles[i].ox = 48 @particles[i].oy = 48 end end end class Particle_Engine::Smokescreen < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 0, 250, 0, 0.2, -64, Graphics.height, -64, Graphics.width, 0.8, 0.8, -5, -15, 5, 80]) initParticles(nil, 100) @maxparticless.times do |i| rnd = rand(3) @opacity[i] = (rnd == 0) ? 1 : 100 filename = (rnd == 0) ? "explosionsmoke" : "smoke" @particles[i].bitmap = loadBitmap(filename, @hue) end end def calcParticlePos(i) if @randomhue == 1 filename = (rand(3) == 0) ? "explosionsmoke" : "smoke" @particles[i].bitmap = loadBitmap(filename, @hue) end multiple = 1.7 xgrav = @xgravity * multiple / @slowdown xgrav = -xgrav if rand(2) == 1 ygrav = @ygravity * multiple / @slowdown ygrav = -ygrav if rand(2) == 1 @particlex[i] += xgrav @particley[i] += ygrav @particlex[i] -= @__offsetx @particley[i] -= @__offsety @particlex[i] = @particlex[i].floor @particley[i] = @particley[i].floor @particles[i].x = @particlex[i] + @startingx + @xoffset @particles[i].y = @particley[i] + @startingy + @yoffset end end class Particle_Engine::Flare < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 1, 30, 10, 1, -64, Graphics.height, -64, Graphics.width, 2, 2, -5, -12, 30, 0]) initParticles("particle", 255) end end class Particle_Engine::Splash < ParticleEffect_Event def initialize(event, viewport) super setParameters([0, 0, 1, 30, 255, 1, -64, Graphics.height, -64, Graphics.width, 4, 2, -5, -12, 30, 0]) initParticles("smoke", 50) end def update super @maxparticless.times do |i| @particles[i].opacity = 50 @particles[i].update end end end class Game_Event < Game_Character attr_accessor :pe_refresh alias nf_particles_game_map_initialize initialize unless method_defined?(:nf_particles_game_map_initialize) def initialize(map_id, event, map = nil) @pe_refresh = false begin nf_particles_game_map_initialize(map_id, event, map) rescue ArgumentError nf_particles_game_map_initialize(map_id, event) end end alias nf_particles_game_map_refresh refresh unless method_defined?(:nf_particles_game_map_refresh) def refresh nf_particles_game_map_refresh @pe_refresh = true end end