Files
infinitefusion-e18/Data/Scripts/007_Objects and windows/008_AnimatedBitmap.rb
2025-04-27 00:14:10 -04:00

233 lines
6.1 KiB
Ruby

#===============================================================================
#
#===============================================================================
class AnimatedBitmap
def initialize(file, hue = 0)
raise "Filename is nil (missing graphic)." if file.nil?
path = file
@path = path
filename = ""
if file.last != "/" # Isn't just a directory
split_file = file.split(/[\\\/]/)
filename = split_file.pop
path = split_file.join("/") + "/"
end
if filename[/^\[\d+(?:,\d+)?\]/] # Starts with 1 or 2 numbers in square brackets
@bitmap = PngAnimatedBitmap.new(path, filename, hue)
else
@bitmap = GifBitmap.new(path, filename, hue)
end
end
def [](index); @bitmap[index]; end
def width; @bitmap.bitmap.width; end
def height; @bitmap.bitmap.height; end
def length; @bitmap.length; end
def each; @bitmap.each { |item| yield item }; end
def bitmap; @bitmap.bitmap; end
def currentIndex; @bitmap.currentIndex; end
def totalFrames; @bitmap.totalFrames; end
def disposed?; @bitmap.disposed?; end
def update; @bitmap.update; end
def dispose; @bitmap.dispose; end
def deanimate; @bitmap.deanimate; end
def copy; @bitmap.copy; end
def path; @path end
end
#===============================================================================
#
#===============================================================================
class PngAnimatedBitmap
attr_accessor :frames
# Creates an animated bitmap from a PNG file.
def initialize(dir, filename, hue = 0)
@frames = []
@currentFrame = 0
@timer_start = System.uptime
panorama = RPG::Cache.load_bitmap(dir, filename, hue)
if filename[/^\[(\d+)(?:,(\d+))?\]/] # Starts with 1 or 2 numbers in brackets
# File has a frame count
numFrames = $1.to_i
duration = $2.to_i # In 1/20ths of a second
duration = 5 if duration == 0
raise "Invalid frame count in #{filename}" if numFrames <= 0
raise "Invalid frame duration in #{filename}" if duration <= 0
if panorama.width % numFrames != 0
raise "Bitmap's width (#{panorama.width}) is not divisible by frame count: #{filename}"
end
@frame_duration = duration / 20.0
subWidth = panorama.width / numFrames
numFrames.times do |i|
subBitmap = Bitmap.new(subWidth, panorama.height)
subBitmap.blt(0, 0, panorama, Rect.new(subWidth * i, 0, subWidth, panorama.height))
@frames.push(subBitmap)
end
panorama.dispose
else
@frames = [panorama]
end
end
def dispose
return if @disposed
@frames.each { |f| f.dispose }
@disposed = true
end
def disposed?
return @disposed
end
def [](index)
return @frames[index]
end
def width; self.bitmap.width; end
def height; self.bitmap.height; end
def bitmap
return @frames[@currentFrame]
end
def currentIndex
return @currentFrame
end
def length
return @frames.length
end
# Actually returns the total number of 1/20ths of a second this animation lasts.
def totalFrames
return (@frame_duration * @frames.length * 20).to_i
end
def each
@frames.each { |item| yield item }
end
def deanimate
(1...@frames.length).each do |i|
@frames[i].dispose
end
@frames = [@frames[0]]
@currentFrame = 0
@frame_duration = 0
return @frames[0]
end
def copy
x = self.clone
x.frames = x.frames.clone
x.frames.each_with_index { |frame, i| x.frames[i] = frame.copy }
return x
end
def update
return if disposed?
if @frames.length > 1
@currentFrame = ((System.uptime - @timer_start) / @frame_duration).to_i % @frames.length
end
end
end
#===============================================================================
#
#===============================================================================
class GifBitmap
attr_accessor :bitmap
# Creates a bitmap from a GIF file. Can also load non-animated bitmaps.
def initialize(dir, filename, hue = 0)
@bitmap = nil
@disposed = false
filename = "" if !filename
begin
@bitmap = RPG::Cache.load_bitmap(dir, filename, hue)
rescue
@bitmap = nil
end
@bitmap = Bitmap.new(32, 32) if @bitmap.nil?
@bitmap.play if @bitmap&.animated?
end
def [](_index)
return @bitmap
end
def deanimate
@bitmap&.goto_and_stop(0) if @bitmap&.animated?
return @bitmap
end
def currentIndex
return @bitmap&.current_frame || 0
end
def length
return @bitmap&.frame_count || 1
end
def each
yield @bitmap
end
def totalFrames
f_rate = @bitmap.frame_rate
f_rate = 1 if f_rate.nil? || f_rate == 0
return (@bitmap) ? (@bitmap.frame_count / f_rate).floor : 1
end
def disposed?
return @disposed
end
def width
return @bitmap&.width || 0
end
def height
return @bitmap&.height || 0
end
# Gifs are animated automatically by mkxp-z. This function does nothing.
def update; end
def dispose
return if @disposed
@bitmap.dispose
@disposed = true
end
def copy
x = self.clone
x.bitmap = @bitmap.copy if @bitmap
return x
end
end
#===============================================================================
#
#===============================================================================
def pbGetTileBitmap(filename, tile_id, hue, width = 1, height = 1)
return RPG::Cache.tileEx(filename, tile_id, hue, width, height) do |f|
AnimatedBitmap.new("Graphics/Tilesets/" + filename).deanimate
end
end
def pbGetTileset(name, hue = 0)
return AnimatedBitmap.new("Graphics/Tilesets/" + name, hue).deanimate
end
def pbGetAutotile(name, hue = 0)
return AnimatedBitmap.new("Graphics/Autotiles/" + name, hue).deanimate
end
def pbGetAnimation(name, hue = 0)
return AnimatedBitmap.new("Graphics/Animations/" + name, hue).deanimate
end