Files
infinitefusion-e18/Data/Scripts/013_Overworld/004_PField_Weather.rb
2021-03-14 23:38:08 +00:00

322 lines
13 KiB
Ruby

# All weather particles are assumed to start at the top/right and move to the
# bottom/left. Particles are only reset if they are off-screen to the left or
# bottom.
module RPG
class Weather
attr_reader :type
attr_reader :max
attr_reader :ox
attr_reader :oy
MAX_SPRITES = 60
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
# [array of particle bitmaps, array of tile bitmaps,
# +x per frame (particle), +y per frame (particle), +opacity per frame (particle),
# +x per frame (tile), +y per frame (tile)]
@weatherTypes = []
@weatherTypes[PBFieldWeather::None] = nil
@weatherTypes[PBFieldWeather::Rain] = [[], nil, -1200 / Graphics.frame_rate, 4800 / Graphics.frame_rate, 0]
@weatherTypes[PBFieldWeather::HeavyRain] = [[], nil, -4800 / Graphics.frame_rate, 4800 / Graphics.frame_rate, 0]
@weatherTypes[PBFieldWeather::Storm] = [[], nil, -4800 / Graphics.frame_rate, 4800 / Graphics.frame_rate, 0]
@weatherTypes[PBFieldWeather::Snow] = [[], nil, -240 / Graphics.frame_rate, 240 / Graphics.frame_rate, 0]
@weatherTypes[PBFieldWeather::Blizzard] = [[], [], -960 / Graphics.frame_rate, 64 / Graphics.frame_rate, 0,
-1440 / Graphics.frame_rate, 720 / Graphics.frame_rate]
@weatherTypes[PBFieldWeather::Sandstorm] = [[], [], -1200 / Graphics.frame_rate, 640 / Graphics.frame_rate, 0,
-720 / Graphics.frame_rate, 360 / Graphics.frame_rate]
@weatherTypes[PBFieldWeather::Sun] = nil
@sprites = []
@sprite_lifetimes = []
@tiles = []
end
def dispose
@sprites.each { |sprite| sprite.dispose if sprite }
@tiles.each { |sprite| sprite.dispose if sprite }
@viewport.dispose
@weatherTypes.each do |weather|
next if !weather
weather[0].each { |bitmap| bitmap.dispose if bitmap }
weather[1].each { |bitmap| bitmap.dispose if bitmap } if weather[1]
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
end
if @weatherTypes[@type] && @weatherTypes[@type][1] && @weatherTypes[@type][1].length > 0
w = @weatherTypes[@type][1][0].width
h = @weatherTypes[@type][1][0].height
@tiles_wide = (Graphics.width.to_f / w).ceil + 1
@tiles_tall = (Graphics.height.to_f / h).ceil + 1
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)
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 }
end
end
def ox=(value)
return if value == @ox
@ox = value
@sprites.each { |sprite| sprite.ox = @ox if sprite }
@tiles.each { |sprite| sprite.ox = @ox if sprite }
end
def oy=(value)
return if value == @oy
@oy = value
@sprites.each { |sprite| sprite.oy = @oy if sprite }
@tiles.each { |sprite| sprite.oy = @oy if sprite }
end
def prepareRainBitmap
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")
rain4 = RPG::Cache.load_bitmap("Graphics/Weather/", "rain_4") # Splash
@weatherTypes[PBFieldWeather::Rain][0] = [rain1, rain2, rain3, rain4]
end
def prepareStormBitmap
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")
storm4 = RPG::Cache.load_bitmap("Graphics/Weather/", "storm_4") # Splash
@weatherTypes[PBFieldWeather::HeavyRain][0] = [storm1, storm2, storm3, storm4]
@weatherTypes[PBFieldWeather::Storm][0] = [storm1, storm2, storm3, storm4]
end
def prepareSnowBitmaps
hail1 = RPG::Cache.load_bitmap("Graphics/Weather/", "hail_1")
hail2 = RPG::Cache.load_bitmap("Graphics/Weather/", "hail_2")
hail3 = RPG::Cache.load_bitmap("Graphics/Weather/", "hail_3")
@weatherTypes[PBFieldWeather::Snow][0] = [hail1, hail2, hail3]
end
def prepareBlizzardBitmaps
blizzard1 = RPG::Cache.load_bitmap("Graphics/Weather/", "blizzard_1")
blizzard2 = RPG::Cache.load_bitmap("Graphics/Weather/", "blizzard_2")
blizzard3 = RPG::Cache.load_bitmap("Graphics/Weather/", "blizzard_3")
blizzard4 = RPG::Cache.load_bitmap("Graphics/Weather/", "blizzard_4")
@weatherTypes[PBFieldWeather::Blizzard][0] = [blizzard1, blizzard2, blizzard3, blizzard4]
blizzard_tile = RPG::Cache.load_bitmap("Graphics/Weather/", "blizzard_tile")
@weatherTypes[PBFieldWeather::Blizzard][1] = [blizzard_tile]
end
def prepareSandstormBitmaps
sandstorm1 = RPG::Cache.load_bitmap("Graphics/Weather/", "sandstorm_1")
sandstorm2 = RPG::Cache.load_bitmap("Graphics/Weather/", "sandstorm_2")
sandstorm3 = RPG::Cache.load_bitmap("Graphics/Weather/", "sandstorm_3")
sandstorm4 = RPG::Cache.load_bitmap("Graphics/Weather/", "sandstorm_4")
@weatherTypes[PBFieldWeather::Sandstorm][0] = [sandstorm1, sandstorm2, sandstorm3, sandstorm4]
sandstorm_tile = RPG::Cache.load_bitmap("Graphics/Weather/", "sandstorm_tile")
@weatherTypes[PBFieldWeather::Sandstorm][1] = [sandstorm_tile]
end
def ensureSprites
if @sprites.length < MAX_SPRITES
for i in 0...MAX_SPRITES
if !@sprites[i]
sprite = Sprite.new(@origViewport)
sprite.z = 1000
sprite.ox = @ox
sprite.oy = @oy
sprite.opacity = 0
@sprites[i] = sprite
end
@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]
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
end
def reset_sprite_position(sprite, index)
if [PBFieldWeather::Rain, PBFieldWeather::HeavyRain, PBFieldWeather::Storm].include?(@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] = Graphics.frame_rate * (30 + rand(20)) / 100
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] = (@oy - sprite.y + rand(Graphics.height * 8 / 5)) / @weatherTypes[@type][3]
end
sprite.opacity = 255
end
def update_sprite_position(sprite, index)
return if !sprite
if @sprite_lifetimes[index] > 0
@sprite_lifetimes[index] -= 1
if @sprite_lifetimes[index] == 0
reset_sprite_position(sprite, index)
return
end
end
if [PBFieldWeather::Rain, PBFieldWeather::HeavyRain, PBFieldWeather::Storm].include?(@type) && index % 2 != 0 # Splash
sprite.visible = (@sprite_lifetimes[index] < Graphics.frame_rate * 2 / 10)
else
sprite.x += @weatherTypes[@type][2]
sprite.y += @weatherTypes[@type][3]
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
end
sprite.opacity += @weatherTypes[@type][4]
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
end
def update_tile_position(sprite, index)
return if !sprite || !sprite.bitmap
if @tiles_wide > 0 && @tiles_tall > 0
sprite.x += @weatherTypes[@type][5]
sprite.y += @weatherTypes[@type][6]
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
else
sprite.visible = false
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 = -@sun if @sunValue > @max || @sunValue < 0
@sunValue = @sunValue + @sun / 32
@viewport.tone.set(@sunValue + 63, @sunValue + 63, @sunValue / 2 + 31, 0)
end
end
def update
# @max is (power+1)*MAX_SPRITES/10, where power is between 1 and 9
update_screen_tone
# Storm flashes
if @type == PBFieldWeather::Storm
rnd = rand(300)
@viewport.flash(Color.new(255, 255, 255, 230), rnd * 20) if rnd < 4
end
@viewport.update
# Update weather particles (raindrops, snowflakes, etc.)
if @weatherTypes[@type]
ensureSprites
for i in 0...@max
update_sprite_position(@sprites[i], i)
end
@tiles.each_with_index { |sprite, i| update_tile_position(sprite, i) }
end
end
end
end