|
|
|
|
@@ -7,21 +7,24 @@ module RPG
|
|
|
|
|
attr_reader :max
|
|
|
|
|
attr_reader :ox
|
|
|
|
|
attr_reader :oy
|
|
|
|
|
MAX_SPRITES = 60
|
|
|
|
|
MAX_SPRITES = 60
|
|
|
|
|
FADE_OLD_TILES_START = 0
|
|
|
|
|
FADE_OLD_TILES_END = 1
|
|
|
|
|
FADE_OLD_TONE_START = 0
|
|
|
|
|
FADE_OLD_TONE_END = 2
|
|
|
|
|
FADE_OLD_PARTICLES_START = 1
|
|
|
|
|
FADE_OLD_PARTICLES_END = 3
|
|
|
|
|
FADE_NEW_PARTICLES_START = 2
|
|
|
|
|
FADE_NEW_PARTICLES_END = 4
|
|
|
|
|
FADE_NEW_TONE_START = 3 # Shouldn't be sooner than FADE_OLD_TONE_END + 1
|
|
|
|
|
FADE_NEW_TONE_END = 5
|
|
|
|
|
FADE_NEW_TILES_START = 4 # Shouldn't be sooner than FADE_OLD_TILES_END
|
|
|
|
|
FADE_NEW_TILES_END = 5
|
|
|
|
|
|
|
|
|
|
def initialize(viewport = nil)
|
|
|
|
|
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
|
|
|
|
@viewport.z = viewport.z + 1
|
|
|
|
|
@origViewport = viewport
|
|
|
|
|
@type = 0
|
|
|
|
|
@max = 0
|
|
|
|
|
@ox = 0
|
|
|
|
|
@oy = 0
|
|
|
|
|
@tiles_wide = 0
|
|
|
|
|
@tiles_tall = 0
|
|
|
|
|
@sun = 0
|
|
|
|
|
@sunValue = 0
|
|
|
|
|
@time_until_flash = 0
|
|
|
|
|
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
|
|
|
|
@viewport.z = viewport.z + 1
|
|
|
|
|
@origViewport = viewport
|
|
|
|
|
# [array of particle bitmaps, array of tile bitmaps,
|
|
|
|
|
# +x per second (particle), +y per second (particle), +opacity per second (particle),
|
|
|
|
|
# +x per second (tile), +y per second (tile)]
|
|
|
|
|
@@ -31,16 +34,32 @@ module RPG
|
|
|
|
|
@weatherTypes[PBFieldWeather::HeavyRain] = [[], nil, -4800, 4800, 0]
|
|
|
|
|
@weatherTypes[PBFieldWeather::Storm] = [[], nil, -4800, 4800, 0]
|
|
|
|
|
@weatherTypes[PBFieldWeather::Snow] = [[], nil, -240, 240, 0]
|
|
|
|
|
@weatherTypes[PBFieldWeather::Blizzard] = [[], [], -960, 64, 0, -1440, 720]
|
|
|
|
|
@weatherTypes[PBFieldWeather::Blizzard] = [[], [], -960, 256, 0, -1440, 720]
|
|
|
|
|
@weatherTypes[PBFieldWeather::Sandstorm] = [[], [], -1200, 640, 0, -720, 360]
|
|
|
|
|
@weatherTypes[PBFieldWeather::Sun] = nil
|
|
|
|
|
@sprites = []
|
|
|
|
|
@sprite_lifetimes = []
|
|
|
|
|
@tiles = []
|
|
|
|
|
@weatherTypes[PBFieldWeather::Fog] = [[], [], 0, 0, 0, -32, 0]
|
|
|
|
|
@type = 0
|
|
|
|
|
@max = 0
|
|
|
|
|
@ox = 0
|
|
|
|
|
@oy = 0
|
|
|
|
|
@tiles_wide = 0
|
|
|
|
|
@tiles_tall = 0
|
|
|
|
|
@tile_x = 0.0
|
|
|
|
|
@tile_y = 0.0
|
|
|
|
|
@sun_magnitude = 0 # +/- maximum addition to sun tone
|
|
|
|
|
@sun_strength = 0 # Current addition to sun tone (0 to @sun_magnitude)
|
|
|
|
|
@time_until_flash = 0
|
|
|
|
|
@sprites = []
|
|
|
|
|
@sprite_lifetimes = []
|
|
|
|
|
@tiles = []
|
|
|
|
|
@new_sprites = []
|
|
|
|
|
@new_sprite_lifetimes = []
|
|
|
|
|
@fading = false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def dispose
|
|
|
|
|
@sprites.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@new_sprites.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@tiles.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@viewport.dispose
|
|
|
|
|
@weatherTypes.each do |weather|
|
|
|
|
|
@@ -50,23 +69,45 @@ module RPG
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def fade_in(new_type, new_max, duration = 1)
|
|
|
|
|
return if @fading
|
|
|
|
|
new_max = 0 if new_type == PBFieldWeather::None
|
|
|
|
|
return if @type == new_type && @max == new_max
|
|
|
|
|
if duration > 0
|
|
|
|
|
@target_type = new_type
|
|
|
|
|
@target_max = new_max
|
|
|
|
|
prepare_bitmaps(@target_type)
|
|
|
|
|
@old_max = @max
|
|
|
|
|
@new_max = 0 # Current number of new particles
|
|
|
|
|
@old_tone = Tone.new(@viewport.tone.red, @viewport.tone.green,
|
|
|
|
|
@viewport.tone.blue, @viewport.tone.gray)
|
|
|
|
|
@target_tone = get_weather_tone(@target_type, @target_max)
|
|
|
|
|
@fade_time = 0.0
|
|
|
|
|
@time_shift = 0
|
|
|
|
|
if @type == PBFieldWeather::None
|
|
|
|
|
@time_shift += 2 # No previous weather to fade out first
|
|
|
|
|
elsif !@weatherTypes[@type] || !@weatherTypes[@type][1] || @weatherTypes[@type][1].length == 0
|
|
|
|
|
@time_shift += 1 # No previous tiles to fade out first
|
|
|
|
|
end
|
|
|
|
|
@fading = true
|
|
|
|
|
@new_sprites.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@new_sprites.clear
|
|
|
|
|
ensureSprites
|
|
|
|
|
@new_sprites.each_with_index { |sprite, i| set_sprite_bitmap(sprite, i, @target_type) }
|
|
|
|
|
else
|
|
|
|
|
self.type = new_type
|
|
|
|
|
self.max = new_max
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def type=(type)
|
|
|
|
|
return if @type == type
|
|
|
|
|
@type = type
|
|
|
|
|
case @type
|
|
|
|
|
when PBFieldWeather::None
|
|
|
|
|
@sprites.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@sprites.clear
|
|
|
|
|
@tiles.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@tiles.clear
|
|
|
|
|
@tiles_wide = @tiles_tall = 0
|
|
|
|
|
return
|
|
|
|
|
when PBFieldWeather::Rain then prepareRainBitmap
|
|
|
|
|
when PBFieldWeather::HeavyRain, PBFieldWeather::Storm then prepareStormBitmap
|
|
|
|
|
when PBFieldWeather::Snow then prepareSnowBitmaps
|
|
|
|
|
when PBFieldWeather::Blizzard then prepareBlizzardBitmaps
|
|
|
|
|
when PBFieldWeather::Sandstorm then prepareSandstormBitmaps
|
|
|
|
|
if @fading
|
|
|
|
|
@max = @target_max
|
|
|
|
|
@fading = false
|
|
|
|
|
end
|
|
|
|
|
@type = type
|
|
|
|
|
prepare_bitmaps(@type)
|
|
|
|
|
if @weatherTypes[@type] && @weatherTypes[@type][1] && @weatherTypes[@type][1].length > 0
|
|
|
|
|
w = @weatherTypes[@type][1][0].width
|
|
|
|
|
h = @weatherTypes[@type][1][0].height
|
|
|
|
|
@@ -76,51 +117,17 @@ module RPG
|
|
|
|
|
@tiles_wide = @tiles_tall = 0
|
|
|
|
|
end
|
|
|
|
|
ensureSprites
|
|
|
|
|
@sprites.each_with_index { |sprite, i| set_sprite_bitmap(sprite, i) }
|
|
|
|
|
@tiles.each_with_index { |sprite, i| set_tile_bitmap(sprite, i) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def set_sprite_bitmap(sprite, index)
|
|
|
|
|
return if !sprite
|
|
|
|
|
weatherBitmaps = (@weatherTypes[@type]) ? @weatherTypes[@type][0] : nil
|
|
|
|
|
if !weatherBitmaps
|
|
|
|
|
sprite.bitmap = nil
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
case @type
|
|
|
|
|
when PBFieldWeather::Rain, PBFieldWeather::HeavyRain, PBFieldWeather::Storm
|
|
|
|
|
last_index = weatherBitmaps.length - 1 # Last sprite is splash
|
|
|
|
|
if index % 2 == 0
|
|
|
|
|
sprite.bitmap = weatherBitmaps[index % last_index]
|
|
|
|
|
else
|
|
|
|
|
sprite.bitmap = weatherBitmaps[last_index]
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
sprite.bitmap = weatherBitmaps[index % weatherBitmaps.length]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def set_tile_bitmap(sprite, index)
|
|
|
|
|
return if !sprite
|
|
|
|
|
weatherBitmaps = (@weatherTypes[@type]) ? @weatherTypes[@type][1] : nil
|
|
|
|
|
if !weatherBitmaps || weatherBitmaps.length == 0
|
|
|
|
|
sprite.bitmap = nil
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
sprite.bitmap = weatherBitmaps[index % weatherBitmaps.length]
|
|
|
|
|
reset_tile_position(sprite, index)
|
|
|
|
|
@sprites.each_with_index { |sprite, i| set_sprite_bitmap(sprite, i, @type) }
|
|
|
|
|
ensureTiles
|
|
|
|
|
@tiles.each_with_index { |sprite, i| set_tile_bitmap(sprite, i, @type) }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def max=(value)
|
|
|
|
|
return if @max == value
|
|
|
|
|
@max = value.clamp(0, MAX_SPRITES)
|
|
|
|
|
if @max == 0
|
|
|
|
|
@sprites.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@sprites.clear
|
|
|
|
|
@tiles.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@tiles.clear
|
|
|
|
|
else
|
|
|
|
|
@sprites.each_with_index { |sprite, i| sprite.visible = (i <= @max) if sprite }
|
|
|
|
|
ensureSprites
|
|
|
|
|
for i in 0...MAX_SPRITES
|
|
|
|
|
@sprites[i].visible = (i < @max) if @sprites[i]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
@@ -128,6 +135,7 @@ module RPG
|
|
|
|
|
return if value == @ox
|
|
|
|
|
@ox = value
|
|
|
|
|
@sprites.each { |sprite| sprite.ox = @ox if sprite }
|
|
|
|
|
@new_sprites.each { |sprite| sprite.ox = @ox if sprite }
|
|
|
|
|
@tiles.each { |sprite| sprite.ox = @ox if sprite }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
@@ -135,10 +143,42 @@ module RPG
|
|
|
|
|
return if value == @oy
|
|
|
|
|
@oy = value
|
|
|
|
|
@sprites.each { |sprite| sprite.oy = @oy if sprite }
|
|
|
|
|
@new_sprites.each { |sprite| sprite.oy = @oy if sprite }
|
|
|
|
|
@tiles.each { |sprite| sprite.oy = @oy if sprite }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def prepareRainBitmap
|
|
|
|
|
def get_weather_tone(weather_type, maximum)
|
|
|
|
|
case weather_type
|
|
|
|
|
when PBFieldWeather::Rain
|
|
|
|
|
return Tone.new(-maximum * 3 / 4, -maximum * 3 / 4, -maximum * 3 / 4, 10)
|
|
|
|
|
when PBFieldWeather::HeavyRain
|
|
|
|
|
return Tone.new(-maximum * 6 / 4, -maximum * 6 / 4, -maximum * 6 / 4, 20)
|
|
|
|
|
when PBFieldWeather::Storm
|
|
|
|
|
return Tone.new(-maximum * 6 / 4, -maximum * 6 / 4, -maximum * 6 / 4, 20)
|
|
|
|
|
when PBFieldWeather::Snow
|
|
|
|
|
return Tone.new( maximum / 2, maximum / 2, maximum / 2, 0)
|
|
|
|
|
when PBFieldWeather::Blizzard
|
|
|
|
|
return Tone.new( maximum * 3 / 4, maximum * 3 / 4, maximum * 3 / 4, 0)
|
|
|
|
|
when PBFieldWeather::Sandstorm
|
|
|
|
|
return Tone.new( maximum / 2, 0, -maximum / 2, 0)
|
|
|
|
|
when PBFieldWeather::Sun
|
|
|
|
|
return Tone.new(64, 64, 32, 0)
|
|
|
|
|
end
|
|
|
|
|
return Tone.new(0, 0, 0, 0)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def prepare_bitmaps(new_type)
|
|
|
|
|
case new_type
|
|
|
|
|
when PBFieldWeather::Rain then prepareRainBitmaps
|
|
|
|
|
when PBFieldWeather::HeavyRain, PBFieldWeather::Storm then prepareStormBitmaps
|
|
|
|
|
when PBFieldWeather::Snow then prepareSnowBitmaps
|
|
|
|
|
when PBFieldWeather::Blizzard then prepareBlizzardBitmaps
|
|
|
|
|
when PBFieldWeather::Sandstorm then prepareSandstormBitmaps
|
|
|
|
|
when PBFieldWeather::Fog then prepareFogBitmaps
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def prepareRainBitmaps
|
|
|
|
|
rain1 = RPG::Cache.load_bitmap("Graphics/Weather/", "rain_1")
|
|
|
|
|
rain2 = RPG::Cache.load_bitmap("Graphics/Weather/", "rain_2")
|
|
|
|
|
rain3 = RPG::Cache.load_bitmap("Graphics/Weather/", "rain_3")
|
|
|
|
|
@@ -146,7 +186,7 @@ module RPG
|
|
|
|
|
@weatherTypes[PBFieldWeather::Rain][0] = [rain1, rain2, rain3, rain4]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def prepareStormBitmap
|
|
|
|
|
def prepareStormBitmaps
|
|
|
|
|
storm1 = RPG::Cache.load_bitmap("Graphics/Weather/", "storm_1")
|
|
|
|
|
storm2 = RPG::Cache.load_bitmap("Graphics/Weather/", "storm_2")
|
|
|
|
|
storm3 = RPG::Cache.load_bitmap("Graphics/Weather/", "storm_3")
|
|
|
|
|
@@ -182,8 +222,14 @@ module RPG
|
|
|
|
|
@weatherTypes[PBFieldWeather::Sandstorm][1] = [sandstorm_tile]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def prepareFogBitmaps
|
|
|
|
|
fog_tile = RPG::Cache.load_bitmap("Graphics/Weather/", "fog_tile")
|
|
|
|
|
@weatherTypes[PBFieldWeather::Fog][1] = [fog_tile]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def ensureSprites
|
|
|
|
|
if @sprites.length < MAX_SPRITES
|
|
|
|
|
if @sprites.length < MAX_SPRITES && @weatherTypes[@type] &&
|
|
|
|
|
@weatherTypes[@type][0] && @weatherTypes[@type][0].length > 0
|
|
|
|
|
for i in 0...MAX_SPRITES
|
|
|
|
|
if !@sprites[i]
|
|
|
|
|
sprite = Sprite.new(@origViewport)
|
|
|
|
|
@@ -193,138 +239,354 @@ module RPG
|
|
|
|
|
sprite.opacity = 0
|
|
|
|
|
@sprites[i] = sprite
|
|
|
|
|
end
|
|
|
|
|
@sprites[i].visible = (i <= @max)
|
|
|
|
|
@sprites[i].visible = (i < @max)
|
|
|
|
|
@sprite_lifetimes[i] = 0
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if @tiles.length < @tiles_wide * @tiles_tall
|
|
|
|
|
for i in 0...(@tiles_wide * @tiles_tall)
|
|
|
|
|
if !@tiles[i]
|
|
|
|
|
if @fading && @new_sprites.length < MAX_SPRITES && @weatherTypes[@target_type] &&
|
|
|
|
|
@weatherTypes[@target_type][0] && @weatherTypes[@target_type][0].length > 0
|
|
|
|
|
for i in 0...MAX_SPRITES
|
|
|
|
|
if !@new_sprites[i]
|
|
|
|
|
sprite = Sprite.new(@origViewport)
|
|
|
|
|
sprite.z = 1000
|
|
|
|
|
sprite.ox = @ox
|
|
|
|
|
sprite.oy = @oy
|
|
|
|
|
sprite.opacity = 0
|
|
|
|
|
@tiles[i] = sprite
|
|
|
|
|
@new_sprites[i] = sprite
|
|
|
|
|
end
|
|
|
|
|
@tiles[i].visible = true
|
|
|
|
|
@new_sprites[i].visible = (i < @new_max)
|
|
|
|
|
@new_sprite_lifetimes[i] = 0
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def reset_sprite_position(sprite, index)
|
|
|
|
|
if [PBFieldWeather::Rain, PBFieldWeather::HeavyRain, PBFieldWeather::Storm].include?(@type) && index % 2 != 0 # Splash
|
|
|
|
|
def ensureTiles
|
|
|
|
|
return if @tiles.length >= @tiles_wide * @tiles_tall
|
|
|
|
|
for i in 0...(@tiles_wide * @tiles_tall)
|
|
|
|
|
if !@tiles[i]
|
|
|
|
|
sprite = Sprite.new(@origViewport)
|
|
|
|
|
sprite.z = 1000
|
|
|
|
|
sprite.ox = @ox
|
|
|
|
|
sprite.oy = @oy
|
|
|
|
|
sprite.opacity = 0
|
|
|
|
|
@tiles[i] = sprite
|
|
|
|
|
end
|
|
|
|
|
@tiles[i].visible = true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def set_sprite_bitmap(sprite, index, weather_type)
|
|
|
|
|
return if !sprite
|
|
|
|
|
weatherBitmaps = (@weatherTypes[weather_type]) ? @weatherTypes[weather_type][0] : nil
|
|
|
|
|
if !weatherBitmaps || weatherBitmaps.length == 0
|
|
|
|
|
sprite.bitmap = nil
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
case weather_type
|
|
|
|
|
when PBFieldWeather::Rain, PBFieldWeather::HeavyRain, PBFieldWeather::Storm
|
|
|
|
|
last_index = weatherBitmaps.length - 1 # Last sprite is splash
|
|
|
|
|
if (index % 2) == 0
|
|
|
|
|
sprite.bitmap = weatherBitmaps[index % last_index]
|
|
|
|
|
else
|
|
|
|
|
sprite.bitmap = weatherBitmaps[last_index]
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
sprite.bitmap = weatherBitmaps[index % weatherBitmaps.length]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def set_tile_bitmap(sprite, index, weather_type)
|
|
|
|
|
return if !sprite || !weather_type
|
|
|
|
|
weatherBitmaps = (@weatherTypes[weather_type]) ? @weatherTypes[weather_type][1] : nil
|
|
|
|
|
if weatherBitmaps && weatherBitmaps.length > 0
|
|
|
|
|
sprite.bitmap = weatherBitmaps[index % weatherBitmaps.length]
|
|
|
|
|
else
|
|
|
|
|
sprite.bitmap = nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def reset_sprite_position(sprite, index, is_new_sprite = false)
|
|
|
|
|
weather_type = (is_new_sprite) ? @target_type : @type
|
|
|
|
|
lifetimes = (is_new_sprite) ? @new_sprite_lifetimes : @sprite_lifetimes
|
|
|
|
|
if index < (is_new_sprite ? @new_max : @max)
|
|
|
|
|
sprite.visible = true
|
|
|
|
|
else
|
|
|
|
|
sprite.visible = false
|
|
|
|
|
lifetimes[index] = 0
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
if [PBFieldWeather::Rain, PBFieldWeather::HeavyRain,
|
|
|
|
|
PBFieldWeather::Storm].include?(weather_type) && (index % 2) != 0 # Splash
|
|
|
|
|
sprite.x = @ox - sprite.bitmap.width + rand(Graphics.width + sprite.bitmap.width * 2)
|
|
|
|
|
sprite.y = @oy - sprite.bitmap.height + rand(Graphics.height + sprite.bitmap.height * 2)
|
|
|
|
|
@sprite_lifetimes[index] = (30 + rand(20)) * 10_000 # 0.3-0.5 seconds
|
|
|
|
|
lifetimes[index] = (30 + rand(20)) * 0.01 # 0.3-0.5 seconds
|
|
|
|
|
else
|
|
|
|
|
gradient = @weatherTypes[@type][2].to_f / @weatherTypes[@type][3]
|
|
|
|
|
sprite.x = @ox - sprite.bitmap.width + rand(Graphics.width + sprite.bitmap.width * 2 - gradient * Graphics.height)
|
|
|
|
|
sprite.y = @oy - sprite.bitmap.height - rand(Graphics.height)
|
|
|
|
|
@sprite_lifetimes[index] = 1_000_000 * (@oy - sprite.y + rand(Graphics.height * 8 / 5)) / @weatherTypes[@type][3]
|
|
|
|
|
gradient = @weatherTypes[weather_type][2].to_f / @weatherTypes[weather_type][3]
|
|
|
|
|
if gradient.abs >= 1
|
|
|
|
|
# Position sprite to the right of the screen
|
|
|
|
|
sprite.x = @ox + Graphics.width + rand(Graphics.width)
|
|
|
|
|
sprite.y = @oy + Graphics.height - rand(Graphics.height + sprite.bitmap.height - Graphics.width / gradient)
|
|
|
|
|
distance_to_cover = sprite.x - @ox - Graphics.width / 2 + sprite.bitmap.width + rand(Graphics.width * 8 / 5)
|
|
|
|
|
lifetimes[index] = (distance_to_cover.to_f / @weatherTypes[weather_type][2]).abs
|
|
|
|
|
else
|
|
|
|
|
# Position sprite to the top of the screen
|
|
|
|
|
sprite.x = @ox - sprite.bitmap.width + rand(Graphics.width + sprite.bitmap.width - gradient * Graphics.height)
|
|
|
|
|
sprite.y = @oy - sprite.bitmap.height - rand(Graphics.height)
|
|
|
|
|
distance_to_cover = @oy - sprite.y + Graphics.height / 2 + rand(Graphics.height * 8 / 5)
|
|
|
|
|
lifetimes[index] = (distance_to_cover.to_f / @weatherTypes[weather_type][3]).abs
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
sprite.opacity = 255
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def update_sprite_position(sprite, index)
|
|
|
|
|
return if !sprite
|
|
|
|
|
delta_t = Graphics.delta
|
|
|
|
|
if @sprite_lifetimes[index] > 0
|
|
|
|
|
@sprite_lifetimes[index] -= delta_t
|
|
|
|
|
if @sprite_lifetimes[index] <= 0
|
|
|
|
|
reset_sprite_position(sprite, index)
|
|
|
|
|
def update_sprite_position(sprite, index, is_new_sprite = false)
|
|
|
|
|
return if !sprite || !sprite.bitmap || !sprite.visible
|
|
|
|
|
delta_t = Graphics.delta_s
|
|
|
|
|
lifetimes = (is_new_sprite) ? @new_sprite_lifetimes : @sprite_lifetimes
|
|
|
|
|
if lifetimes[index] >= 0
|
|
|
|
|
lifetimes[index] -= delta_t
|
|
|
|
|
if lifetimes[index] <= 0
|
|
|
|
|
reset_sprite_position(sprite, index, is_new_sprite)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if [PBFieldWeather::Rain, PBFieldWeather::HeavyRain, PBFieldWeather::Storm].include?(@type) && index % 2 != 0 # Splash
|
|
|
|
|
sprite.visible = (@sprite_lifetimes[index] < 200_000) # 0.2 seconds
|
|
|
|
|
# Determine which weather type this sprite is representing
|
|
|
|
|
weather_type = (is_new_sprite) ? @target_type : @type
|
|
|
|
|
# Update visibility/position/opacity of sprite
|
|
|
|
|
if [PBFieldWeather::Rain, PBFieldWeather::HeavyRain,
|
|
|
|
|
PBFieldWeather::Storm].include?(weather_type) && (index % 2) != 0 # Splash
|
|
|
|
|
sprite.opacity = (lifetimes[index] < 0.2) ? 255 : 0 # 0.2 seconds
|
|
|
|
|
else
|
|
|
|
|
sprite.x += @weatherTypes[@type][2] * delta_t / 1_000_000
|
|
|
|
|
sprite.y += @weatherTypes[@type][3] * delta_t / 1_000_000
|
|
|
|
|
if @type == PBFieldWeather::Snow || @type == PBFieldWeather::Blizzard
|
|
|
|
|
sprite.x -= (4 * (sprite.y - @oy)) / Graphics.height
|
|
|
|
|
sprite.x -= [2, 1, 0, -1][rand(4)]
|
|
|
|
|
sprite.y += index % 6
|
|
|
|
|
dist_x = @weatherTypes[weather_type][2] * delta_t
|
|
|
|
|
dist_y = @weatherTypes[weather_type][3] * delta_t
|
|
|
|
|
sprite.x += dist_x
|
|
|
|
|
sprite.y += dist_y
|
|
|
|
|
if weather_type == PBFieldWeather::Snow
|
|
|
|
|
sprite.x += dist_x * (sprite.y - @oy) / (Graphics.height * 3) # Faster when further down screen
|
|
|
|
|
sprite.x += [2, 1, 0, -1][rand(4)] * dist_x / 8 # Random movement
|
|
|
|
|
sprite.y += [2, 1, 1, 0, 0, -1][index % 6] * dist_y / 10 # Variety
|
|
|
|
|
end
|
|
|
|
|
sprite.opacity += @weatherTypes[weather_type][4] * delta_t
|
|
|
|
|
x = sprite.x - @ox
|
|
|
|
|
y = sprite.y - @oy
|
|
|
|
|
# Check if sprite is off-screen; if so, reset it
|
|
|
|
|
if sprite.opacity < 64 || x < -sprite.bitmap.width || y > Graphics.height
|
|
|
|
|
reset_sprite_position(sprite, index, is_new_sprite)
|
|
|
|
|
end
|
|
|
|
|
sprite.opacity += @weatherTypes[@type][4] * delta_t / 1_000_000
|
|
|
|
|
end
|
|
|
|
|
x = sprite.x - @ox
|
|
|
|
|
y = sprite.y - @oy
|
|
|
|
|
# Check if sprite is off-screen; if so, reset it
|
|
|
|
|
if sprite.opacity < 64 || x < -sprite.bitmap.width || y > Graphics.height
|
|
|
|
|
reset_sprite_position(sprite, index)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def reset_tile_position(sprite, index)
|
|
|
|
|
sprite.x = @ox + (index % @tiles_wide) * sprite.bitmap.width
|
|
|
|
|
sprite.y = @oy + (index / @tiles_wide) * sprite.bitmap.height
|
|
|
|
|
def recalculate_tile_positions
|
|
|
|
|
delta_t = Graphics.delta_s
|
|
|
|
|
weather_type = @type
|
|
|
|
|
if @fading && @fade_time >= [FADE_OLD_TONE_END - @time_shift, 0].max
|
|
|
|
|
weather_type = @target_type
|
|
|
|
|
end
|
|
|
|
|
@tile_x += @weatherTypes[weather_type][5] * delta_t
|
|
|
|
|
@tile_y += @weatherTypes[weather_type][6] * delta_t
|
|
|
|
|
if @tile_x < -@tiles_wide * @weatherTypes[weather_type][1][0].width
|
|
|
|
|
@tile_x += @tiles_wide * @weatherTypes[weather_type][1][0].width
|
|
|
|
|
end
|
|
|
|
|
if @tile_y > @tiles_tall * @weatherTypes[weather_type][1][0].height
|
|
|
|
|
@tile_y -= @tiles_tall * @weatherTypes[weather_type][1][0].height
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def update_tile_position(sprite, index)
|
|
|
|
|
return if !sprite || !sprite.bitmap
|
|
|
|
|
delta_t = Graphics.delta
|
|
|
|
|
if @tiles_wide > 0 && @tiles_tall > 0
|
|
|
|
|
sprite.x += @weatherTypes[@type][5] * delta_t / 1_000_000
|
|
|
|
|
sprite.y += @weatherTypes[@type][6] * delta_t / 1_000_000
|
|
|
|
|
sprite.x += @tiles_wide * sprite.bitmap.width if sprite.x - @ox + sprite.bitmap.width < 0
|
|
|
|
|
sprite.y -= @tiles_tall * sprite.bitmap.height if sprite.y - @oy > Graphics.height
|
|
|
|
|
sprite.visible = true
|
|
|
|
|
sprite.opacity = 255
|
|
|
|
|
return if !sprite || !sprite.bitmap || !sprite.visible
|
|
|
|
|
weather_type = @type
|
|
|
|
|
if @fading && @fade_time >= [FADE_OLD_TONE_END - @time_shift, 0].max
|
|
|
|
|
weather_type = @target_type
|
|
|
|
|
end
|
|
|
|
|
sprite.x = @ox + @tile_x + (index % @tiles_wide) * sprite.bitmap.width
|
|
|
|
|
sprite.y = @oy + @tile_y + (index / @tiles_wide) * sprite.bitmap.height
|
|
|
|
|
sprite.x += @tiles_wide * sprite.bitmap.width if sprite.x - @ox < -sprite.bitmap.width
|
|
|
|
|
sprite.y -= @tiles_tall * sprite.bitmap.height if sprite.y - @oy > Graphics.height
|
|
|
|
|
sprite.visible = true
|
|
|
|
|
if @fading && @type != @target_type
|
|
|
|
|
if @fade_time >= FADE_OLD_TILES_START && @fade_time < FADE_OLD_TILES_END
|
|
|
|
|
if @time_shift == 0 # There were old tiles to fade out
|
|
|
|
|
fraction = (@fade_time - [FADE_OLD_TILES_START - @time_shift, 0].max) / (FADE_OLD_TILES_END - FADE_OLD_TILES_START)
|
|
|
|
|
sprite.opacity = 255 * (1 - fraction)
|
|
|
|
|
end
|
|
|
|
|
elsif @fade_time >= [FADE_NEW_TILES_START - @time_shift, 0].max &&
|
|
|
|
|
@fade_time < [FADE_NEW_TILES_END - @time_shift, 0].max
|
|
|
|
|
fraction = (@fade_time - [FADE_NEW_TILES_START - @time_shift, 0].max) / (FADE_NEW_TILES_END - FADE_NEW_TILES_START)
|
|
|
|
|
sprite.opacity = 255 * fraction
|
|
|
|
|
else
|
|
|
|
|
sprite.opacity = 0
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
sprite.visible = false
|
|
|
|
|
sprite.opacity = (@max > 0) ? 255 : 0
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Set tone of viewport (general screen brightening/darkening)
|
|
|
|
|
def update_screen_tone
|
|
|
|
|
# @max is (power+1)*MAX_SPRITES/10, where power is between 1 and 9
|
|
|
|
|
case @type
|
|
|
|
|
when PBFieldWeather::None
|
|
|
|
|
@viewport.tone.set(0, 0, 0, 0)
|
|
|
|
|
when PBFieldWeather::Rain
|
|
|
|
|
@viewport.tone.set(-@max * 3 / 4, -@max * 3 / 4, -@max * 3 / 4, 10)
|
|
|
|
|
when PBFieldWeather::HeavyRain
|
|
|
|
|
@viewport.tone.set(-@max * 6 / 4, -@max * 6 / 4, -@max * 6 / 4, 20)
|
|
|
|
|
when PBFieldWeather::Storm
|
|
|
|
|
@viewport.tone.set(-@max * 6 / 4, -@max * 6 / 4, -@max * 6 / 4, 20)
|
|
|
|
|
when PBFieldWeather::Snow
|
|
|
|
|
@viewport.tone.set( @max / 2, @max / 2, @max / 2, 0)
|
|
|
|
|
when PBFieldWeather::Blizzard
|
|
|
|
|
@viewport.tone.set( @max * 3 / 4, @max * 3 / 4, max * 3 / 4, 0)
|
|
|
|
|
when PBFieldWeather::Sandstorm
|
|
|
|
|
@viewport.tone.set( @max / 2, 0, -@max / 2, 0)
|
|
|
|
|
when PBFieldWeather::Sun
|
|
|
|
|
@sun = @max if @sun != @max && @sun != -@max
|
|
|
|
|
@sun *= -1 if (@sun > 0 && @sunValue > @max) || (@sun < 0 && @sunValue < 0)
|
|
|
|
|
@sunValue += @sun.to_f * Graphics.delta / 400_000 # 0.4 seconds
|
|
|
|
|
@viewport.tone.set(@sunValue + 63, @sunValue + 63, @sunValue / 2 + 31, 0)
|
|
|
|
|
weather_type = @type
|
|
|
|
|
weather_max = @max
|
|
|
|
|
fraction = 1
|
|
|
|
|
tone_red = 0
|
|
|
|
|
tone_green = 0
|
|
|
|
|
tone_blue = 0
|
|
|
|
|
tone_gray = 0
|
|
|
|
|
# Get base tone
|
|
|
|
|
if @fading
|
|
|
|
|
if @type == @target_type # Just changing max
|
|
|
|
|
if @fade_time >= [FADE_NEW_TONE_START - @time_shift, 0].max &&
|
|
|
|
|
@fade_time < [FADE_NEW_TONE_END - @time_shift, 0].max
|
|
|
|
|
weather_max = @target_max
|
|
|
|
|
fract = (@fade_time - [FADE_NEW_TONE_START - @time_shift, 0].max) / (FADE_NEW_TONE_END - FADE_NEW_TONE_START)
|
|
|
|
|
tone_red = @target_tone.red + (1 - fract) * (@old_tone.red - @target_tone.red)
|
|
|
|
|
tone_green = @target_tone.green + (1 - fract) * (@old_tone.green - @target_tone.green)
|
|
|
|
|
tone_blue = @target_tone.blue + (1 - fract) * (@old_tone.blue - @target_tone.blue)
|
|
|
|
|
tone_gray = @target_tone.gray + (1 - fract) * (@old_tone.gray - @target_tone.gray)
|
|
|
|
|
else
|
|
|
|
|
tone_red = @viewport.tone.red
|
|
|
|
|
tone_green = @viewport.tone.green
|
|
|
|
|
tone_blue = @viewport.tone.blue
|
|
|
|
|
tone_gray = @viewport.tone.gray
|
|
|
|
|
end
|
|
|
|
|
elsif @time_shift < 2 && @fade_time >= FADE_OLD_TONE_START && @fade_time < FADE_OLD_TONE_END
|
|
|
|
|
weather_max = @old_max
|
|
|
|
|
fraction = ((@fade_time - FADE_OLD_TONE_START) / (FADE_OLD_TONE_END - FADE_OLD_TONE_START)).clamp(0, 1)
|
|
|
|
|
fraction = 1 - fraction
|
|
|
|
|
tone_red = @old_tone.red
|
|
|
|
|
tone_green = @old_tone.green
|
|
|
|
|
tone_blue = @old_tone.blue
|
|
|
|
|
tone_gray = @old_tone.gray
|
|
|
|
|
elsif @fade_time >= [FADE_NEW_TONE_START - @time_shift, 0].max
|
|
|
|
|
weather_type = @target_type
|
|
|
|
|
weather_max = @target_max
|
|
|
|
|
fraction = ((@fade_time - [FADE_NEW_TONE_START - @time_shift, 0].max) / (FADE_NEW_TONE_END - FADE_NEW_TONE_START)).clamp(0, 1)
|
|
|
|
|
tone_red = @target_tone.red
|
|
|
|
|
tone_green = @target_tone.green
|
|
|
|
|
tone_blue = @target_tone.blue
|
|
|
|
|
tone_gray = @target_tone.gray
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
base_tone = get_weather_tone(weather_type, weather_max)
|
|
|
|
|
tone_red = base_tone.red
|
|
|
|
|
tone_green = base_tone.green
|
|
|
|
|
tone_blue = base_tone.blue
|
|
|
|
|
tone_gray = base_tone.gray
|
|
|
|
|
end
|
|
|
|
|
# Modify base tone
|
|
|
|
|
if weather_type == PBFieldWeather::Sun
|
|
|
|
|
@sun_magnitude = weather_max if @sun_magnitude != weather_max && @sun_magnitude != -weather_max
|
|
|
|
|
@sun_magnitude *= -1 if (@sun_magnitude > 0 && @sun_strength > @sun_magnitude) ||
|
|
|
|
|
(@sun_magnitude < 0 && @sun_strength < 0)
|
|
|
|
|
@sun_strength += @sun_magnitude.to_f * Graphics.delta_s * 0.4 # 0.4 seconds
|
|
|
|
|
tone_red += @sun_strength
|
|
|
|
|
tone_green += @sun_strength
|
|
|
|
|
tone_blue += @sun_strength / 2
|
|
|
|
|
end
|
|
|
|
|
# Apply screen tone
|
|
|
|
|
@viewport.tone.set(tone_red * fraction, tone_green * fraction,
|
|
|
|
|
tone_blue * fraction, tone_gray * fraction)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def update_fading
|
|
|
|
|
return if !@fading
|
|
|
|
|
old_fade_time = @fade_time
|
|
|
|
|
@fade_time += Graphics.delta_s
|
|
|
|
|
# Change tile bitmaps
|
|
|
|
|
if @type != @target_type
|
|
|
|
|
tile_change_threshold = [FADE_OLD_TONE_END - @time_shift, 0].max
|
|
|
|
|
if old_fade_time <= tile_change_threshold && @fade_time > tile_change_threshold
|
|
|
|
|
@tile_x = @tile_y = 0.0
|
|
|
|
|
if @weatherTypes[@target_type] && @weatherTypes[@target_type][1] && @weatherTypes[@target_type][1].length > 0
|
|
|
|
|
w = @weatherTypes[@target_type][1][0].width
|
|
|
|
|
h = @weatherTypes[@target_type][1][0].height
|
|
|
|
|
@tiles_wide = (Graphics.width.to_f / w).ceil + 1
|
|
|
|
|
@tiles_tall = (Graphics.height.to_f / h).ceil + 1
|
|
|
|
|
ensureTiles
|
|
|
|
|
@tiles.each_with_index { |sprite, i| set_tile_bitmap(sprite, i, @target_type) }
|
|
|
|
|
else
|
|
|
|
|
@tiles_wide = @tiles_tall = 0
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
# Reduce the number of old weather particles
|
|
|
|
|
if @max > 0 && @fade_time >= [FADE_OLD_PARTICLES_START - @time_shift, 0].max
|
|
|
|
|
fraction = (@fade_time - [FADE_OLD_PARTICLES_START - @time_shift, 0].max) / (FADE_OLD_PARTICLES_END - FADE_OLD_PARTICLES_START)
|
|
|
|
|
@max = @old_max * (1 - fraction)
|
|
|
|
|
# NOTE: Sprite visibilities aren't updated here; a sprite is allowed to
|
|
|
|
|
# die off naturally in def reset_sprite_position.
|
|
|
|
|
end
|
|
|
|
|
# Increase the number of new weather particles
|
|
|
|
|
if @new_max < @target_max && @fade_time >= [FADE_NEW_PARTICLES_START - @time_shift, 0].max
|
|
|
|
|
fraction = (@fade_time - [FADE_NEW_PARTICLES_START - @time_shift, 0].max) / (FADE_NEW_PARTICLES_END - FADE_NEW_PARTICLES_START)
|
|
|
|
|
@new_max = (@target_max * fraction).floor
|
|
|
|
|
@new_sprites.each_with_index { |sprite, i| sprite.visible = (i < @new_max) if sprite }
|
|
|
|
|
end
|
|
|
|
|
# End fading
|
|
|
|
|
if @fade_time >= ((@target_type == PBFieldWeather::None) ? FADE_OLD_PARTICLES_END : FADE_NEW_TILES_END) - @time_shift
|
|
|
|
|
if !@sprites.any? { |sprite| sprite.visible }
|
|
|
|
|
@type = @target_type
|
|
|
|
|
@max = @target_max
|
|
|
|
|
@target_type = nil
|
|
|
|
|
@target_max = nil
|
|
|
|
|
@old_max = nil
|
|
|
|
|
@new_max = nil
|
|
|
|
|
@old_tone = nil
|
|
|
|
|
@target_tone = nil
|
|
|
|
|
@fade_time = 0.0
|
|
|
|
|
@time_shift = 0
|
|
|
|
|
@sprites.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@sprites = @new_sprites
|
|
|
|
|
@new_sprites = []
|
|
|
|
|
@sprite_lifetimes = @new_sprite_lifetimes
|
|
|
|
|
@new_sprite_lifetimes = []
|
|
|
|
|
@fading = false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def update
|
|
|
|
|
# @max is (power+1)*MAX_SPRITES/10, where power is between 1 and 9
|
|
|
|
|
update_fading
|
|
|
|
|
update_screen_tone
|
|
|
|
|
# Storm flashes
|
|
|
|
|
if @type == PBFieldWeather::Storm
|
|
|
|
|
if @type == PBFieldWeather::Storm && !@fading
|
|
|
|
|
if @time_until_flash > 0
|
|
|
|
|
@time_until_flash -= Graphics.delta
|
|
|
|
|
@time_until_flash -= Graphics.delta_s
|
|
|
|
|
if @time_until_flash <= 0
|
|
|
|
|
@viewport.flash(Color.new(255, 255, 255, 230), (2 + rand(3)) * 20)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if @time_until_flash <= 0
|
|
|
|
|
@time_until_flash = (1 + rand(12)) * 500_000 # 0.5-6 seconds
|
|
|
|
|
@time_until_flash = (1 + rand(12)) * 0.5 # 0.5-6 seconds
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
@viewport.update
|
|
|
|
|
# Update weather particles (raindrops, snowflakes, etc.)
|
|
|
|
|
if @weatherTypes[@type]
|
|
|
|
|
if @weatherTypes[@type] && @weatherTypes[@type][0] && @weatherTypes[@type][0].length > 0
|
|
|
|
|
ensureSprites
|
|
|
|
|
for i in 0...@max
|
|
|
|
|
update_sprite_position(@sprites[i], i)
|
|
|
|
|
for i in 0...MAX_SPRITES
|
|
|
|
|
update_sprite_position(@sprites[i], i, false)
|
|
|
|
|
end
|
|
|
|
|
elsif @sprites.length > 0
|
|
|
|
|
@sprites.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@sprites.clear
|
|
|
|
|
end
|
|
|
|
|
# Update new weather particles (while fading in only)
|
|
|
|
|
if @fading && @weatherTypes[@target_type] && @weatherTypes[@target_type][0] && @weatherTypes[@target_type][0].length > 0
|
|
|
|
|
ensureSprites
|
|
|
|
|
for i in 0...MAX_SPRITES
|
|
|
|
|
update_sprite_position(@new_sprites[i], i, true)
|
|
|
|
|
end
|
|
|
|
|
elsif @new_sprites.length > 0
|
|
|
|
|
@new_sprites.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@new_sprites.clear
|
|
|
|
|
end
|
|
|
|
|
# Update weather tiles (sandstorm/blizzard tiled overlay)
|
|
|
|
|
if @tiles_wide > 0 && @tiles_tall > 0
|
|
|
|
|
ensureTiles
|
|
|
|
|
recalculate_tile_positions
|
|
|
|
|
@tiles.each_with_index { |sprite, i| update_tile_position(sprite, i) }
|
|
|
|
|
elsif @tiles.length > 0
|
|
|
|
|
@tiles.each { |sprite| sprite.dispose if sprite }
|
|
|
|
|
@tiles.clear
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|