# Map Effects v1.4.1 for VX and VXace by Zeus81 # Άζ30 for commercial use # Licence : http://creativecommons.org/licenses/by-nc-nd/4.0/ # Contact : zeusex81@gmail.com # (fr) Manuel d'utilisation : https://www.dropbox.com/s/lb1d3q9jmx53taf/Map%20Effects%20Doc%20Fr.txt # (en) User Guide : https://www.dropbox.com/s/sk3uwq2bleoxr7s/Map%20Effects%20Doc%20En.txt # Demo : https://www.dropbox.com/s/2ex6906dyehl7an/Map%20Effects.zip $imported ||= {} $imported[:Zeus_Map_Effects] = __FILE__ def xp?() false end ; def vx?() false end ; def vxace?() false end RUBY_VERSION == '1.8.1' ? defined?(Hangup) ? def xp?() true end : def vx?() true end : def vxace?() true end class << Graphics def snap_elements_to_bitmap(*elements) if !@snap_elements_back or @snap_elements_back.disposed? @snap_elements_back = Sprite.new @snap_elements_back.bitmap = Bitmap.new(1, 1) @snap_elements_back.bitmap.set_pixel(0, 0, Color.new(0, 0, 0)) @snap_elements_back.z = 0x0FFF_FFFF end @snap_elements_back.zoom_x = width @snap_elements_back.zoom_y = height @snap_elements_back.visible = true elements.each {|element| element.z += 0x1FFF_FFFF} bmp = snap_to_bitmap rescue retry @snap_elements_back.visible = false elements.each {|element| element.z -= 0x1FFF_FFFF} return bmp end end module Math module_function def min(x, y) x < y ? x : y end def max(x, y) x < y ? y : x end def middle(min, x, max) x < max ? x < min ? min : x : max end end module Zeus module Animation def animate(variable, target_value, duration=0, ext=nil) @za_animations ||= {} base_value = Marshal.load(Marshal.dump(instance_variable_get(variable))) if duration < 1 update_animation_value(variable, base_value, target_value, 1, 1, ext) @za_animations.delete(variable) else @za_animations[variable] = [base_value, target_value, 0, duration.to_i, ext] end end def animating? @za_animations and !@za_animations.empty? end def clear_animations @za_animations and @za_animations.clear end def memorize_animations(variables = instance_variables) data = {} variables.each {|var| data[var.to_sym] = instance_variable_get(var)} data.delete(:@za_memorize) @za_memorize = Marshal.dump(data) end def restore_animations return unless @za_memorize Marshal.load(@za_memorize).each {|var,value| instance_variable_set(var,value)} end def update_animations return unless @za_animations @za_animations.delete_if do |variable, data| data[2] += 1 update_animation_value(variable, *data) data[2] == data[3] end end private def calculate_next_value(base_value, target_value, duration, duration_total) base_value + (target_value - base_value) * duration / duration_total end def update_animation_value(variable, base_value, target_value, duration, duration_total, ext) method_name = "update_animation_variable_#{variable.to_s[1..-1]}" method_name = "update_animation_#{base_value.class}" unless respond_to?(method_name) send(method_name, variable, base_value, target_value, duration, duration_total, ext) end def update_animation_Color(variable, base_value, target_value, duration, duration_total, ext) value = instance_variable_get(variable) value.red = calculate_next_value(base_value.red , target_value.red , duration, duration_total) value.green = calculate_next_value(base_value.green, target_value.green, duration, duration_total) value.blue = calculate_next_value(base_value.blue , target_value.blue , duration, duration_total) value.alpha = calculate_next_value(base_value.alpha, target_value.alpha, duration, duration_total) end def update_animation_Tone(variable, base_value, target_value, duration, duration_total, ext) value = instance_variable_get(variable) value.red = calculate_next_value(base_value.red , target_value.red , duration, duration_total) value.green = calculate_next_value(base_value.green, target_value.green, duration, duration_total) value.blue = calculate_next_value(base_value.blue , target_value.blue , duration, duration_total) value.gray = calculate_next_value(base_value.gray , target_value.gray , duration, duration_total) end def update_animation_Float(variable, base_value, target_value, duration, duration_total, ext) value = calculate_next_value(base_value, target_value, duration, duration_total) instance_variable_set(variable, value) end alias update_animation_Fixnum update_animation_Float alias update_animation_Bignum update_animation_Float end end class Game_Map_Effects include Zeus::Animation attr_accessor :active, :refresh_rate, :back, :x, :y, :ox, :oy, :angle, :zoom_x, :zoom_y, :mirror, :opacity, :blend_type, :color, :tone, :hue, :wave_amp, :wave_length, :wave_speed, :wave_phase, :pixelize, :blur_division, :blur_fade, :blur_animation, :gaussian_blur_length, :linear_blur_angle, :linear_blur_length, :radial_blur_angle, :zoom_blur_length, :motion_blur_rate def initialize @active = true @refresh_rate = 30.0 clear end def clear @back = false @x = @ox = Graphics.width / 2 @y = @oy = Graphics.height / 2 @zoom_x = 1.0 @zoom_y = 1.0 @zoom2 = Math.sqrt(100.0) @angle = 0.0 @wave_amp = 0.0 @wave_length = 180 @wave_speed = 360 @wave_phase = 0.0 @mirror = false @opacity = 255 @blend_type = 0 @color ||= Color.new(0, 0, 0, 0) @color.set(0, 0, 0, 0) @tone ||= Tone.new(0, 0, 0, 0) @tone.set(0, 0, 0, 0) @hue = 0 @pixelize = 1.0 @pixelize2 = Math.sqrt(100.0) @blur_division = 4.0 @blur_fade = 1.0 @blur_animation = 0.0 @gaussian_blur_length = 0.0 @linear_blur_angle = 0.0 @linear_blur_length = 0.0 @radial_blur_angle = 0.0 @zoom_blur_length = 0.0 @motion_blur_rate = 0.0 clear_animations end alias memorize memorize_animations alias restore restore_animations alias update update_animations def active? return false unless @active animating? or blur? or @mirror or @blend_type != 0 or @zoom_x != 1 or @zoom_y != 1 or @pixelize > 1 or @angle % 360 != 0 or @hue.to_i % 360 != 0 or @color.alpha != 0 or @tone.red != 0 or @tone.green != 0 or @tone.blue != 0 or @tone.gray != 0 or (@wave_amp * @zoom_x >= 1 and @wave_length * @zoom_y >= 1) end def blur? return false if @blur_division < 1 @gaussian_blur_length != 0 or @linear_blur_length != 0 or @radial_blur_angle != 0 or @zoom_blur_length != 0 or @motion_blur_rate != 0 end def refresh_bitmap? @refresh_rate > 0 and Graphics.frame_count % (Graphics.frame_rate / @refresh_rate.to_f) < 1 end def tilemap_wave_sync(tilemap_oy) return 0 if @wave_length == 0 tilemap_oy * @wave_speed / @wave_length.to_f end def blur_animation_offset return 0 if @blur_animation == 0 1 - @blur_animation * Graphics.frame_count / Graphics.frame_rate.to_f % 1 end def refresh_motion_blur? @blur_division >= 1 and @motion_blur_rate > 0 and Graphics.frame_count % @motion_blur_rate < 1 end def set_origin(x, y, duration=0) x = x * Graphics.width / 100 y = y * Graphics.height / 100 animate(:@x , x, duration) animate(:@y , y, duration) animate(:@ox, x, duration) animate(:@oy, y, duration) end def set_zoom(zoom, duration=0, center_on_player=true) zoom = Math.sqrt(Math.max(1, zoom)) animate(:@zoom2, zoom, duration, center_on_player) end def update_animation_variable_zoom2(variable, base_value, target_value, duration, duration_total, center_on_player) update_animation_Float(variable, base_value, target_value, duration, duration_total, nil) @zoom_y = @zoom_x = @zoom2 ** 2 / 100.0 display_ratio = Game_Map::DisplayRatio.to_f if center_on_player x = $game_player.real_x / display_ratio y = $game_player.real_y / display_ratio else x = $game_map.display_x / display_ratio + $game_map.screen_tile_x / 2 y = $game_map.display_y / display_ratio + $game_map.screen_tile_y / 2 end $game_player.center(x, y) end def set_angle(angle, duration=0) animate(:@angle, angle, duration) end def set_opacity(opacity, duration=0) opacity = opacity * 255 / 100 animate(:@opacity, opacity, duration) end def set_color(red, green, blue, alpha, duration=0) animate(:@color, Color.new(red, green, blue, alpha), duration) end def set_tone(red, green, blue, gray, duration=0) animate(:@tone, Tone.new(red, green, blue, gray), duration) end def set_hue(hue, duration=0) animate(:@hue, hue, duration) end def set_wave(amp, length, speed, duration=0) animate(:@wave_amp , amp , duration) animate(:@wave_length, length, duration) animate(:@wave_speed , speed , duration) end def set_pixelize(pixelize, duration=0) pixelize = Math.sqrt(Math.max(100, pixelize)) animate(:@pixelize2, pixelize, duration) end def update_animation_variable_pixelize2(variable, base_value, target_value, duration, duration_total, ext) update_animation_Float(variable, base_value, target_value, duration, duration_total, ext) @pixelize = @pixelize2 ** 2 / 100.0 end def setup_blur(division, fade, animation, duration=0) division = Math.middle(0, division, 16) animate(:@blur_division , division , duration) animate(:@blur_fade , fade , duration) animate(:@blur_animation, animation, duration) end def set_gaussian_blur(length, duration=0) animate(:@gaussian_blur_length, length, duration) end def set_linear_blur(angle, length, duration=0) animate(:@linear_blur_angle , angle , duration) animate(:@linear_blur_length, length, duration) end def set_radial_blur(angle, duration=0) animate(:@radial_blur_angle, angle, duration) end def set_zoom_blur(zoom, duration=0) length = Math.max(1, zoom) / 100.0 - 1 animate(:@zoom_blur_length, length, duration) end def set_motion_blur(rate, duration=0) animate(:@motion_blur_rate, rate, duration) end end class Spriteset_Map_Effects Blur_Offset = [[0.7,0.7], [-0.7,-0.7], [-0.7,0.7], [0.7,-0.7], [0,1], [0,-1], [1,0], [-1,0]] def initialize(*viewports) @map_viewports = viewports @viewport = Viewport.new(viewports[0].rect) @viewport.z = viewports[0].z @viewport.visible = false @effects_sprites = [] @effects_bitmaps = [] @data = $game_map.effects end def dispose(dispose_viewport=true) @effects_sprites.each {|sprite| sprite.dispose} @effects_sprites.clear @effects_bitmaps.each {|bitmap| bitmap.dispose if bitmap} @effects_bitmaps.clear @pixelize_bitmap.dispose if @pixelize_bitmap @pixelize_bitmap = nil @back_sprite.dispose if @back_sprite @back_sprite = nil if dispose_viewport @viewport.dispose else @viewport.visible = false @map_viewports.each {|viewport| viewport.visible = true} end end def update(tilemap_oy = 0) unless @data.active? dispose(false) if @viewport.visible return end @viewport.visible = true @motion_blur_refresh ||= @data.refresh_motion_blur? refresh_sprites if !@effects_bitmaps[0] or @data.refresh_bitmap? refresh_bitmaps refresh_pixelize end refresh_back wave_sync = @data.tilemap_wave_sync(tilemap_oy) blur_offset = @data.blur_animation_offset @effects_sprites.each_with_index do |sprite, id| update_effects(sprite, id, wave_sync) update_pixelize(sprite) if @pixelize_bitmap update_blur(sprite, id, blur_offset) if id > 0 end @data.wave_phase = @effects_sprites[0].wave_phase - wave_sync end def refresh_sprites n = (@data.blur? ? @data.blur_division.to_i+1 : 1) - @effects_sprites.size n.times {@effects_sprites << Sprite.new(@viewport)} (-n).times {@effects_sprites.pop.dispose} end def refresh_bitmaps n = (@data.motion_blur_rate == 0 ? 1 : @effects_sprites.size) - @effects_bitmaps.size n.times {@effects_bitmaps << nil} (-n).times {bmp = @effects_bitmaps.pop and bmp.dispose} @map_viewports.each {|viewport| viewport.visible = true} @effects_bitmaps.unshift(@effects_bitmaps.pop) if @motion_blur_refresh @effects_bitmaps[0].dispose if @effects_bitmaps[0] @effects_bitmaps[0] = Graphics.snap_elements_to_bitmap(*@map_viewports) @effects_bitmaps[0].hue_change(@data.hue % 360) if @data.hue.to_i % 360 != 0 @map_viewports.each {|viewport| viewport.visible = false} @motion_blur_refresh = false end def refresh_pixelize if @data.pixelize > 1 bmp = @effects_bitmaps[0] @pixelize_rect ||= Rect.new(0, 0, 0, 0) @pixelize_rect.width = Math.max(1, bmp.width / @data.pixelize) @pixelize_rect.height = Math.max(1, bmp.height / @data.pixelize) @pixelize_bitmap ||= Bitmap.new(bmp.width, bmp.height) @pixelize_bitmap.clear @pixelize_bitmap.stretch_blt(@pixelize_rect, bmp, bmp.rect) elsif @pixelize_bitmap @pixelize_bitmap.dispose @pixelize_bitmap = nil end end def refresh_back if @data.back @back_sprite ||= Sprite.new(@viewport) @back_sprite.bitmap = @effects_bitmaps[0] elsif @back_sprite @back_sprite.dispose @back_sprite = nil end end def update_effects(sprite, id, wave_sync) sprite.bitmap = @effects_bitmaps[id] || @effects_bitmaps[0] sprite.x = @data.x sprite.y = @data.y sprite.z = id + 1 sprite.ox = @data.ox sprite.oy = @data.oy sprite.zoom_x = @data.zoom_x sprite.zoom_y = @data.zoom_y sprite.angle = @data.angle % 360 sprite.wave_amp = @data.wave_amp * @data.zoom_x sprite.wave_length = @data.wave_length * @data.zoom_y sprite.wave_speed = @data.wave_speed * @data.zoom_y sprite.wave_phase = @data.wave_phase + wave_sync sprite.mirror = @data.mirror sprite.opacity = @data.opacity sprite.blend_type = @data.blend_type sprite.color = @data.color sprite.tone = @data.tone sprite.update end def update_pixelize(sprite) pzx = @pixelize_bitmap.width / @pixelize_rect.width.to_f pzy = @pixelize_bitmap.height / @pixelize_rect.height.to_f sprite.bitmap = @pixelize_bitmap sprite.src_rect = @pixelize_rect sprite.x -= sprite.ox - (sprite.ox /= pzx).to_i * pzx sprite.y -= sprite.oy - (sprite.oy /= pzy).to_i * pzy sprite.zoom_x *= pzx sprite.zoom_y *= pzy end def update_blur(sprite, id, blur_offset) update_blur_opacity(sprite, id-blur_offset) update_gaussian_blur(sprite, id) if @data.gaussian_blur_length != 0 update_linear_blur(sprite, id-blur_offset) if @data.linear_blur_length != 0 update_radial_blur(sprite, id-blur_offset) if @data.radial_blur_angle != 0 update_zoom_blur(sprite, id-blur_offset) if @data.zoom_blur_length != 0 end def update_blur_opacity(sprite, id) sprite.opacity /= (id < 1 ? 2 : id+1) ** (1 + @data.blur_fade / (@data.blur_division*20.0)) end def update_gaussian_blur(sprite, id) box, boy = *Blur_Offset[(id-1)%8] offset = ((id+3)/4) / ((@data.blur_division.to_i+3)/4).to_f * @data.gaussian_blur_length sprite.x += (offset.ceil * box).round sprite.y += (offset.ceil * boy).round end def update_linear_blur(sprite, id) radian = @data.linear_blur_angle * Math::PI / 180 offset = id * @data.linear_blur_length / @data.blur_division.to_f sprite.x += offset * Math.cos( radian) sprite.y += offset * Math.sin(-radian) end def update_zoom_blur(sprite, id) zoom = 1 + id * @data.zoom_blur_length / @data.blur_division.to_f sprite.zoom_x *= zoom sprite.zoom_y *= zoom end def update_radial_blur(sprite, id) sprite.angle += id * @data.radial_blur_angle / @data.blur_division.to_f sprite.angle %= 360 end end class Game_Map if vx? def screen_tile_x() Graphics.width / 32 end def screen_tile_y() Graphics.height / 32 end DisplayRatio = 256 else DisplayRatio = 1 end def zoom_ox return 0 unless effects.active and effects.zoom_x > 1 (1 - 1 / effects.zoom_x) * screen_tile_x / 2 end def zoom_oy return 0 unless effects.active and effects.zoom_y > 1 (1 - 1 / effects.zoom_y) * screen_tile_y / 2 end def limit_x(x) ox = zoom_ox min = DisplayRatio * -ox max = DisplayRatio * (width - screen_tile_x + ox) x < max ? x < min ? min : x : max end def limit_y(y) oy = zoom_oy min = DisplayRatio * -oy max = DisplayRatio * (height - screen_tile_y + oy) y < max ? y < min ? min : y : max end def set_display_x(x) x = loop_horizontal? ? x % (width * DisplayRatio) : limit_x(x) @parallax_x += x - @display_x if @parallax_loop_x or !loop_horizontal? @display_x = x end def set_display_y(y) y = loop_vertical? ? y % (height * DisplayRatio) : limit_y(y) @parallax_y += y - @display_y if @parallax_loop_y or !loop_vertical? @display_y = y end def set_display_pos(x, y) set_display_x(x); set_display_y(y) end def scroll_down(distance) set_display_y(@display_y + distance) end def scroll_left(distance) set_display_x(@display_x - distance) end def scroll_right(distance) set_display_x(@display_x + distance) end def scroll_up(distance) set_display_y(@display_y - distance) end def effects() @effects ||= Game_Map_Effects.new end alias zeus_map_effects_update update def update(*args) zeus_map_effects_update(*args) effects.update end end class Game_Interpreter def map_effects $game_map.effects end end class Game_Player def center(x, y) $game_map.set_display_pos(x*256-CENTER_X, y*256-CENTER_Y) end end if vx? class Spriteset_Map alias zeus_map_effects_update update def update zeus_map_effects_update @map_effects ||= Spriteset_Map_Effects.new(@viewport1) @map_effects.update(@tilemap.oy) end alias zeus_map_effects_dispose dispose def dispose zeus_map_effects_dispose @map_effects.dispose end end $imported[:Zeus_Weather_Viewport] ||= __FILE__ if $imported[:Zeus_Weather_Viewport] == __FILE__ class Spriteset_Map alias zeus_weather_viewport_create_weather create_weather def create_weather zeus_weather_viewport_create_weather @weather.weather_viewport = @viewport1 end end class Spriteset_Weather if vx? def weather_viewport=(viewport) for sprite in @sprites sprite.viewport = viewport sprite.z = 0x8000 end end else attr_accessor :weather_viewport alias zeus_weather_viewport_add_sprite add_sprite def add_sprite zeus_weather_viewport_add_sprite @sprites[-1].viewport = @weather_viewport @sprites[-1].z = 0x8000 end end end end