mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2026-07-24 00:27:00 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,657 @@
|
||||
#===============================================================================
|
||||
# Checking for files and directories
|
||||
#===============================================================================
|
||||
# Works around a problem with FileTest.directory if directory contains accent marks
|
||||
def safeIsDirectory?(f)
|
||||
ret = false
|
||||
Dir.chdir(f) { ret = true } rescue nil
|
||||
return ret
|
||||
end
|
||||
|
||||
# Works around a problem with FileTest.exist if path contains accent marks
|
||||
def safeExists?(f)
|
||||
return FileTest.exist?(f) if f[/\A[\x20-\x7E]*\z/]
|
||||
ret = false
|
||||
begin
|
||||
File.open(f,"rb") { ret = true }
|
||||
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
|
||||
ret = false
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Similar to "Dir.glob", but designed to work around a problem with accessing
|
||||
# files if a path contains accent marks.
|
||||
# "dir" is the directory path, "wildcard" is the filename pattern to match.
|
||||
def safeGlob(dir,wildcard)
|
||||
ret = []
|
||||
afterChdir = false
|
||||
begin
|
||||
Dir.chdir(dir) {
|
||||
afterChdir = true
|
||||
Dir.glob(wildcard) { |f| ret.push(dir+"/"+f) }
|
||||
}
|
||||
rescue Errno::ENOENT
|
||||
raise if afterChdir
|
||||
end
|
||||
if block_given?
|
||||
ret.each { |f| yield(f) }
|
||||
end
|
||||
return (block_given?) ? nil : ret
|
||||
end
|
||||
|
||||
# Finds the real path for an image file. This includes paths in encrypted
|
||||
# archives. Returns nil if the path can't be found.
|
||||
def pbResolveBitmap(x)
|
||||
return nil if !x
|
||||
noext = x.gsub(/\.(bmp|png|gif|jpg|jpeg)$/,"")
|
||||
filename = nil
|
||||
# RTP.eachPathFor(x) { |path|
|
||||
# filename = pbTryString(path) if !filename
|
||||
# filename = pbTryString(path+".gif") if !filename
|
||||
# }
|
||||
RTP.eachPathFor(noext) { |path|
|
||||
filename = pbTryString(path+".png") if !filename
|
||||
filename = pbTryString(path+".gif") if !filename
|
||||
# filename = pbTryString(path+".jpg") if !filename
|
||||
# filename = pbTryString(path+".jpeg") if !filename
|
||||
# filename = pbTryString(path+".bmp") if !filename
|
||||
}
|
||||
return filename
|
||||
end
|
||||
|
||||
# Finds the real path for an image file. This includes paths in encrypted
|
||||
# archives. Returns _x_ if the path can't be found.
|
||||
def pbBitmapName(x)
|
||||
ret = pbResolveBitmap(x)
|
||||
return (ret) ? ret : x
|
||||
end
|
||||
|
||||
def getUnicodeString(addr)
|
||||
return "" if addr==0
|
||||
rtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
|
||||
ret = ""
|
||||
data = "xx"
|
||||
index = (addr.is_a?(String)) ? 0 : addr
|
||||
loop do
|
||||
if addr.is_a?(String)
|
||||
data = addr[index,2]
|
||||
else
|
||||
rtlMoveMemory_pi.call(data, index, 2)
|
||||
end
|
||||
codepoint = data.unpack("v")[0]
|
||||
break if codepoint==0
|
||||
index += 2
|
||||
if codepoint<=0x7F
|
||||
ret += codepoint.chr
|
||||
elsif codepoint<=0x7FF
|
||||
ret += (0xC0|((codepoint>>6)&0x1F)).chr
|
||||
ret += (0x80|(codepoint &0x3F)).chr
|
||||
elsif codepoint<=0xFFFF
|
||||
ret += (0xE0|((codepoint>>12)&0x0F)).chr
|
||||
ret += (0x80|((codepoint>>6)&0x3F)).chr
|
||||
ret += (0x80|(codepoint &0x3F)).chr
|
||||
elsif codepoint<=0x10FFFF
|
||||
ret += (0xF0|((codepoint>>18)&0x07)).chr
|
||||
ret += (0x80|((codepoint>>12)&0x3F)).chr
|
||||
ret += (0x80|((codepoint>>6)&0x3F)).chr
|
||||
ret += (0x80|(codepoint &0x3F)).chr
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def getUnicodeStringFromAnsi(addr)
|
||||
return "" if addr==0
|
||||
rtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
|
||||
ret = ""
|
||||
data = "x"
|
||||
index = (addr.is_a?(String)) ? 0 : addr
|
||||
loop do
|
||||
if addr.is_a?(String)
|
||||
data = addr[index,1]
|
||||
else
|
||||
rtlMoveMemory_pi.call(data, index, 1)
|
||||
end
|
||||
index += 1
|
||||
codepoint = data.unpack("C")[0]
|
||||
break if codepoint==0 || !codepoint
|
||||
break if codepoint==0
|
||||
if codepoint<=0x7F
|
||||
ret += codepoint.chr
|
||||
else
|
||||
ret += (0xC0|((codepoint>>6)&0x1F)).chr
|
||||
ret += (0x80|(codepoint &0x3F)).chr
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def getKnownFolder(guid)
|
||||
packedGuid = guid.pack("VvvC*")
|
||||
shGetKnownFolderPath = Win32API.new("shell32.dll","SHGetKnownFolderPath","pllp","i") rescue nil
|
||||
coTaskMemFree = Win32API.new("ole32.dll","CoTaskMemFree","i","") rescue nil
|
||||
return "" if !(shGetKnownFolderPath && coTaskMemFree)
|
||||
path = "\0"*4
|
||||
ret = shGetKnownFolderPath.call(packedGuid,0,0,path)
|
||||
path = path.unpack("V")[0]
|
||||
ret = getUnicodeString(path)
|
||||
coTaskMemFree.call(path)
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
|
||||
module RTP
|
||||
@rtpPaths = nil
|
||||
|
||||
def self.exists?(filename,extensions=[])
|
||||
return false if !filename || filename==""
|
||||
eachPathFor(filename) { |path|
|
||||
return true if safeExists?(path)
|
||||
for ext in extensions
|
||||
return true if safeExists?(path+ext)
|
||||
end
|
||||
}
|
||||
return false
|
||||
end
|
||||
|
||||
def self.getImagePath(filename)
|
||||
return self.getPath(filename,["",".png",".gif"]) # ".jpg",".bmp",".jpeg"
|
||||
end
|
||||
|
||||
def self.getAudioPath(filename)
|
||||
return self.getPath(filename,["",".mp3",".wav",".wma",".mid",".ogg",".midi"])
|
||||
end
|
||||
|
||||
def self.getPath(filename,extensions=[])
|
||||
return filename if !filename || filename==""
|
||||
eachPathFor(filename) { |path|
|
||||
return path if safeExists?(path)
|
||||
for ext in extensions
|
||||
file = path+ext
|
||||
return file if safeExists?(file)
|
||||
end
|
||||
}
|
||||
return filename
|
||||
end
|
||||
|
||||
# Gets the absolute RGSS paths for the given file name
|
||||
def self.eachPathFor(filename)
|
||||
return if !filename
|
||||
if filename[/^[A-Za-z]\:[\/\\]/] || filename[/^[\/\\]/]
|
||||
# filename is already absolute
|
||||
yield filename
|
||||
else
|
||||
# relative path
|
||||
RTP.eachPath { |path|
|
||||
if path=="./"
|
||||
yield filename
|
||||
else
|
||||
yield path+filename
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# Gets all RGSS search paths
|
||||
def self.eachPath
|
||||
# XXX: Use "." instead of Dir.pwd because of problems retrieving files if
|
||||
# the current directory contains an accent mark
|
||||
yield ".".gsub(/[\/\\]/,"/").gsub(/[\/\\]$/,"")+"/"
|
||||
if !@rtpPaths
|
||||
tmp = Sprite.new
|
||||
isRgss2 = tmp.respond_to?("wave_amp")
|
||||
tmp.dispose
|
||||
@rtpPaths = []
|
||||
if isRgss2
|
||||
rtp = getGameIniValue("Game","RTP")
|
||||
if rtp!=""
|
||||
rtp = MiniRegistry.get(MiniRegistry::HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Enterbrain\\RGSS2\\RTP",rtp,nil)
|
||||
if rtp && safeIsDirectory?(rtp)
|
||||
@rtpPaths.push(rtp.sub(/[\/\\]$/,"")+"/")
|
||||
end
|
||||
end
|
||||
else
|
||||
%w( RTP1 RTP2 RTP3 ).each { |v|
|
||||
rtp = getGameIniValue("Game",v)
|
||||
if rtp!=""
|
||||
rtp = MiniRegistry.get(MiniRegistry::HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Enterbrain\\RGSS\\RTP",rtp,nil)
|
||||
if rtp && safeIsDirectory?(rtp)
|
||||
@rtpPaths.push(rtp.sub(/[\/\\]$/,"")+"/")
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
@rtpPaths.each { |x| yield x }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@folder = nil
|
||||
|
||||
def self.getGameIniValue(section,key)
|
||||
val = "\0"*256
|
||||
gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
|
||||
gps.call(section, key, "", val, 256, ".\\Game.ini")
|
||||
val.delete!("\0")
|
||||
return val
|
||||
end
|
||||
|
||||
def self.isDirWritable(dir)
|
||||
return false if !dir || dir==""
|
||||
loop do
|
||||
name = dir.gsub(/[\/\\]$/,"")+"/writetest"
|
||||
for i in 0...12
|
||||
name += sprintf("%02X",rand(256))
|
||||
end
|
||||
name += ".tmp"
|
||||
if !safeExists?(name)
|
||||
retval = false
|
||||
begin
|
||||
File.open(name,"wb") { retval = true }
|
||||
rescue Errno::EINVAL, Errno::EACCES, Errno::ENOENT
|
||||
ensure
|
||||
File.delete(name) rescue nil
|
||||
end
|
||||
return retval
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.ensureGameDir(dir)
|
||||
title = RTP.getGameIniValue("Game","Title")
|
||||
title = "RGSS Game" if title==""
|
||||
title = title.gsub(/[^\w ]/,"_")
|
||||
newdir = dir.gsub(/[\/\\]$/,"")+"/"
|
||||
# Convert to UTF-8 because of ANSI function
|
||||
newdir += getUnicodeStringFromAnsi(title)
|
||||
Dir.mkdir(newdir) rescue nil
|
||||
ret = safeIsDirectory?(newdir) ? newdir : dir
|
||||
return ret
|
||||
end
|
||||
|
||||
def self.getSaveFileName(fileName)
|
||||
return getSaveFolder().gsub(/[\/\\]$/,"")+"/"+fileName
|
||||
end
|
||||
|
||||
def self.getSaveFolder
|
||||
if !@@folder
|
||||
# XXX: Use "." instead of Dir.pwd because of problems retrieving files if
|
||||
# the current directory contains an accent mark
|
||||
pwd = "."
|
||||
# Get the known folder path for saved games
|
||||
savedGames = getKnownFolder([
|
||||
0x4c5c32ff,0xbb9d,0x43b0,0xb5,0xb4,0x2d,0x72,0xe5,0x4e,0xaa,0xa4])
|
||||
if savedGames && savedGames!="" && isDirWritable(savedGames)
|
||||
pwd = ensureGameDir(savedGames)
|
||||
end
|
||||
if isDirWritable(pwd)
|
||||
@@folder = pwd
|
||||
else
|
||||
appdata = ENV["LOCALAPPDATA"]
|
||||
if isDirWritable(appdata)
|
||||
appdata = ensureGameDir(appdata)
|
||||
else
|
||||
appdata = ENV["APPDATA"]
|
||||
if isDirWritable(appdata)
|
||||
appdata = ensureGameDir(appdata)
|
||||
elsif isDirWritable(pwd)
|
||||
appdata = pwd
|
||||
else
|
||||
appdata = "."
|
||||
end
|
||||
end
|
||||
@@folder = appdata
|
||||
end
|
||||
end
|
||||
return @@folder
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
module FileTest
|
||||
Image_ext = ['.bmp', '.png', '.jpg', '.jpeg', '.gif']
|
||||
Audio_ext = ['.mp3', '.mid', '.midi', '.ogg', '.wav', '.wma']
|
||||
|
||||
def self.audio_exist?(filename)
|
||||
return RTP.exists?(filename,Audio_ext)
|
||||
end
|
||||
|
||||
def self.image_exist?(filename)
|
||||
return RTP.exists?(filename,Image_ext)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Used to determine whether a data file exists (rather than a graphics or
|
||||
# audio file). Doesn't check RTP, but does check encrypted archives.
|
||||
def pbRgssExists?(filename)
|
||||
filename = canonicalize(filename)
|
||||
if safeExists?("./Game.rgssad") || safeExists?("./Game.rgss2a")
|
||||
return pbGetFileChar(filename)!=nil
|
||||
else
|
||||
return safeExists?(filename)
|
||||
end
|
||||
end
|
||||
|
||||
# Opens an IO, even if the file is in an encrypted archive.
|
||||
# Doesn't check RTP for the file.
|
||||
def pbRgssOpen(file,mode=nil)
|
||||
#File.open("debug.txt","ab") { |fw| fw.write([file,mode,Time.now.to_f].inspect+"\r\n") }
|
||||
if !safeExists?("./Game.rgssad") && !safeExists?("./Game.rgss2a")
|
||||
if block_given?
|
||||
File.open(file,mode) { |f| yield f }
|
||||
return nil
|
||||
else
|
||||
return File.open(file,mode)
|
||||
end
|
||||
end
|
||||
file = canonicalize(file)
|
||||
Marshal.neverload = true
|
||||
begin
|
||||
str = load_data(file)
|
||||
ensure
|
||||
Marshal.neverload = false
|
||||
end
|
||||
if block_given?
|
||||
StringInput.open(str) { |f| yield f }
|
||||
return nil
|
||||
else
|
||||
return StringInput.open(str)
|
||||
end
|
||||
end
|
||||
|
||||
# Gets at least the first byte of a file. Doesn't check RTP, but does check
|
||||
# encrypted archives.
|
||||
def pbGetFileChar(file)
|
||||
file = canonicalize(file)
|
||||
if !safeExists?("./Game.rgssad") && !safeExists?("./Game.rgss2a")
|
||||
return nil if !safeExists?(file)
|
||||
begin
|
||||
File.open(file,"rb") { |f| return f.read(1) } # read one byte
|
||||
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
|
||||
return nil
|
||||
end
|
||||
end
|
||||
Marshal.neverload = true
|
||||
str = nil
|
||||
begin
|
||||
str = load_data(file)
|
||||
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, RGSSError
|
||||
str = nil
|
||||
ensure
|
||||
Marshal.neverload = false
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
def pbTryString(x)
|
||||
ret = pbGetFileChar(x)
|
||||
return (ret!=nil && ret!="") ? x : nil
|
||||
end
|
||||
|
||||
# Gets the contents of a file. Doesn't check RTP, but does check
|
||||
# encrypted archives.
|
||||
def pbGetFileString(file)
|
||||
file = canonicalize(file)
|
||||
if !(safeExists?("./Game.rgssad") || safeExists?("./Game.rgss2a"))
|
||||
return nil if !safeExists?(file)
|
||||
begin
|
||||
File.open(file,"rb") { |f| return f.read } # read all data
|
||||
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
|
||||
return nil
|
||||
end
|
||||
end
|
||||
Marshal.neverload = true
|
||||
str = nil
|
||||
begin
|
||||
str = load_data(file)
|
||||
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, RGSSError
|
||||
str = nil
|
||||
ensure
|
||||
Marshal.neverload = false
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module MiniRegistry
|
||||
HKEY_CLASSES_ROOT = 0x80000000
|
||||
HKEY_CURRENT_USER = 0x80000001
|
||||
HKEY_LOCAL_MACHINE = 0x80000002
|
||||
HKEY_USERS = 0x80000003
|
||||
FormatMessageA = Win32API.new("kernel32","FormatMessageA","LPLLPLP","L")
|
||||
RegOpenKeyExA = Win32API.new("advapi32","RegOpenKeyExA","LPLLP","L")
|
||||
RegCloseKey = Win32API.new("advapi32","RegCloseKey","L","L")
|
||||
RegQueryValueExA = Win32API.new("advapi32","RegQueryValueExA","LPLPPP","L")
|
||||
|
||||
def self.open(hkey,subkey,bit64=false)
|
||||
key = 0.chr*4
|
||||
flag = bit64 ? 0x20119 : 0x20019
|
||||
rg = RegOpenKeyExA.call(hkey, subkey, 0, flag, key)
|
||||
return nil if rg!=0
|
||||
key = key.unpack("V")[0]
|
||||
if block_given?
|
||||
begin
|
||||
yield(key)
|
||||
ensure
|
||||
check(RegCloseKey.call(key))
|
||||
end
|
||||
else
|
||||
return key
|
||||
end
|
||||
end
|
||||
|
||||
def self.close(hkey); check(RegCloseKey.call(hkey)) if hkey; end
|
||||
|
||||
def self.get(hkey,subkey,name,defaultValue=nil,bit64=false)
|
||||
self.open(hkey,subkey,bit64) { |key|
|
||||
return self.read(key,name) rescue defaultValue
|
||||
}
|
||||
return defaultValue
|
||||
end
|
||||
|
||||
def self.read(hkey,name)
|
||||
hkey = 0 if !hkey
|
||||
type = 0.chr*4
|
||||
size = 0.chr*4
|
||||
check(RegQueryValueExA.call(hkey,name,0,type,0,size))
|
||||
data = " "*size.unpack("V")[0]
|
||||
check(RegQueryValueExA.call(hkey,name,0,type,data,size))
|
||||
type = type.unpack("V")[0]
|
||||
data = data[0,size.unpack("V")[0]]
|
||||
case type
|
||||
when 1; return data.chop # REG_SZ
|
||||
when 2; return data.gsub(/%([^%]+)%/) { ENV[$1] || $& } # REG_EXPAND_SZ
|
||||
when 3; return data # REG_BINARY
|
||||
when 4; return data.unpack("V")[0] # REG_DWORD
|
||||
when 5; return data.unpack("V")[0] # REG_DWORD_BIG_ENDIAN
|
||||
when 11; qw = data.unpack("VV"); return (data[1]<<32|data[0]) # REG_QWORD
|
||||
else; raise "Type #{type} not supported."
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.check(code)
|
||||
if code!=0
|
||||
msg = "\0"*1024
|
||||
len = FormatMessageA.call(0x1200, 0, code, 0, msg, 1024, 0)
|
||||
raise msg[0, len].tr("\r", '').chomp
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class StringInput
|
||||
include Enumerable
|
||||
|
||||
class << self
|
||||
def new( str )
|
||||
if block_given?
|
||||
begin
|
||||
f = super
|
||||
yield f
|
||||
ensure
|
||||
f.close if f
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
alias open new
|
||||
end
|
||||
|
||||
def initialize( str )
|
||||
@string = str
|
||||
@pos = 0
|
||||
@closed = false
|
||||
@lineno = 0
|
||||
end
|
||||
|
||||
attr_reader :lineno,:string
|
||||
|
||||
def inspect
|
||||
return "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@string[0,30].inspect}>"
|
||||
end
|
||||
|
||||
def close
|
||||
raise IOError, 'closed stream' if @closed
|
||||
@pos = nil
|
||||
@closed = true
|
||||
end
|
||||
|
||||
def closed?; @closed; end
|
||||
|
||||
def pos
|
||||
raise IOError, 'closed stream' if @closed
|
||||
[@pos, @string.size].min
|
||||
end
|
||||
|
||||
alias tell pos
|
||||
|
||||
def rewind; seek(0); end
|
||||
|
||||
def pos=(value); seek(value); end
|
||||
|
||||
def seek(offset, whence=IO::SEEK_SET)
|
||||
raise IOError, 'closed stream' if @closed
|
||||
case whence
|
||||
when IO::SEEK_SET; @pos = offset
|
||||
when IO::SEEK_CUR; @pos += offset
|
||||
when IO::SEEK_END; @pos = @string.size - offset
|
||||
else
|
||||
raise ArgumentError, "unknown seek flag: #{whence}"
|
||||
end
|
||||
@pos = 0 if @pos < 0
|
||||
@pos = [@pos, @string.size + 1].min
|
||||
offset
|
||||
end
|
||||
|
||||
def eof?
|
||||
raise IOError, 'closed stream' if @closed
|
||||
@pos > @string.size
|
||||
end
|
||||
|
||||
def each( &block )
|
||||
raise IOError, 'closed stream' if @closed
|
||||
begin
|
||||
@string.each(&block)
|
||||
ensure
|
||||
@pos = 0
|
||||
end
|
||||
end
|
||||
|
||||
def gets
|
||||
raise IOError, 'closed stream' if @closed
|
||||
if idx = @string.index(?\n, @pos)
|
||||
idx += 1 # "\n".size
|
||||
line = @string[ @pos ... idx ]
|
||||
@pos = idx
|
||||
@pos += 1 if @pos == @string.size
|
||||
else
|
||||
line = @string[ @pos .. -1 ]
|
||||
@pos = @string.size + 1
|
||||
end
|
||||
@lineno += 1
|
||||
line
|
||||
end
|
||||
|
||||
def getc
|
||||
raise IOError, 'closed stream' if @closed
|
||||
ch = @string[@pos]
|
||||
@pos += 1
|
||||
@pos += 1 if @pos == @string.size
|
||||
ch
|
||||
end
|
||||
|
||||
def read( len = nil )
|
||||
raise IOError, 'closed stream' if @closed
|
||||
if !len
|
||||
return nil if eof?
|
||||
rest = @string[@pos ... @string.size]
|
||||
@pos = @string.size + 1
|
||||
return rest
|
||||
end
|
||||
str = @string[@pos, len]
|
||||
@pos += len
|
||||
@pos += 1 if @pos == @string.size
|
||||
str
|
||||
end
|
||||
|
||||
def read_all; read(); end
|
||||
|
||||
alias sysread read
|
||||
end
|
||||
|
||||
|
||||
|
||||
module ::Marshal
|
||||
class << self
|
||||
if !@oldloadAliased
|
||||
alias oldload load
|
||||
@oldloadAliased = true
|
||||
end
|
||||
|
||||
@@neverload = false
|
||||
|
||||
def neverload
|
||||
return @@neverload
|
||||
end
|
||||
|
||||
def neverload=(value)
|
||||
@@neverload = value
|
||||
end
|
||||
|
||||
def load(port,*arg)
|
||||
if @@neverload
|
||||
if port.is_a?(IO)
|
||||
return port.read
|
||||
end
|
||||
return port
|
||||
end
|
||||
oldpos = port.pos if port.is_a?(IO)
|
||||
begin
|
||||
oldload(port,*arg)
|
||||
rescue
|
||||
p [$!.class,$!.message,$!.backtrace]
|
||||
if port.is_a?(IO)
|
||||
port.pos = oldpos
|
||||
return port.read
|
||||
end
|
||||
return port
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,497 @@
|
||||
class Hangup < Exception; end
|
||||
|
||||
|
||||
|
||||
def strsplit(str,re)
|
||||
ret=[]
|
||||
tstr=str
|
||||
while re=~tstr
|
||||
ret[ret.length]=$~.pre_match
|
||||
tstr=$~.post_match
|
||||
end
|
||||
ret[ret.length]=tstr if ret.length
|
||||
return ret
|
||||
end
|
||||
|
||||
def canonicalize(c)
|
||||
csplit = strsplit(c,/[\/\\]/)
|
||||
pos = -1
|
||||
ret = []
|
||||
retstr = ""
|
||||
for x in csplit
|
||||
if x=="."
|
||||
elsif x==".."
|
||||
if pos>=0
|
||||
ret.delete_at(pos)
|
||||
pos -= 1
|
||||
end
|
||||
else
|
||||
ret.push(x)
|
||||
pos += 1
|
||||
end
|
||||
end
|
||||
for i in 0...ret.length
|
||||
retstr += "/" if i>0
|
||||
retstr += ret[i]
|
||||
end
|
||||
return retstr
|
||||
end
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
class WeakRef
|
||||
@@id_map = {}
|
||||
@@id_rev_map = {}
|
||||
@@final = lambda { |id|
|
||||
__old_status = Thread.critical
|
||||
Thread.critical = true
|
||||
begin
|
||||
rids = @@id_map[id]
|
||||
if rids
|
||||
for rid in rids
|
||||
@@id_rev_map.delete(rid)
|
||||
end
|
||||
@@id_map.delete(id)
|
||||
end
|
||||
rid = @@id_rev_map[id]
|
||||
if rid
|
||||
@@id_rev_map.delete(id)
|
||||
@@id_map[rid].delete(id)
|
||||
@@id_map.delete(rid) if @@id_map[rid].empty?
|
||||
end
|
||||
ensure
|
||||
Thread.critical = __old_status
|
||||
end
|
||||
}
|
||||
|
||||
# Create a new WeakRef from +orig+.
|
||||
def initialize(orig)
|
||||
__setobj__(orig)
|
||||
end
|
||||
|
||||
def __getobj__
|
||||
unless @@id_rev_map[self.__id__] == @__id
|
||||
return nil
|
||||
end
|
||||
begin
|
||||
ObjectSpace._id2ref(@__id)
|
||||
rescue RangeError
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def __setobj__(obj)
|
||||
@__id = obj.__id__
|
||||
__old_status = Thread.critical
|
||||
begin
|
||||
Thread.critical = true
|
||||
unless @@id_rev_map.key?(self)
|
||||
ObjectSpace.define_finalizer obj, @@final
|
||||
ObjectSpace.define_finalizer self, @@final
|
||||
end
|
||||
@@id_map[@__id] = [] unless @@id_map[@__id]
|
||||
ensure
|
||||
Thread.critical = __old_status
|
||||
end
|
||||
@@id_map[@__id].push self.__id__
|
||||
@@id_rev_map[self.__id__] = @__id
|
||||
end
|
||||
|
||||
# Returns true if the referenced object still exists, and false if it has
|
||||
# been garbage collected.
|
||||
def weakref_alive?
|
||||
@@id_rev_map[self.__id__] == @__id
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class WeakHashtable
|
||||
include Enumerable
|
||||
|
||||
def initialize
|
||||
@hash={}
|
||||
end
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
end
|
||||
|
||||
def delete(value)
|
||||
@hash.delete(value)
|
||||
end
|
||||
|
||||
def include?(value)
|
||||
@hash.include?(value)
|
||||
end
|
||||
|
||||
def each
|
||||
@hash.each { |i| yield i }
|
||||
end
|
||||
|
||||
def keys
|
||||
@hash.keys
|
||||
end
|
||||
|
||||
def values
|
||||
@hash.values
|
||||
end
|
||||
|
||||
def [](key)
|
||||
o=@hash[key]
|
||||
return o if !o
|
||||
if o.weakref_alive?
|
||||
o=o.__getobj__
|
||||
else
|
||||
@hash.delete(key)
|
||||
o=nil
|
||||
end
|
||||
return o
|
||||
end
|
||||
|
||||
def []=(key,o)
|
||||
if o!=nil
|
||||
o=WeakRef.new(o)
|
||||
end
|
||||
@hash[key]=o
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# Cache from RPG Maker VX library
|
||||
module Cache
|
||||
def self.system(x,hue=0)
|
||||
BitmapCache.load_bitmap("Graphics/System/"+x,hue, true)
|
||||
end
|
||||
|
||||
def self.character(x,hue=0)
|
||||
BitmapCache.load_bitmap("Graphics/Characters/"+x,hue, true)
|
||||
end
|
||||
|
||||
def self.picture(x,hue=0)
|
||||
BitmapCache.load_bitmap("Graphics/Pictures/"+x,hue, true)
|
||||
end
|
||||
|
||||
def self.animation(x,hue=0)
|
||||
BitmapCache.load_bitmap("Graphics/Animations/"+x,hue, true)
|
||||
end
|
||||
|
||||
def self.battler(x,hue=0)
|
||||
BitmapCache.load_bitmap("Graphics/Battlers/"+x,hue, true)
|
||||
end
|
||||
|
||||
def self.face(x,hue=0)
|
||||
BitmapCache.load_bitmap("Graphics/Faces/"+x,hue, true)
|
||||
end
|
||||
|
||||
def self.parallax(x,hue=0)
|
||||
BitmapCache.load_bitmap("Graphics/Parallaxes/"+x,hue, true)
|
||||
end
|
||||
|
||||
def self.clear
|
||||
BitmapCache.clear()
|
||||
end
|
||||
|
||||
def self.load_bitmap(dir,name,hue=0)
|
||||
BitmapCache.load_bitmap(dir+name,hue, true)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# RPG::Cache from RPG Maker XP library
|
||||
module RPG
|
||||
module Cache
|
||||
def self.load_bitmap(folder_name, filename, hue = 0)
|
||||
BitmapCache.load_bitmap(folder_name+filename.to_s,hue, true)
|
||||
end
|
||||
|
||||
def self.animation(filename, hue)
|
||||
self.load_bitmap("Graphics/Animations/", filename, hue)
|
||||
end
|
||||
|
||||
def self.autotile(filename)
|
||||
self.load_bitmap("Graphics/Autotiles/", filename)
|
||||
end
|
||||
|
||||
def self.battleback(filename)
|
||||
self.load_bitmap("Graphics/Battlebacks/", filename)
|
||||
end
|
||||
|
||||
def self.battler(filename, hue)
|
||||
self.load_bitmap("Graphics/Battlers/", filename, hue)
|
||||
end
|
||||
|
||||
def self.character(filename, hue)
|
||||
self.load_bitmap("Graphics/Characters/", filename, hue)
|
||||
end
|
||||
|
||||
def self.fog(filename, hue)
|
||||
self.load_bitmap("Graphics/Fogs/", filename, hue)
|
||||
end
|
||||
|
||||
def self.gameover(filename)
|
||||
self.load_bitmap("Graphics/Gameovers/", filename)
|
||||
end
|
||||
|
||||
def self.icon(filename)
|
||||
self.load_bitmap("Graphics/Icons/", filename)
|
||||
end
|
||||
|
||||
def self.panorama(filename, hue)
|
||||
self.load_bitmap("Graphics/Panoramas/", filename, hue)
|
||||
end
|
||||
|
||||
def self.picture(filename)
|
||||
self.load_bitmap("Graphics/Pictures/", filename)
|
||||
end
|
||||
|
||||
def self.tileset(filename)
|
||||
self.load_bitmap("Graphics/Tilesets/", filename)
|
||||
end
|
||||
|
||||
def self.title(filename)
|
||||
self.load_bitmap("Graphics/Titles/", filename)
|
||||
end
|
||||
|
||||
def self.windowskin(filename)
|
||||
self.load_bitmap("Graphics/Windowskins/", filename)
|
||||
end
|
||||
|
||||
def self.tile(filename, tile_id, hue)
|
||||
BitmapCache.tile(filename,tile_id,hue)
|
||||
end
|
||||
|
||||
def self.clear
|
||||
BitmapCache.clear()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# A safer version of RPG::Cache, this module loads bitmaps that keep an internal
|
||||
# reference count. Each call to dispose decrements the reference count and the
|
||||
# bitmap is freed when the reference count reaches 0.
|
||||
class Thread
|
||||
def Thread.exclusive
|
||||
_old = Thread.critical
|
||||
begin
|
||||
Thread.critical = true
|
||||
return yield
|
||||
ensure
|
||||
Thread.critical = _old
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class BitmapWrapper < Bitmap
|
||||
@@disposedBitmaps={}
|
||||
@@keys={}
|
||||
=begin
|
||||
@@final = lambda { |id|
|
||||
Thread.exclusive {
|
||||
if @@disposedBitmaps[id]!=true
|
||||
File.open("debug.txt","ab") { |f|
|
||||
f.write("Bitmap finalized without being disposed: #{@@keys[id]}\r\n")
|
||||
}
|
||||
end
|
||||
@@disposedBitmaps[id]=nil
|
||||
}
|
||||
}
|
||||
=end
|
||||
attr_reader :refcount
|
||||
|
||||
def dispose
|
||||
return if self.disposed?
|
||||
@refcount-=1
|
||||
if @refcount==0
|
||||
super
|
||||
#Thread.exclusive { @@disposedBitmaps[__id__]=true }
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(*arg)
|
||||
super
|
||||
@refcount=1
|
||||
#Thread.exclusive { @@keys[__id__]=arg.inspect+caller(1).inspect }
|
||||
#ObjectSpace.define_finalizer(self,@@final)
|
||||
end
|
||||
|
||||
def resetRef # internal
|
||||
@refcount=1
|
||||
end
|
||||
|
||||
def copy
|
||||
bm=self.clone
|
||||
bm.resetRef
|
||||
return bm
|
||||
end
|
||||
|
||||
def addRef
|
||||
@refcount+=1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
module BitmapCache
|
||||
@cache = WeakHashtable.new
|
||||
|
||||
def self.fromCache(i)
|
||||
return nil if !@cache.include?(i)
|
||||
obj=@cache[i]
|
||||
return nil if obj && obj.disposed?
|
||||
return obj
|
||||
end
|
||||
|
||||
def self.setKey(key,obj)
|
||||
@cache[key]=obj
|
||||
end
|
||||
|
||||
def self.debug
|
||||
File.open("bitmapcache2.txt","wb") { |f|
|
||||
for i in @cache.keys
|
||||
k = fromCache(i)
|
||||
if !k
|
||||
f.write("#{i} (nil)\r\n")
|
||||
elsif k.disposed?
|
||||
f.write("#{i} (disposed)\r\n")
|
||||
else
|
||||
f.write("#{i} (#{k.refcount}, #{k.width}x#{k.height})\r\n")
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def self.load_bitmap(path, hue = 0, failsafe = false)
|
||||
cached = true
|
||||
path = canonicalize(path)
|
||||
objPath = fromCache(path)
|
||||
if !objPath
|
||||
@cleancounter = ((@cleancounter || 0) + 1)%10
|
||||
if @cleancounter == 0
|
||||
for i in @cache.keys
|
||||
@cache.delete(i) if !fromCache(i)
|
||||
end
|
||||
end
|
||||
begin
|
||||
bm = BitmapWrapper.new(path)
|
||||
rescue Hangup
|
||||
begin
|
||||
bm = BitmapWrapper.new(path)
|
||||
rescue
|
||||
raise _INTL("Failed to load the bitmap located at: {1}",path) if !failsafe
|
||||
bm = BitmapWrapper.new(32,32)
|
||||
end
|
||||
rescue
|
||||
raise _INTL("Failed to load the bitmap located at: {1}",path) if !failsafe
|
||||
bm = BitmapWrapper.new(32,32)
|
||||
end
|
||||
objPath = bm
|
||||
@cache[path] = objPath
|
||||
cached=false
|
||||
end
|
||||
if hue == 0
|
||||
objPath.addRef if cached
|
||||
return objPath
|
||||
else
|
||||
key = [path, hue]
|
||||
objKey = fromCache(key)
|
||||
if !objKey
|
||||
bitmap = objPath.copy
|
||||
bitmap.hue_change(hue) if hue!=0
|
||||
objKey = bitmap
|
||||
@cache[key] = objKey
|
||||
else
|
||||
objKey.addRef
|
||||
end
|
||||
return objKey
|
||||
end
|
||||
end
|
||||
|
||||
def self.animation(filename, hue)
|
||||
self.load_bitmap("Graphics/Animations/"+filename, hue)
|
||||
end
|
||||
|
||||
def self.autotile(filename)
|
||||
self.load_bitmap("Graphics/Autotiles/"+ filename)
|
||||
end
|
||||
|
||||
def self.battleback(filename)
|
||||
self.load_bitmap("Graphics/Battlebacks/"+ filename)
|
||||
end
|
||||
|
||||
def self.battler(filename, hue)
|
||||
self.load_bitmap("Graphics/Battlers/"+ filename, hue)
|
||||
end
|
||||
|
||||
def self.character(filename, hue)
|
||||
self.load_bitmap("Graphics/Characters/"+ filename, hue)
|
||||
end
|
||||
|
||||
def self.fog(filename, hue)
|
||||
self.load_bitmap("Graphics/Fogs/"+ filename, hue)
|
||||
end
|
||||
|
||||
def self.gameover(filename)
|
||||
self.load_bitmap("Graphics/Gameovers/"+ filename)
|
||||
end
|
||||
|
||||
def self.icon(filename)
|
||||
self.load_bitmap("Graphics/Icons/"+ filename)
|
||||
end
|
||||
|
||||
def self.panorama(filename, hue)
|
||||
self.load_bitmap("Graphics/Panoramas/"+ filename, hue)
|
||||
end
|
||||
|
||||
def self.picture(filename)
|
||||
self.load_bitmap("Graphics/Pictures/"+ filename)
|
||||
end
|
||||
|
||||
def self.tileset(filename)
|
||||
self.load_bitmap("Graphics/Tilesets/"+ filename)
|
||||
end
|
||||
|
||||
def self.title(filename)
|
||||
self.load_bitmap("Graphics/Titles/"+ filename)
|
||||
end
|
||||
|
||||
def self.windowskin(filename)
|
||||
self.load_bitmap("Graphics/Windowskins/"+ filename)
|
||||
end
|
||||
|
||||
def self.tileEx(filename, tile_id, hue)
|
||||
key = [filename, tile_id, hue]
|
||||
objKey=fromCache(key)
|
||||
if !objKey
|
||||
bitmap=BitmapWrapper.new(32, 32)
|
||||
x = (tile_id - 384) % 8 * 32
|
||||
y = (tile_id - 384) / 8 * 32
|
||||
rect = Rect.new(x, y, 32, 32)
|
||||
tileset = yield(filename)
|
||||
bitmap.blt(0, 0, tileset, rect)
|
||||
tileset.dispose
|
||||
bitmap.hue_change(hue) if hue!=0
|
||||
objKey=bitmap
|
||||
@cache[key]=objKey
|
||||
else
|
||||
objKey.addRef
|
||||
end
|
||||
objKey
|
||||
end
|
||||
|
||||
def self.tile(filename, tile_id, hue)
|
||||
return self.tileEx(filename, tile_id,hue) { |f| self.tileset(f) }
|
||||
end
|
||||
|
||||
def self.clear
|
||||
@cache = {}
|
||||
GC.start
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,608 @@
|
||||
class WindowCursorRect < Rect
|
||||
def initialize(window)
|
||||
@window=window
|
||||
@x=0
|
||||
@y=0
|
||||
@width=0
|
||||
@height=0
|
||||
end
|
||||
|
||||
attr_reader :x,:y,:width,:height
|
||||
|
||||
def empty
|
||||
needupdate=@x!=0 || @y!=0 || @width!=0 || @height!=0
|
||||
if needupdate
|
||||
@x=0
|
||||
@y=0
|
||||
@width=0
|
||||
@height=0
|
||||
@window.width=@window.width
|
||||
end
|
||||
end
|
||||
|
||||
def isEmpty?
|
||||
return @x==0 && @y==0 && @width==0 && @height==0
|
||||
end
|
||||
|
||||
def set(x,y,width,height)
|
||||
needupdate=@x!=x || @y!=y || @width!=width || @height!=height
|
||||
if needupdate
|
||||
@x=x
|
||||
@y=y
|
||||
@width=width
|
||||
@height=height
|
||||
@window.width=@window.width
|
||||
end
|
||||
end
|
||||
|
||||
def height=(value)
|
||||
@height=value; @window.width=@window.width
|
||||
end
|
||||
|
||||
def width=(value)
|
||||
@width=value; @window.width=@window.width
|
||||
end
|
||||
|
||||
def x=(value)
|
||||
@x=value; @window.width=@window.width
|
||||
end
|
||||
|
||||
def y=(value)
|
||||
@y=value; @window.width=@window.width
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Window
|
||||
attr_reader :tone
|
||||
attr_reader :color
|
||||
attr_reader :blend_type
|
||||
attr_reader :contents_blend_type
|
||||
attr_reader :viewport
|
||||
attr_reader :contents
|
||||
attr_reader :ox
|
||||
attr_reader :oy
|
||||
attr_reader :x
|
||||
attr_reader :y
|
||||
attr_reader :z
|
||||
attr_reader :width
|
||||
attr_reader :active
|
||||
attr_reader :pause
|
||||
attr_reader :height
|
||||
attr_reader :opacity
|
||||
attr_reader :back_opacity
|
||||
attr_reader :contents_opacity
|
||||
attr_reader :visible
|
||||
attr_reader :cursor_rect
|
||||
attr_reader :openness
|
||||
attr_reader :stretch
|
||||
|
||||
def windowskin
|
||||
@_windowskin
|
||||
end
|
||||
|
||||
def initialize(viewport=nil)
|
||||
@sprites={}
|
||||
@spritekeys=[
|
||||
"back",
|
||||
"corner0","side0","scroll0",
|
||||
"corner1","side1","scroll1",
|
||||
"corner2","side2","scroll2",
|
||||
"corner3","side3","scroll3",
|
||||
"cursor","contents","pause"
|
||||
]
|
||||
@sidebitmaps=[nil,nil,nil,nil]
|
||||
@cursorbitmap=nil
|
||||
@bgbitmap=nil
|
||||
@viewport=viewport
|
||||
for i in @spritekeys
|
||||
@sprites[i]=Sprite.new(@viewport)
|
||||
end
|
||||
@disposed=false
|
||||
@tone=Tone.new(0,0,0)
|
||||
@color=Color.new(0,0,0,0)
|
||||
@blankcontents=Bitmap.new(1,1) # RGSS2 requires this
|
||||
@contents=@blankcontents
|
||||
@_windowskin=nil
|
||||
@rpgvx=false # Set to true to emulate RPGVX windows
|
||||
@x=0
|
||||
@y=0
|
||||
@width=0
|
||||
@openness=255
|
||||
@height=0
|
||||
@ox=0
|
||||
@oy=0
|
||||
@z=0
|
||||
@stretch=true
|
||||
@visible=true
|
||||
@active=true
|
||||
@blend_type=0
|
||||
@contents_blend_type=0
|
||||
@opacity=255
|
||||
@back_opacity=255
|
||||
@contents_opacity=255
|
||||
@cursor_rect=WindowCursorRect.new(self)
|
||||
@cursorblink=0
|
||||
@cursoropacity=255
|
||||
@pause=false
|
||||
@pauseopacity=255
|
||||
@pauseframe=0
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def dispose
|
||||
if !self.disposed?
|
||||
for i in @sprites
|
||||
i[1].dispose if i[1]
|
||||
@sprites[i[0]]=nil
|
||||
end
|
||||
for i in 0...@sidebitmaps.length
|
||||
@sidebitmaps[i].dispose if @sidebitmaps[i]
|
||||
@sidebitmaps[i]=nil
|
||||
end
|
||||
@blankcontents.dispose
|
||||
@cursorbitmap.dispose if @cursorbitmap
|
||||
@backbitmap.dispose if @backbitmap
|
||||
@sprites.clear
|
||||
@sidebitmaps.clear
|
||||
@_windowskin=nil
|
||||
@_contents=nil
|
||||
@disposed=true
|
||||
end
|
||||
end
|
||||
|
||||
def openness=(value)
|
||||
@openness=value
|
||||
@openness=0 if @openness<0
|
||||
@openness=255 if @openness>255
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def stretch=(value)
|
||||
@stretch=value
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def visible=(value)
|
||||
@visible=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def viewport=(value)
|
||||
@viewport=value
|
||||
for i in @spritekeys
|
||||
@sprites[i].dispose
|
||||
if @sprites[i].is_a?(Sprite)
|
||||
@sprites[i]=Sprite.new(@viewport)
|
||||
else
|
||||
@sprites[i]=nil
|
||||
end
|
||||
end
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def z=(value)
|
||||
@z=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def contents=(value)
|
||||
@contents=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def windowskin=(value)
|
||||
@_windowskin=value
|
||||
if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128
|
||||
@rpgvx=true
|
||||
else
|
||||
@rpgvx=false
|
||||
end
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def ox=(value)
|
||||
@ox=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def active=(value)
|
||||
@active=value
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def cursor_rect=(value)
|
||||
if !value
|
||||
@cursor_rect.empty
|
||||
else
|
||||
@cursor_rect.set(value.x,value.y,value.width,value.height)
|
||||
end
|
||||
end
|
||||
|
||||
def oy=(value)
|
||||
@oy=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def width=(value)
|
||||
@width=value
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def height=(value)
|
||||
@height=value
|
||||
privRefresh(true)
|
||||
end
|
||||
|
||||
def pause=(value)
|
||||
@pause=value
|
||||
@pauseopacity=0 if !value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def x=(value)
|
||||
@x=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def y=(value)
|
||||
@y=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def opacity=(value)
|
||||
@opacity=value
|
||||
@opacity=0 if @opacity<0
|
||||
@opacity=255 if @opacity>255
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def back_opacity=(value)
|
||||
@back_opacity=value
|
||||
@back_opacity=0 if @back_opacity<0
|
||||
@back_opacity=255 if @back_opacity>255
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def contents_opacity=(value)
|
||||
@contents_opacity=value
|
||||
@contents_opacity=0 if @contents_opacity<0
|
||||
@contents_opacity=255 if @contents_opacity>255
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def tone=(value)
|
||||
@tone=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def color=(value)
|
||||
@color=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def blend_type=(value)
|
||||
@blend_type=value
|
||||
privRefresh
|
||||
end
|
||||
|
||||
def flash(color,duration)
|
||||
return if disposed?
|
||||
for i in @sprites
|
||||
i[1].flash(color,duration)
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
mustchange=false
|
||||
if @active
|
||||
if @cursorblink==0
|
||||
@cursoropacity-=8
|
||||
@cursorblink=1 if @cursoropacity<=128
|
||||
else
|
||||
@cursoropacity+=8
|
||||
@cursorblink=0 if @cursoropacity>=255
|
||||
end
|
||||
mustchange=true if !@cursor_rect.isEmpty?
|
||||
else
|
||||
mustchange=true if @cursoropacity!=128
|
||||
@cursoropacity=128
|
||||
end
|
||||
if @pause
|
||||
@pauseframe=(Graphics.frame_count / 8) % 4
|
||||
@pauseopacity=[@pauseopacity+64,255].min
|
||||
mustchange=true
|
||||
end
|
||||
privRefresh if mustchange
|
||||
for i in @sprites
|
||||
i[1].update
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensureBitmap(bitmap,dwidth,dheight)
|
||||
if !bitmap||bitmap.disposed?||bitmap.width<dwidth||bitmap.height<dheight
|
||||
bitmap.dispose if bitmap
|
||||
bitmap=Bitmap.new([1,dwidth].max,[1,dheight].max)
|
||||
end
|
||||
return bitmap
|
||||
end
|
||||
|
||||
def tileBitmap(dstbitmap,dstrect,srcbitmap,srcrect)
|
||||
return if !srcbitmap || srcbitmap.disposed?
|
||||
left=dstrect.x
|
||||
top=dstrect.y
|
||||
y=0;loop do break unless y<dstrect.height
|
||||
x=0;loop do break unless x<dstrect.width
|
||||
dstbitmap.blt(x+left,y+top,srcbitmap,srcrect)
|
||||
x+=srcrect.width
|
||||
end
|
||||
y+=srcrect.height
|
||||
end
|
||||
end
|
||||
|
||||
def privRefresh(changeBitmap=false)
|
||||
return if self.disposed?
|
||||
backopac=self.back_opacity*self.opacity/255
|
||||
contopac=self.contents_opacity
|
||||
cursoropac=@cursoropacity*contopac/255
|
||||
for i in 0...4
|
||||
@sprites["corner#{i}"].bitmap=@_windowskin
|
||||
@sprites["scroll#{i}"].bitmap=@_windowskin
|
||||
end
|
||||
@sprites["pause"].bitmap=@_windowskin
|
||||
@sprites["contents"].bitmap=@contents
|
||||
if @_windowskin && !@_windowskin.disposed?
|
||||
for i in 0...4
|
||||
@sprites["corner#{i}"].opacity=@opacity
|
||||
@sprites["corner#{i}"].tone=@tone
|
||||
@sprites["corner#{i}"].color=@color
|
||||
@sprites["corner#{i}"].blend_type=@blend_type
|
||||
@sprites["corner#{i}"].visible=@visible
|
||||
@sprites["side#{i}"].opacity=@opacity
|
||||
@sprites["side#{i}"].tone=@tone
|
||||
@sprites["side#{i}"].color=@color
|
||||
@sprites["side#{i}"].blend_type=@blend_type
|
||||
@sprites["side#{i}"].visible=@visible
|
||||
@sprites["scroll#{i}"].opacity=@opacity
|
||||
@sprites["scroll#{i}"].tone=@tone
|
||||
@sprites["scroll#{i}"].blend_type=@blend_type
|
||||
@sprites["scroll#{i}"].color=@color
|
||||
@sprites["scroll#{i}"].visible=@visible
|
||||
end
|
||||
for i in ["back","cursor","pause","contents"]
|
||||
@sprites[i].color=@color
|
||||
@sprites[i].tone=@tone
|
||||
@sprites[i].blend_type=@blend_type
|
||||
end
|
||||
@sprites["contents"].blend_type=@contents_blend_type
|
||||
@sprites["back"].opacity=backopac
|
||||
@sprites["contents"].opacity=contopac
|
||||
@sprites["cursor"].opacity=cursoropac
|
||||
@sprites["pause"].opacity=@pauseopacity
|
||||
@sprites["back"].visible=@visible
|
||||
@sprites["contents"].visible=@visible && @openness==255
|
||||
@sprites["pause"].visible=@visible && @pause
|
||||
@sprites["cursor"].visible=@visible && @openness==255
|
||||
hascontents=(@contents && !@contents.disposed?)
|
||||
@sprites["scroll0"].visible = @visible && hascontents && @oy > 0
|
||||
@sprites["scroll1"].visible = @visible && hascontents && @ox > 0
|
||||
@sprites["scroll2"].visible = @visible && hascontents &&
|
||||
(@contents.width - @ox) > @width-32
|
||||
@sprites["scroll3"].visible = @visible && hascontents &&
|
||||
(@contents.height - @oy) > @height-32
|
||||
else
|
||||
for i in 0...4
|
||||
@sprites["corner#{i}"].visible=false
|
||||
@sprites["side#{i}"].visible=false
|
||||
@sprites["scroll#{i}"].visible=false
|
||||
end
|
||||
@sprites["contents"].visible=@visible && @openness==255
|
||||
@sprites["contents"].color=@color
|
||||
@sprites["contents"].tone=@tone
|
||||
@sprites["contents"].blend_type=@contents_blend_type
|
||||
@sprites["contents"].opacity=contopac
|
||||
@sprites["back"].visible=false
|
||||
@sprites["pause"].visible=false
|
||||
@sprites["cursor"].visible=false
|
||||
end
|
||||
for i in @sprites
|
||||
i[1].z=@z
|
||||
end
|
||||
if @rpgvx
|
||||
@sprites["cursor"].z=@z # For Compatibility
|
||||
@sprites["contents"].z=@z # For Compatibility
|
||||
@sprites["pause"].z=@z # For Compatibility
|
||||
else
|
||||
@sprites["cursor"].z=@z+1 # For Compatibility
|
||||
@sprites["contents"].z=@z+2 # For Compatibility
|
||||
@sprites["pause"].z=@z+2 # For Compatibility
|
||||
end
|
||||
if @rpgvx
|
||||
trimX=64
|
||||
trimY=0
|
||||
backRect=Rect.new(0,0,64,64)
|
||||
blindsRect=Rect.new(0,64,64,64)
|
||||
else
|
||||
trimX=128
|
||||
trimY=0
|
||||
backRect=Rect.new(0,0,128,128)
|
||||
blindsRect=nil
|
||||
end
|
||||
@sprites["corner0"].src_rect.set(trimX,trimY+0,16,16);
|
||||
@sprites["corner1"].src_rect.set(trimX+48,trimY+0,16,16);
|
||||
@sprites["corner2"].src_rect.set(trimX,trimY+48,16,16);
|
||||
@sprites["corner3"].src_rect.set(trimX+48,trimY+48,16,16);
|
||||
@sprites["scroll0"].src_rect.set(trimX+24, trimY+16, 16, 8) # up
|
||||
@sprites["scroll3"].src_rect.set(trimX+24, trimY+40, 16, 8) # down
|
||||
@sprites["scroll1"].src_rect.set(trimX+16, trimY+24, 8, 16) # left
|
||||
@sprites["scroll2"].src_rect.set(trimX+40, trimY+24, 8, 16) # right
|
||||
cursorX=trimX
|
||||
cursorY=trimY+64
|
||||
sideRects=[
|
||||
Rect.new(trimX+16,trimY+0,32,16),
|
||||
Rect.new(trimX,trimY+16,16,32),
|
||||
Rect.new(trimX+48,trimY+16,16,32),
|
||||
Rect.new(trimX+16,trimY+48,32,16)
|
||||
]
|
||||
if @width>32 && @height>32
|
||||
@sprites["contents"].src_rect.set(@ox,@oy,@width-32,@height-32)
|
||||
else
|
||||
@sprites["contents"].src_rect.set(0,0,0,0)
|
||||
end
|
||||
pauseRects=[
|
||||
trimX+32,trimY+64,
|
||||
trimX+48,trimY+64,
|
||||
trimX+32,trimY+80,
|
||||
trimX+48,trimY+80,
|
||||
]
|
||||
pauseWidth=16
|
||||
pauseHeight=16
|
||||
@sprites["pause"].src_rect.set(
|
||||
pauseRects[@pauseframe*2],
|
||||
pauseRects[@pauseframe*2+1],
|
||||
pauseWidth,pauseHeight
|
||||
)
|
||||
@sprites["pause"].x=@x+(@width/2)-(pauseWidth/2)
|
||||
@sprites["pause"].y=@y+@height-16 # 16 refers to skin margin
|
||||
@sprites["contents"].x=@x+16
|
||||
@sprites["contents"].y=@y+16
|
||||
@sprites["corner0"].x=@x
|
||||
@sprites["corner0"].y=@y
|
||||
@sprites["corner1"].x=@x+@width-16
|
||||
@sprites["corner1"].y=@y
|
||||
@sprites["corner2"].x=@x
|
||||
@sprites["corner2"].y=@y+@height-16
|
||||
@sprites["corner3"].x=@x+@width-16
|
||||
@sprites["corner3"].y=@y+@height-16
|
||||
@sprites["side0"].x=@x+16
|
||||
@sprites["side0"].y=@y
|
||||
@sprites["side1"].x=@x
|
||||
@sprites["side1"].y=@y+16
|
||||
@sprites["side2"].x=@x+@width-16
|
||||
@sprites["side2"].y=@y+16
|
||||
@sprites["side3"].x=@x+16
|
||||
@sprites["side3"].y=@y+@height-16
|
||||
@sprites["scroll0"].x = @x+@width / 2 - 8
|
||||
@sprites["scroll0"].y = @y+8
|
||||
@sprites["scroll1"].x = @x+8
|
||||
@sprites["scroll1"].y = @y+@height / 2 - 8
|
||||
@sprites["scroll2"].x = @x+@width - 16
|
||||
@sprites["scroll2"].y = @y+@height / 2 - 8
|
||||
@sprites["scroll3"].x = @x+@width / 2 - 8
|
||||
@sprites["scroll3"].y = @y+@height - 16
|
||||
@sprites["back"].x=@x+2
|
||||
@sprites["back"].y=@y+2
|
||||
@sprites["cursor"].x=@x+16+@cursor_rect.x
|
||||
@sprites["cursor"].y=@y+16+@cursor_rect.y
|
||||
if changeBitmap && @_windowskin && !@_windowskin.disposed?
|
||||
width=@cursor_rect.width
|
||||
height=@cursor_rect.height
|
||||
if width > 0 && height > 0
|
||||
cursorrects=[
|
||||
# sides
|
||||
Rect.new(cursorX+2, cursorY+0, 28, 2),
|
||||
Rect.new(cursorX+0, cursorY+2, 2, 28),
|
||||
Rect.new(cursorX+30, cursorY+2, 2, 28),
|
||||
Rect.new(cursorX+2, cursorY+30, 28, 2),
|
||||
# corners
|
||||
Rect.new(cursorX+0, cursorY+0, 2, 2),
|
||||
Rect.new(cursorX+30, cursorY+0, 2, 2),
|
||||
Rect.new(cursorX+0, cursorY+30, 2, 2),
|
||||
Rect.new(cursorX+30, cursorY+30, 2, 2),
|
||||
# back
|
||||
Rect.new(cursorX+2, cursorY+2, 28, 28)
|
||||
]
|
||||
margin=2
|
||||
fullmargin=4
|
||||
@cursorbitmap = ensureBitmap(@cursorbitmap, width, height)
|
||||
@cursorbitmap.clear
|
||||
@sprites["cursor"].bitmap=@cursorbitmap
|
||||
@sprites["cursor"].src_rect.set(0,0,width,height)
|
||||
rect = Rect.new(margin,margin,
|
||||
width - fullmargin, height - fullmargin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[8])
|
||||
@cursorbitmap.blt(0, 0, @_windowskin, cursorrects[4])# top left
|
||||
@cursorbitmap.blt(width-margin, 0, @_windowskin, cursorrects[5]) # top right
|
||||
@cursorbitmap.blt(0, height-margin, @_windowskin, cursorrects[6]) # bottom right
|
||||
@cursorbitmap.blt(width-margin, height-margin, @_windowskin, cursorrects[7]) # bottom left
|
||||
rect = Rect.new(margin, 0,
|
||||
width - fullmargin, margin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[0])
|
||||
rect = Rect.new(0, margin,
|
||||
margin, height - fullmargin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[1])
|
||||
rect = Rect.new(width - margin, margin,
|
||||
margin, height - fullmargin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[2])
|
||||
rect = Rect.new(margin, height-margin,
|
||||
width - fullmargin, margin)
|
||||
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[3])
|
||||
else
|
||||
@sprites["cursor"].visible=false
|
||||
@sprites["cursor"].src_rect.set(0,0,0,0)
|
||||
end
|
||||
for i in 0...4
|
||||
dwidth = (i==0 || i==3) ? @width-32 : 16
|
||||
dheight = (i==0 || i==3) ? 16 : @height-32
|
||||
@sidebitmaps[i]=ensureBitmap(@sidebitmaps[i],dwidth,dheight)
|
||||
@sprites["side#{i}"].bitmap=@sidebitmaps[i]
|
||||
@sprites["side#{i}"].src_rect.set(0,0,dwidth,dheight)
|
||||
@sidebitmaps[i].clear
|
||||
if sideRects[i].width>0 && sideRects[i].height>0
|
||||
@sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect,
|
||||
@_windowskin,sideRects[i])
|
||||
end
|
||||
end
|
||||
backwidth=@width-4
|
||||
backheight=@height-4
|
||||
if backwidth>0 && backheight>0
|
||||
@backbitmap=ensureBitmap(@backbitmap,backwidth,backheight)
|
||||
@sprites["back"].bitmap=@backbitmap
|
||||
@sprites["back"].src_rect.set(0,0,backwidth,backheight)
|
||||
@backbitmap.clear
|
||||
if @stretch
|
||||
@backbitmap.stretch_blt(@sprites["back"].src_rect,@_windowskin,backRect)
|
||||
else
|
||||
tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,backRect)
|
||||
end
|
||||
if blindsRect
|
||||
tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,blindsRect)
|
||||
end
|
||||
else
|
||||
@sprites["back"].visible=false
|
||||
@sprites["back"].src_rect.set(0,0,0,0)
|
||||
end
|
||||
end
|
||||
if @openness!=255
|
||||
opn=@openness/255.0
|
||||
for k in @spritekeys
|
||||
sprite=@sprites[k]
|
||||
ratio=(@height<=0) ? 0 : (sprite.y-@y)*1.0/@height
|
||||
sprite.zoom_y=opn
|
||||
sprite.oy=0
|
||||
sprite.y=(@y+(@height/2.0)+(@height*ratio*opn)-(@height/2*opn)).floor
|
||||
end
|
||||
else
|
||||
for k in @spritekeys
|
||||
sprite=@sprites[k]
|
||||
sprite.zoom_y=1.0
|
||||
end
|
||||
end
|
||||
i=0
|
||||
# Ensure Z order
|
||||
for k in @spritekeys
|
||||
sprite=@sprites[k]
|
||||
y=sprite.y
|
||||
sprite.y=i
|
||||
sprite.oy=(sprite.zoom_y<=0) ? 0 : (i-y)/sprite.zoom_y
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,781 @@
|
||||
module MessageConfig
|
||||
FontName = "Power Green"
|
||||
# in Graphics/Windowskins/ (specify empty string to use the default windowskin)
|
||||
TextSkinName = "speech hgss 1"
|
||||
ChoiceSkinName = "choice 1"
|
||||
WindowOpacity = 255
|
||||
TextSpeed = nil # can be positive to wait frames or negative to
|
||||
# show multiple characters in a single frame
|
||||
LIGHTTEXTBASE = Color.new(248,248,248)
|
||||
LIGHTTEXTSHADOW = Color.new(72,80,88)
|
||||
DARKTEXTBASE = Color.new(80,80,88)
|
||||
DARKTEXTSHADOW = Color.new(160,160,168)
|
||||
# 0 = Pause cursor is displayed at end of text
|
||||
# 1 = Pause cursor is displayed at bottom right
|
||||
# 2 = Pause cursor is displayed at lower middle side
|
||||
CURSORMODE = 1
|
||||
FontSubstitutes = {
|
||||
"Power Red and Blue" => "Pokemon RS",
|
||||
"Power Red and Green" => "Pokemon FireLeaf",
|
||||
"Power Green" => "Pokemon Emerald",
|
||||
"Power Green Narrow" => "Pokemon Emerald Narrow",
|
||||
"Power Green Small" => "Pokemon Emerald Small",
|
||||
"Power Clear" => "Pokemon DP"
|
||||
}
|
||||
@@systemFrame = nil
|
||||
@@defaultTextSkin = nil
|
||||
@@systemFont = nil
|
||||
@@textSpeed = nil
|
||||
|
||||
def self.pbTryFonts(*args)
|
||||
for a in args
|
||||
if a && a.is_a?(String)
|
||||
return a if Font.exist?(a)
|
||||
a=MessageConfig::FontSubstitutes[a] || a
|
||||
return a if Font.exist?(a)
|
||||
elsif a && a.is_a?(Array)
|
||||
for aa in a
|
||||
ret=MessageConfig.pbTryFonts(aa)
|
||||
return ret if ret!=""
|
||||
end
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
def self.pbDefaultSystemFrame
|
||||
return "" if !MessageConfig::ChoiceSkinName
|
||||
return pbResolveBitmap("Graphics/Windowskins/"+MessageConfig::ChoiceSkinName) || ""
|
||||
end
|
||||
|
||||
def self.pbDefaultSpeechFrame
|
||||
return "" if !MessageConfig::TextSkinName
|
||||
return pbResolveBitmap("Graphics/Windowskins/"+MessageConfig::TextSkinName) || ""
|
||||
end
|
||||
|
||||
def self.pbDefaultSystemFontName
|
||||
return MessageConfig.pbTryFonts(MessageConfig::FontName,"Arial Narrow","Arial")
|
||||
end
|
||||
|
||||
def self.pbDefaultTextSpeed
|
||||
return (TextSpeed) ? TextSpeed : (Graphics.width>400) ? -2 : 1
|
||||
end
|
||||
|
||||
def self.pbDefaultWindowskin
|
||||
skin=load_data("Data/System.rxdata").windowskin_name rescue nil
|
||||
if skin && skin!=""
|
||||
skin=pbResolveBitmap("Graphics/Windowskins/"+skin) || ""
|
||||
end
|
||||
skin=pbResolveBitmap("Graphics/System/Window") if !skin || skin==""
|
||||
skin=pbResolveBitmap("Graphics/Windowskins/001-Blue01") if !skin || skin==""
|
||||
return skin || ""
|
||||
end
|
||||
|
||||
def self.pbGetSystemFrame
|
||||
if !@@systemFrame
|
||||
skin=MessageConfig.pbDefaultSystemFrame
|
||||
skin=MessageConfig.pbDefaultWindowskin if !skin || skin==""
|
||||
@@systemFrame=skin || ""
|
||||
end
|
||||
return @@systemFrame
|
||||
end
|
||||
|
||||
def self.pbGetSpeechFrame
|
||||
if !@@defaultTextSkin
|
||||
skin=MessageConfig.pbDefaultSpeechFrame
|
||||
skin=MessageConfig.pbDefaultWindowskin if !skin || skin==""
|
||||
@@defaultTextSkin=skin || ""
|
||||
end
|
||||
return @@defaultTextSkin
|
||||
end
|
||||
|
||||
def self.pbGetSystemFontName
|
||||
@@systemFont=pbDefaultSystemFontName if !@@systemFont
|
||||
return @@systemFont
|
||||
end
|
||||
|
||||
def self.pbGetTextSpeed
|
||||
@@textSpeed=pbDefaultTextSpeed if !@@textSpeed
|
||||
return @@textSpeed
|
||||
end
|
||||
|
||||
def self.pbSetSystemFrame(value)
|
||||
@@systemFrame=pbResolveBitmap(value) || ""
|
||||
end
|
||||
|
||||
def self.pbSetSpeechFrame(value)
|
||||
@@defaultTextSkin=pbResolveBitmap(value) || ""
|
||||
end
|
||||
|
||||
def self.pbSetSystemFontName(value)
|
||||
@@systemFont=MessageConfig.pbTryFonts(value,"Arial Narrow","Arial")
|
||||
end
|
||||
|
||||
def self.pbSetTextSpeed(value)
|
||||
@@textSpeed=value
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Position a window
|
||||
#===============================================================================
|
||||
def pbBottomRight(window)
|
||||
window.x=Graphics.width-window.width
|
||||
window.y=Graphics.height-window.height
|
||||
end
|
||||
|
||||
def pbBottomLeft(window)
|
||||
window.x=0
|
||||
window.y=Graphics.height-window.height
|
||||
end
|
||||
|
||||
def pbBottomLeftLines(window,lines,width=nil)
|
||||
window.x=0
|
||||
window.width=width ? width : Graphics.width
|
||||
window.height=(window.borderY rescue 32)+lines*32
|
||||
window.y=Graphics.height-window.height
|
||||
end
|
||||
|
||||
def pbPositionFaceWindow(facewindow,msgwindow)
|
||||
return if !facewindow
|
||||
if msgwindow
|
||||
if facewindow.height<=msgwindow.height
|
||||
facewindow.y=msgwindow.y
|
||||
else
|
||||
facewindow.y=msgwindow.y+msgwindow.height-facewindow.height
|
||||
end
|
||||
facewindow.x=Graphics.width-facewindow.width
|
||||
msgwindow.x=0
|
||||
msgwindow.width=Graphics.width-facewindow.width
|
||||
else
|
||||
facewindow.height=Graphics.height if facewindow.height>Graphics.height
|
||||
facewindow.x=0
|
||||
facewindow.y=0
|
||||
end
|
||||
end
|
||||
|
||||
def pbPositionNearMsgWindow(cmdwindow,msgwindow,side)
|
||||
return if !cmdwindow
|
||||
if msgwindow
|
||||
height=[cmdwindow.height,Graphics.height-msgwindow.height].min
|
||||
if cmdwindow.height!=height
|
||||
cmdwindow.height=height
|
||||
end
|
||||
cmdwindow.y=msgwindow.y-cmdwindow.height
|
||||
if cmdwindow.y<0
|
||||
cmdwindow.y=msgwindow.y+msgwindow.height
|
||||
if cmdwindow.y+cmdwindow.height>Graphics.height
|
||||
cmdwindow.y=msgwindow.y-cmdwindow.height
|
||||
end
|
||||
end
|
||||
case side
|
||||
when :left
|
||||
cmdwindow.x=msgwindow.x
|
||||
when :right
|
||||
cmdwindow.x=msgwindow.x+msgwindow.width-cmdwindow.width
|
||||
else
|
||||
cmdwindow.x=msgwindow.x+msgwindow.width-cmdwindow.width
|
||||
end
|
||||
else
|
||||
cmdwindow.height=Graphics.height if cmdwindow.height>Graphics.height
|
||||
cmdwindow.x=0
|
||||
cmdwindow.y=0
|
||||
end
|
||||
end
|
||||
|
||||
# internal function
|
||||
def pbRepositionMessageWindow(msgwindow, linecount=2)
|
||||
msgwindow.height=32*linecount+msgwindow.borderY
|
||||
msgwindow.y=(Graphics.height)-(msgwindow.height)
|
||||
if $game_system && $game_system.respond_to?("message_position")
|
||||
case $game_system.message_position
|
||||
when 0 # up
|
||||
msgwindow.y=0
|
||||
when 1 # middle
|
||||
msgwindow.y=(Graphics.height/2)-(msgwindow.height/2)
|
||||
when 2
|
||||
msgwindow.y=(Graphics.height)-(msgwindow.height)
|
||||
end
|
||||
end
|
||||
if $game_system && $game_system.respond_to?("message_frame")
|
||||
if $game_system.message_frame != 0
|
||||
msgwindow.opacity = 0
|
||||
end
|
||||
end
|
||||
if $game_message
|
||||
case $game_message.background
|
||||
when 1; msgwindow.opacity=0 # dim
|
||||
when 2; msgwindow.opacity=0 # transparent
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# internal function
|
||||
def pbUpdateMsgWindowPos(msgwindow,event,eventChanged=false)
|
||||
if event
|
||||
if eventChanged
|
||||
msgwindow.resizeToFit2(msgwindow.text,Graphics.width*2/3,msgwindow.height)
|
||||
end
|
||||
msgwindow.y=event.screen_y-48-msgwindow.height
|
||||
if msgwindow.y<0
|
||||
msgwindow.y=event.screen_y+24
|
||||
end
|
||||
msgwindow.x=event.screen_x-(msgwindow.width/2)
|
||||
msgwindow.x=0 if msgwindow.x<0
|
||||
if msgwindow.x>Graphics.width-msgwindow.width
|
||||
msgwindow.x=Graphics.width-msgwindow.width
|
||||
end
|
||||
else
|
||||
curwidth=msgwindow.width
|
||||
if curwidth!=Graphics.width
|
||||
msgwindow.width=Graphics.width
|
||||
msgwindow.width=Graphics.width
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Determine the colour of a background
|
||||
#===============================================================================
|
||||
def isDarkBackground(background,rect=nil)
|
||||
return true if !background || background.disposed?
|
||||
rect = background.rect if !rect
|
||||
return true if rect.width<=0 || rect.height<=0
|
||||
xSeg = (rect.width/16)
|
||||
xLoop = (xSeg==0) ? 1 : 16
|
||||
xStart = (xSeg==0) ? rect.x+(rect.width/2) : rect.x+xSeg/2
|
||||
ySeg = (rect.height/16)
|
||||
yLoop = (ySeg==0) ? 1 : 16
|
||||
yStart = (ySeg==0) ? rect.y+(rect.height/2) : rect.y+ySeg/2
|
||||
count = 0
|
||||
y = yStart
|
||||
r = 0; g = 0; b = 0
|
||||
yLoop.times do
|
||||
x = xStart
|
||||
xLoop.times do
|
||||
clr = background.get_pixel(x,y)
|
||||
if clr.alpha!=0
|
||||
r += clr.red
|
||||
g += clr.green
|
||||
b += clr.blue
|
||||
count += 1
|
||||
end
|
||||
x += xSeg
|
||||
end
|
||||
y += ySeg
|
||||
end
|
||||
return true if count==0
|
||||
r /= count
|
||||
g /= count
|
||||
b /= count
|
||||
return (r*0.299+g*0.587+b*0.114)<160
|
||||
end
|
||||
|
||||
def isDarkWindowskin(windowskin)
|
||||
return true if !windowskin || windowskin.disposed?
|
||||
if windowskin.width==192 && windowskin.height==128
|
||||
return isDarkBackground(windowskin,Rect.new(0,0,128,128))
|
||||
elsif windowskin.width==128 && windowskin.height==128
|
||||
return isDarkBackground(windowskin,Rect.new(0,0,64,64))
|
||||
elsif windowskin.width==96 && windowskin.height==48
|
||||
return isDarkBackground(windowskin,Rect.new(32,16,16,16))
|
||||
else
|
||||
clr = windowskin.get_pixel(windowskin.width/2, windowskin.height/2)
|
||||
return (clr.red*0.299+clr.green*0.587+clr.blue*0.114)<160
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Determine which text colours to use based on the darkness of the background
|
||||
#===============================================================================
|
||||
def getSkinColor(windowskin,color,isDarkSkin)
|
||||
if !windowskin || windowskin.disposed? ||
|
||||
windowskin.width!=128 || windowskin.height!=128
|
||||
# Base color, shadow color (these are reversed on dark windowskins)
|
||||
textcolors = [
|
||||
"0070F8","78B8E8", # 1 Blue
|
||||
"E82010","F8A8B8", # 2 Red
|
||||
"60B048","B0D090", # 3 Green
|
||||
"48D8D8","A8E0E0", # 4 Cyan
|
||||
"D038B8","E8A0E0", # 5 Magenta
|
||||
"E8D020","F8E888", # 6 Yellow
|
||||
"A0A0A8","D0D0D8", # 7 Grey
|
||||
"F0F0F8","C8C8D0", # 8 White
|
||||
"9040E8","B8A8E0", # 9 Purple
|
||||
"F89818","F8C898", # 10 Orange
|
||||
colorToRgb32(MessageConfig::DARKTEXTBASE),
|
||||
colorToRgb32(MessageConfig::DARKTEXTSHADOW), # 11 Dark default
|
||||
colorToRgb32(MessageConfig::LIGHTTEXTBASE),
|
||||
colorToRgb32(MessageConfig::LIGHTTEXTSHADOW) # 12 Light default
|
||||
]
|
||||
if color==0 || color>textcolors.length/2 # No special colour, use default
|
||||
if isDarkSkin # Dark background, light text
|
||||
return shadowc3tag(MessageConfig::LIGHTTEXTBASE,MessageConfig::LIGHTTEXTSHADOW)
|
||||
end
|
||||
# Light background, dark text
|
||||
return shadowc3tag(MessageConfig::DARKTEXTBASE,MessageConfig::DARKTEXTSHADOW)
|
||||
end
|
||||
# Special colour as listed above
|
||||
if isDarkSkin && color!=12 # Dark background, light text
|
||||
return sprintf("<c3=%s,%s>",textcolors[2*(color-1)+1],textcolors[2*(color-1)])
|
||||
end
|
||||
# Light background, dark text
|
||||
return sprintf("<c3=%s,%s>",textcolors[2*(color-1)],textcolors[2*(color-1)+1])
|
||||
else # VX windowskin
|
||||
color = 0 if color>=32
|
||||
x = 64 + (color % 8) * 8
|
||||
y = 96 + (color / 8) * 8
|
||||
pixel = windowskin.get_pixel(x, y)
|
||||
return shadowctagFromColor(pixel)
|
||||
end
|
||||
end
|
||||
|
||||
def getDefaultTextColors(windowskin)
|
||||
if !windowskin || windowskin.disposed? ||
|
||||
windowskin.width!=128 || windowskin.height!=128
|
||||
if isDarkWindowskin(windowskin)
|
||||
return [MessageConfig::LIGHTTEXTBASE,MessageConfig::LIGHTTEXTSHADOW] # White
|
||||
else
|
||||
return [MessageConfig::DARKTEXTBASE,MessageConfig::DARKTEXTSHADOW] # Dark gray
|
||||
end
|
||||
else # VX windowskin
|
||||
color = windowskin.get_pixel(64, 96)
|
||||
shadow = nil
|
||||
isDark = (color.red+color.green+color.blue)/3 < 128
|
||||
if isDark
|
||||
shadow = Color.new(color.red+64,color.green+64,color.blue+64)
|
||||
else
|
||||
shadow = Color.new(color.red-64,color.green-64,color.blue-64)
|
||||
end
|
||||
return [color,shadow]
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Makes sure a bitmap exists
|
||||
#===============================================================================
|
||||
def pbDoEnsureBitmap(bitmap,dwidth,dheight)
|
||||
if !bitmap || bitmap.disposed? || bitmap.width<dwidth || bitmap.height<dheight
|
||||
oldfont = (bitmap && !bitmap.disposed?) ? bitmap.font : nil
|
||||
bitmap.dispose if bitmap
|
||||
bitmap = Bitmap.new([1,dwidth].max,[1,dheight].max)
|
||||
(oldfont) ? bitmap.font = oldfont : pbSetSystemFont(bitmap)
|
||||
bitmap.font.shadow = false if bitmap.font && bitmap.font.respond_to?("shadow")
|
||||
end
|
||||
return bitmap
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Set a bitmap's font
|
||||
#===============================================================================
|
||||
# Gets the name of the system small font.
|
||||
def pbSmallFontName
|
||||
return MessageConfig.pbTryFonts("Power Green Small","Pokemon Emerald Small",
|
||||
"Arial Narrow","Arial")
|
||||
end
|
||||
|
||||
# Gets the name of the system narrow font.
|
||||
def pbNarrowFontName
|
||||
return MessageConfig.pbTryFonts("Power Green Narrow","Pokemon Emerald Narrow",
|
||||
"Arial Narrow","Arial")
|
||||
end
|
||||
|
||||
# Sets a bitmap's font to the system font.
|
||||
def pbSetSystemFont(bitmap)
|
||||
fontname=MessageConfig.pbGetSystemFontName
|
||||
bitmap.font.name=fontname
|
||||
if fontname=="Pokemon FireLeaf" || fontname=="Power Red and Green"
|
||||
bitmap.font.size=29
|
||||
elsif fontname=="Pokemon Emerald Small" || fontname=="Power Green Small"
|
||||
bitmap.font.size=25
|
||||
else
|
||||
bitmap.font.size=31
|
||||
end
|
||||
end
|
||||
|
||||
# Sets a bitmap's font to the system small font.
|
||||
def pbSetSmallFont(bitmap)
|
||||
bitmap.font.name=pbSmallFontName
|
||||
bitmap.font.size=25
|
||||
end
|
||||
|
||||
# Sets a bitmap's font to the system narrow font.
|
||||
def pbSetNarrowFont(bitmap)
|
||||
bitmap.font.name=pbNarrowFontName
|
||||
bitmap.font.size=31
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Blend colours, set the colour of all bitmaps in a sprite hash
|
||||
#===============================================================================
|
||||
def pbAlphaBlend(dstColor,srcColor)
|
||||
r=(255*(srcColor.red-dstColor.red)/255)+dstColor.red
|
||||
g=(255*(srcColor.green-dstColor.green)/255)+dstColor.green
|
||||
b=(255*(srcColor.blue-dstColor.blue)/255)+dstColor.blue
|
||||
a=(255*(srcColor.alpha-dstColor.alpha)/255)+dstColor.alpha
|
||||
return Color.new(r,g,b,a)
|
||||
end
|
||||
|
||||
def pbSrcOver(dstColor,srcColor)
|
||||
er=srcColor.red*srcColor.alpha/255
|
||||
eg=srcColor.green*srcColor.alpha/255
|
||||
eb=srcColor.blue*srcColor.alpha/255
|
||||
iea=255-srcColor.alpha
|
||||
cr=dstColor.red*dstColor.alpha/255
|
||||
cg=dstColor.green*dstColor.alpha/255
|
||||
cb=dstColor.blue*dstColor.alpha/255
|
||||
ica=255-dstColor.alpha
|
||||
a=255-(iea*ica)/255
|
||||
r=(iea*cr)/255+er
|
||||
g=(iea*cg)/255+eg
|
||||
b=(iea*cb)/255+eb
|
||||
r=(a==0) ? 0 : r*255/a
|
||||
g=(a==0) ? 0 : g*255/a
|
||||
b=(a==0) ? 0 : b*255/a
|
||||
return Color.new(r,g,b,a)
|
||||
end
|
||||
|
||||
def pbSetSpritesToColor(sprites,color)
|
||||
return if !sprites || !color
|
||||
colors={}
|
||||
for i in sprites
|
||||
next if !i[1] || pbDisposed?(i[1])
|
||||
colors[i[0]]=i[1].color.clone
|
||||
i[1].color=pbSrcOver(i[1].color,color)
|
||||
end
|
||||
Graphics.update
|
||||
Input.update
|
||||
for i in colors
|
||||
next if !sprites[i[0]]
|
||||
sprites[i[0]].color=i[1]
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Update and dispose sprite hashes
|
||||
#===============================================================================
|
||||
def using(window)
|
||||
begin
|
||||
yield if block_given?
|
||||
ensure
|
||||
window.dispose
|
||||
end
|
||||
end
|
||||
|
||||
def pbUpdateSpriteHash(windows)
|
||||
for i in windows
|
||||
window=i[1]
|
||||
if window
|
||||
if window.is_a?(Sprite) || window.is_a?(Window)
|
||||
window.update if !pbDisposed?(window)
|
||||
elsif window.is_a?(Plane)
|
||||
begin
|
||||
window.update if !window.disposed?
|
||||
rescue NoMethodError
|
||||
end
|
||||
elsif window.respond_to?("update")
|
||||
begin
|
||||
window.update
|
||||
rescue RGSSError
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Disposes all objects in the specified hash.
|
||||
def pbDisposeSpriteHash(sprites)
|
||||
return if !sprites
|
||||
for i in sprites.keys
|
||||
pbDisposeSprite(sprites,i)
|
||||
end
|
||||
sprites.clear
|
||||
end
|
||||
|
||||
# Disposes the specified graphics object within the specified hash. Basically
|
||||
# like: sprites[id].dispose
|
||||
def pbDisposeSprite(sprites,id)
|
||||
sprite = sprites[id]
|
||||
sprite.dispose if sprite && !pbDisposed?(sprite)
|
||||
sprites[id] = nil
|
||||
end
|
||||
|
||||
def pbDisposed?(x)
|
||||
return true if !x
|
||||
return x.disposed? if !x.is_a?(Viewport)
|
||||
begin
|
||||
x.rect = x.rect
|
||||
rescue
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Fades and window activations for sprite hashes
|
||||
#===============================================================================
|
||||
class Game_Temp
|
||||
attr_accessor :fadestate
|
||||
|
||||
def fadestate
|
||||
return (@fadestate) ? @fadestate : 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbPushFade
|
||||
$game_temp.fadestate = [$game_temp.fadestate+1,0].max if $game_temp
|
||||
end
|
||||
|
||||
def pbPopFade
|
||||
$game_temp.fadestate = [$game_temp.fadestate-1,0].max if $game_temp
|
||||
end
|
||||
|
||||
def pbIsFaded?
|
||||
return ($game_temp) ? $game_temp.fadestate>0 : false
|
||||
end
|
||||
|
||||
# pbFadeOutIn(z) { block }
|
||||
# Fades out the screen before a block is run and fades it back in after the
|
||||
# block exits. z indicates the z-coordinate of the viewport used for this effect
|
||||
def pbFadeOutIn(z=99999,nofadeout=false)
|
||||
col=Color.new(0,0,0,0)
|
||||
viewport=Viewport.new(0,0,Graphics.width,Graphics.height)
|
||||
viewport.z=z
|
||||
numFrames = (Graphics.frame_rate*0.4).floor
|
||||
alphaDiff = (255.0/numFrames).ceil
|
||||
for j in 0..numFrames
|
||||
col.set(0,0,0,j*alphaDiff)
|
||||
viewport.color=col
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
pbPushFade
|
||||
begin
|
||||
yield if block_given?
|
||||
ensure
|
||||
pbPopFade
|
||||
if !nofadeout
|
||||
for j in 0..numFrames
|
||||
col.set(0,0,0,(numFrames-j)*alphaDiff)
|
||||
viewport.color=col
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
end
|
||||
viewport.dispose
|
||||
end
|
||||
end
|
||||
|
||||
def pbFadeOutInWithUpdate(z,sprites,nofadeout=false)
|
||||
col=Color.new(0,0,0,0)
|
||||
viewport=Viewport.new(0,0,Graphics.width,Graphics.height)
|
||||
viewport.z=z
|
||||
numFrames = (Graphics.frame_rate*0.4).floor
|
||||
alphaDiff = (255.0/numFrames).ceil
|
||||
for j in 0..numFrames
|
||||
col.set(0,0,0,j*alphaDiff)
|
||||
viewport.color=col
|
||||
pbUpdateSpriteHash(sprites)
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
pbPushFade
|
||||
begin
|
||||
yield if block_given?
|
||||
ensure
|
||||
pbPopFade
|
||||
if !nofadeout
|
||||
for j in 0..numFrames
|
||||
col.set(0,0,0,(numFrames-j)*alphaDiff)
|
||||
viewport.color=col
|
||||
pbUpdateSpriteHash(sprites)
|
||||
Graphics.update
|
||||
Input.update
|
||||
end
|
||||
end
|
||||
viewport.dispose
|
||||
end
|
||||
end
|
||||
|
||||
def pbFadeOutAndHide(sprites)
|
||||
visiblesprites = {}
|
||||
numFrames = (Graphics.frame_rate*0.4).floor
|
||||
alphaDiff = (255.0/numFrames).ceil
|
||||
pbDeactivateWindows(sprites) {
|
||||
for j in 0..numFrames
|
||||
pbSetSpritesToColor(sprites,Color.new(0,0,0,j*alphaDiff))
|
||||
(block_given?) ? yield : pbUpdateSpriteHash(sprites)
|
||||
end
|
||||
}
|
||||
for i in sprites
|
||||
next if !i[1]
|
||||
next if pbDisposed?(i[1])
|
||||
visiblesprites[i[0]] = true if i[1].visible
|
||||
i[1].visible = false
|
||||
end
|
||||
return visiblesprites
|
||||
end
|
||||
|
||||
def pbFadeInAndShow(sprites,visiblesprites=nil)
|
||||
if visiblesprites
|
||||
for i in visiblesprites
|
||||
if i[1] && sprites[i[0]] && !pbDisposed?(sprites[i[0]])
|
||||
sprites[i[0]].visible = true
|
||||
end
|
||||
end
|
||||
end
|
||||
numFrames = (Graphics.frame_rate*0.4).floor
|
||||
alphaDiff = (255.0/numFrames).ceil
|
||||
pbDeactivateWindows(sprites) {
|
||||
for j in 0..numFrames
|
||||
pbSetSpritesToColor(sprites,Color.new(0,0,0,((numFrames-j)*alphaDiff)))
|
||||
(block_given?) ? yield : pbUpdateSpriteHash(sprites)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# Restores which windows are active for the given sprite hash.
|
||||
# _activeStatuses_ is the result of a previous call to pbActivateWindows
|
||||
def pbRestoreActivations(sprites,activeStatuses)
|
||||
return if !sprites || !activeStatuses
|
||||
for k in activeStatuses.keys
|
||||
if sprites[k] && sprites[k].is_a?(Window) && !pbDisposed?(sprites[k])
|
||||
sprites[k].active=activeStatuses[k] ? true : false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Deactivates all windows. If a code block is given, deactivates all windows,
|
||||
# runs the code in the block, and reactivates them.
|
||||
def pbDeactivateWindows(sprites)
|
||||
if block_given?
|
||||
pbActivateWindow(sprites,nil) { yield }
|
||||
else
|
||||
pbActivateWindow(sprites,nil)
|
||||
end
|
||||
end
|
||||
|
||||
# Activates a specific window of a sprite hash. _key_ is the key of the window
|
||||
# in the sprite hash. If a code block is given, deactivates all windows except
|
||||
# the specified window, runs the code in the block, and reactivates them.
|
||||
def pbActivateWindow(sprites,key)
|
||||
return if !sprites
|
||||
activeStatuses={}
|
||||
for i in sprites
|
||||
if i[1] && i[1].is_a?(Window) && !pbDisposed?(i[1])
|
||||
activeStatuses[i[0]]=i[1].active
|
||||
i[1].active=(i[0]==key)
|
||||
end
|
||||
end
|
||||
if block_given?
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
pbRestoreActivations(sprites,activeStatuses)
|
||||
end
|
||||
return {}
|
||||
else
|
||||
return activeStatuses
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Create background planes for a sprite hash
|
||||
#===============================================================================
|
||||
# Adds a background to the sprite hash.
|
||||
# _planename_ is the hash key of the background.
|
||||
# _background_ is a filename within the Graphics/Pictures/ folder and can be
|
||||
# an animated image.
|
||||
# _viewport_ is a viewport to place the background in.
|
||||
def addBackgroundPlane(sprites,planename,background,viewport=nil)
|
||||
sprites[planename]=AnimatedPlane.new(viewport)
|
||||
bitmapName=pbResolveBitmap("Graphics/Pictures/#{background}")
|
||||
if bitmapName==nil
|
||||
# Plane should exist in any case
|
||||
sprites[planename].bitmap=nil
|
||||
sprites[planename].visible=false
|
||||
else
|
||||
sprites[planename].setBitmap(bitmapName)
|
||||
for spr in sprites.values
|
||||
if spr.is_a?(Window)
|
||||
spr.windowskin=nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Adds a background to the sprite hash.
|
||||
# _planename_ is the hash key of the background.
|
||||
# _background_ is a filename within the Graphics/Pictures/ folder and can be
|
||||
# an animated image.
|
||||
# _color_ is the color to use if the background can't be found.
|
||||
# _viewport_ is a viewport to place the background in.
|
||||
def addBackgroundOrColoredPlane(sprites,planename,background,color,viewport=nil)
|
||||
bitmapName=pbResolveBitmap("Graphics/Pictures/#{background}")
|
||||
if bitmapName==nil
|
||||
# Plane should exist in any case
|
||||
sprites[planename]=ColoredPlane.new(color,@viewport)
|
||||
else
|
||||
sprites[planename]=AnimatedPlane.new(viewport)
|
||||
sprites[planename].setBitmap(bitmapName)
|
||||
for spr in sprites.values
|
||||
if spr.is_a?(Window)
|
||||
spr.windowskin=nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Ensure required method definitions
|
||||
#===============================================================================
|
||||
module Graphics
|
||||
if !self.respond_to?("width")
|
||||
def self.width; return 640; end
|
||||
end
|
||||
if !self.respond_to?("height")
|
||||
def self.height; return 480; end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
if !defined?(_INTL)
|
||||
def _INTL(*args)
|
||||
string=args[0].clone
|
||||
for i in 1...args.length
|
||||
string.gsub!(/\{#{i}\}/,"#{args[i]}")
|
||||
end
|
||||
return string
|
||||
end
|
||||
end
|
||||
|
||||
if !defined?(_ISPRINTF)
|
||||
def _ISPRINTF(*args)
|
||||
string=args[0].clone
|
||||
for i in 1...args.length
|
||||
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
|
||||
next sprintf("%"+$1,args[i])
|
||||
}
|
||||
end
|
||||
return string
|
||||
end
|
||||
end
|
||||
|
||||
if !defined?(_MAPINTL)
|
||||
def _MAPINTL(*args)
|
||||
string=args[1].clone
|
||||
for i in 2...args.length
|
||||
string.gsub!(/\{#{i}\}/,"#{args[i+1]}")
|
||||
end
|
||||
return string
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,709 @@
|
||||
def getCubicPoint2(src,t)
|
||||
x0 = src[0]; y0 = src[1]
|
||||
cx0 = src[2]; cy0 = src[3]
|
||||
cx1 = src[4]; cy1 = src[5]
|
||||
x1 = src[6]; y1 = src[7]
|
||||
|
||||
x1 = cx1+(x1-cx1)*t
|
||||
x0 = x0+(cx0-x0)*t
|
||||
cx0 = cx0+(cx1-cx0)*t
|
||||
cx1 = cx0+(x1-cx0)*t
|
||||
cx0 = x0+(cx0-x0)*t
|
||||
cx = cx0+(cx1-cx0)*t
|
||||
# a = x1 - 3 * cx1 + 3 * cx0 - x0
|
||||
# b = 3 * (cx1 - 2 * cx0 + x0)
|
||||
# c = 3 * (cx0 - x0)
|
||||
# d = x0
|
||||
# cx = a*t*t*t + b*t*t + c*t + d
|
||||
y1 = cy1+(y1-cy1)*t
|
||||
y0 = y0+(cy0-y0)*t
|
||||
cy0 = cy0+(cy1-cy0)*t
|
||||
cy1 = cy0+(y1-cy0)*t
|
||||
cy0 = y0+(cy0-y0)*t
|
||||
cy = cy0+(cy1-cy0)*t
|
||||
# a = y1 - 3 * cy1 + 3 * cy0 - y0
|
||||
# b = 3 * (cy1 - 2 * cy0 + y0)
|
||||
# c = 3 * (cy0 - y0)
|
||||
# d = y0
|
||||
# cy = a*t*t*t + b*t*t + c*t + d
|
||||
return [cx,cy]
|
||||
end
|
||||
|
||||
|
||||
|
||||
class Processes
|
||||
XY = 0
|
||||
DeltaXY = 1
|
||||
Z = 2
|
||||
Curve = 3
|
||||
Zoom = 4
|
||||
Angle = 5
|
||||
Tone = 6
|
||||
Color = 7
|
||||
Hue = 8
|
||||
Opacity = 9
|
||||
Visible = 10
|
||||
BlendType = 11
|
||||
SE = 12
|
||||
Name = 13
|
||||
Origin = 14
|
||||
Src = 15
|
||||
SrcSize = 16
|
||||
CropBottom = 17
|
||||
end
|
||||
|
||||
|
||||
|
||||
class PictureEx
|
||||
attr_accessor :x # x-coordinate
|
||||
attr_accessor :y # y-coordinate
|
||||
attr_accessor :z # z value
|
||||
attr_accessor :zoom_x # x directional zoom rate
|
||||
attr_accessor :zoom_y # y directional zoom rate
|
||||
attr_accessor :angle # rotation angle
|
||||
attr_accessor :tone # tone
|
||||
attr_accessor :color # color
|
||||
attr_accessor :hue # filename hue
|
||||
attr_accessor :opacity # opacity level
|
||||
attr_accessor :visible # visibility boolean
|
||||
attr_accessor :blend_type # blend method
|
||||
attr_accessor :name # file name
|
||||
attr_accessor :origin # starting point
|
||||
attr_reader :src_rect # source rect
|
||||
attr_reader :cropBottom # crops sprite to above this y-coordinate
|
||||
attr_reader :frameUpdates # Array of processes updated in a frame
|
||||
|
||||
def initialize(z)
|
||||
# process: [type, delay, total_duration, frame_counter, cb, etc.]
|
||||
@processes = []
|
||||
@x = 0.0
|
||||
@y = 0.0
|
||||
@z = z
|
||||
@zoom_x = 100.0
|
||||
@zoom_y = 100.0
|
||||
@angle = 0
|
||||
@rotate_speed = 0
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@tone_duration = 0
|
||||
@color = Color.new(0, 0, 0, 0)
|
||||
@hue = 0
|
||||
@opacity = 255.0
|
||||
@visible = true
|
||||
@blend_type = 0
|
||||
@name = ""
|
||||
@origin = PictureOrigin::TopLeft
|
||||
@src_rect = Rect.new(0,0,-1,-1)
|
||||
@cropBottom = -1
|
||||
@frameUpdates = []
|
||||
end
|
||||
|
||||
def callback(cb)
|
||||
if cb.is_a?(Proc); proc.call(self)
|
||||
elsif cb.is_a?(Array); cb[0].method(cb[1]).call(self)
|
||||
elsif cb.is_a?(Method); cb.call(self)
|
||||
end
|
||||
end
|
||||
|
||||
def setCallback(delay, cb=nil)
|
||||
delay = ensureDelayAndDuration(delay)
|
||||
@processes.push([nil,delay,0,0,cb])
|
||||
end
|
||||
|
||||
def running?
|
||||
return @processes.length>0
|
||||
end
|
||||
|
||||
def totalDuration
|
||||
ret = 0
|
||||
for process in @processes
|
||||
dur = process[1]+process[2]
|
||||
ret = dur if dur>ret
|
||||
end
|
||||
ret *= 20.0/Graphics.frame_rate
|
||||
return ret.to_i
|
||||
end
|
||||
|
||||
def ensureDelayAndDuration(delay, duration=nil)
|
||||
delay = self.totalDuration if delay<0
|
||||
delay *= Graphics.frame_rate/20.0
|
||||
if !duration.nil?
|
||||
duration *= Graphics.frame_rate/20.0
|
||||
return delay.to_i, duration.to_i
|
||||
end
|
||||
return delay.to_i
|
||||
end
|
||||
|
||||
def ensureDelay(delay)
|
||||
return ensureDelayAndDuration(delay)
|
||||
end
|
||||
|
||||
# speed is the angle to change by in 1/20 of a second. @rotate_speed is the
|
||||
# angle to change by per frame.
|
||||
# NOTE: This is not compatible with manually changing the angle at a certain
|
||||
# point. If you make a sprite auto-rotate, you should not try to alter
|
||||
# the angle another way too.
|
||||
def rotate(speed)
|
||||
@rotate_speed = speed*20.0/Graphics.frame_rate
|
||||
while @rotate_speed<0; @rotate_speed += 360; end
|
||||
@rotate_speed %= 360
|
||||
end
|
||||
|
||||
def erase
|
||||
self.name = ""
|
||||
end
|
||||
|
||||
def clearProcesses
|
||||
@processes = []
|
||||
end
|
||||
|
||||
def adjustPosition(xOffset, yOffset)
|
||||
for process in @processes
|
||||
next if process[0]!=Processes::XY
|
||||
process[5] += xOffset
|
||||
process[6] += yOffset
|
||||
process[7] += xOffset
|
||||
process[8] += yOffset
|
||||
end
|
||||
end
|
||||
|
||||
def move(delay, duration, origin, x, y, zoom_x=100.0, zoom_y=100.0, opacity=255)
|
||||
setOrigin(delay,duration,origin)
|
||||
moveXY(delay,duration,x,y)
|
||||
moveZoomXY(delay,duration,zoom_x,zoom_y)
|
||||
moveOpacity(delay,duration,opacity)
|
||||
end
|
||||
|
||||
def moveXY(delay, duration, x, y, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::XY,delay,duration,0,cb,@x,@y,x,y])
|
||||
end
|
||||
|
||||
def setXY(delay, x, y, cb=nil)
|
||||
moveXY(delay,0,x,y,cb)
|
||||
end
|
||||
|
||||
def moveCurve(delay, duration, x1, y1, x2, y2, x3, y3, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Curve,delay,duration,0,cb,[@x,@y,x1,y1,x2,y2,x3,y3]])
|
||||
end
|
||||
|
||||
def moveDelta(delay, duration, x, y, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::DeltaXY,delay,duration,0,cb,@x,@y,x,y])
|
||||
end
|
||||
|
||||
def setDelta(delay, x, y, cb=nil)
|
||||
moveDelta(delay,0,x,y,cb)
|
||||
end
|
||||
|
||||
def moveZ(delay, duration, z, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Z,delay,duration,0,cb,@z,z])
|
||||
end
|
||||
|
||||
def setZ(delay, z, cb=nil)
|
||||
moveZ(delay,0,z,cb)
|
||||
end
|
||||
|
||||
def moveZoomXY(delay, duration, zoom_x, zoom_y, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Zoom,delay,duration,0,cb,@zoom_x,@zoom_y,zoom_x,zoom_y])
|
||||
end
|
||||
|
||||
def setZoomXY(delay, zoom_x, zoom_y, cb=nil)
|
||||
moveZoomXY(delay,0,zoom_x,zoom_y,cb)
|
||||
end
|
||||
|
||||
def moveZoom(delay, duration, zoom, cb=nil)
|
||||
moveZoomXY(delay,duration,zoom,zoom,cb)
|
||||
end
|
||||
|
||||
def setZoom(delay, zoom, cb=nil)
|
||||
moveZoomXY(delay,0,zoom,zoom,cb)
|
||||
end
|
||||
|
||||
def moveAngle(delay, duration, angle, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Angle,delay,duration,0,cb,@angle,angle])
|
||||
end
|
||||
|
||||
def setAngle(delay, angle, cb=nil)
|
||||
moveAngle(delay,0,angle,cb)
|
||||
end
|
||||
|
||||
def moveTone(delay, duration, tone, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
target = (tone) ? tone.clone : Tone.new(0,0,0,0)
|
||||
@processes.push([Processes::Tone,delay,duration,0,cb,@tone.clone,target])
|
||||
end
|
||||
|
||||
def setTone(delay, tone, cb=nil)
|
||||
moveTone(delay,0,tone,cb)
|
||||
end
|
||||
|
||||
def moveColor(delay, duration, color, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
target = (color) ? color.clone : Color.new(0,0,0,0)
|
||||
@processes.push([Processes::Color,delay,duration,0,cb,@color.clone,target])
|
||||
end
|
||||
|
||||
def setColor(delay, color, cb=nil)
|
||||
moveColor(delay,0,color,cb)
|
||||
end
|
||||
|
||||
# Hue changes don't actually work.
|
||||
def moveHue(delay, duration, hue, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Hue,delay,duration,0,cb,@hue,hue])
|
||||
end
|
||||
|
||||
# Hue changes don't actually work.
|
||||
def setHue(delay, hue, cb=nil)
|
||||
moveHue(delay,0,hue,cb)
|
||||
end
|
||||
|
||||
def moveOpacity(delay, duration, opacity, cb=nil)
|
||||
delay, duration = ensureDelayAndDuration(delay,duration)
|
||||
@processes.push([Processes::Opacity,delay,duration,0,cb,@opacity,opacity])
|
||||
end
|
||||
|
||||
def setOpacity(delay, opacity, cb=nil)
|
||||
moveOpacity(delay,0,opacity,cb)
|
||||
end
|
||||
|
||||
def setVisible(delay, visible, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::Visible,delay,0,0,cb,visible])
|
||||
end
|
||||
|
||||
# Only values of 0 (normal), 1 (additive) and 2 (subtractive) are allowed.
|
||||
def setBlendType(delay, blend, cb=nil)
|
||||
delay = ensureDelayAndDuration(delay)
|
||||
@processes.push([Processes::BlendType,delay,0,0,cb,blend])
|
||||
end
|
||||
|
||||
def setSE(delay, seFile, volume=nil, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::SE,delay,0,0,cb,seFile,volume])
|
||||
end
|
||||
|
||||
def setName(delay, name, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::Name,delay,0,0,cb,name])
|
||||
end
|
||||
|
||||
def setOrigin(delay, origin, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::Origin,delay,0,0,cb,origin])
|
||||
end
|
||||
|
||||
def setSrc(delay, srcX, srcY, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::Src,delay,0,0,cb,srcX,srcY])
|
||||
end
|
||||
|
||||
def setSrcSize(delay, srcWidth, srcHeight, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::SrcSize,delay,0,0,cb,srcWidth,srcHeight])
|
||||
end
|
||||
|
||||
# Used to cut Pokémon sprites off when they faint and sink into the ground.
|
||||
def setCropBottom(delay, y, cb=nil)
|
||||
delay = ensureDelay(delay)
|
||||
@processes.push([Processes::CropBottom,delay,0,0,cb,y])
|
||||
end
|
||||
|
||||
def update
|
||||
procEnded = false
|
||||
@frameUpdates.clear
|
||||
for i in 0...@processes.length
|
||||
process = @processes[i]
|
||||
# Decrease delay of processes that are scheduled to start later
|
||||
if process[1]>=0
|
||||
# Set initial values if the process will start this frame
|
||||
if process[1]==0
|
||||
case process[0]
|
||||
when Processes::XY
|
||||
process[5] = @x
|
||||
process[6] = @y
|
||||
when Processes::DeltaXY
|
||||
process[5] = @x
|
||||
process[6] = @y
|
||||
process[7] += @x
|
||||
process[8] += @y
|
||||
when Processes::Curve
|
||||
process[5][0] = @x
|
||||
process[5][1] = @y
|
||||
when Processes::Z
|
||||
process[5] = @z
|
||||
when Processes::Zoom
|
||||
process[5] = @zoom_x
|
||||
process[6] = @zoom_y
|
||||
when Processes::Angle
|
||||
process[5] = @angle
|
||||
when Processes::Tone
|
||||
process[5] = @tone.clone
|
||||
when Processes::Color
|
||||
process[5] = @color.clone
|
||||
when Processes::Hue
|
||||
process[5] = @hue
|
||||
when Processes::Opacity
|
||||
process[5] = @opacity
|
||||
end
|
||||
end
|
||||
# Decrease delay counter
|
||||
process[1] -= 1
|
||||
# Process hasn't started yet, skip to the next one
|
||||
next if process[1]>=0
|
||||
end
|
||||
# Update process
|
||||
@frameUpdates.push(process[0]) if !@frameUpdates.include?(process[0])
|
||||
fra = (process[2]==0) ? 1 : process[3] # Frame counter
|
||||
dur = (process[2]==0) ? 1 : process[2] # Total duration of process
|
||||
case process[0]
|
||||
when Processes::XY, Processes::DeltaXY
|
||||
@x = process[5] + fra * (process[7] - process[5]) / dur
|
||||
@y = process[6] + fra * (process[8] - process[6]) / dur
|
||||
when Processes::Curve
|
||||
@x, @y = getCubicPoint2(process[5],fra.to_f/dur)
|
||||
when Processes::Z
|
||||
@z = process[5] + fra * (process[6] - process[5]) / dur
|
||||
when Processes::Zoom
|
||||
@zoom_x = process[5] + fra * (process[7] - process[5]) / dur
|
||||
@zoom_y = process[6] + fra * (process[8] - process[6]) / dur
|
||||
when Processes::Angle
|
||||
@angle = process[5] + fra * (process[6] - process[5]) / dur
|
||||
when Processes::Tone
|
||||
@tone.red = process[5].red + fra * (process[6].red - process[5].red) / dur
|
||||
@tone.green = process[5].green + fra * (process[6].green - process[5].green) / dur
|
||||
@tone.blue = process[5].blue + fra * (process[6].blue - process[5].blue) / dur
|
||||
@tone.gray = process[5].gray + fra * (process[6].gray - process[5].gray) / dur
|
||||
when Processes::Color
|
||||
@color.red = process[5].red + fra * (process[6].red - process[5].red) / dur
|
||||
@color.green = process[5].green + fra * (process[6].green - process[5].green) / dur
|
||||
@color.blue = process[5].blue + fra * (process[6].blue - process[5].blue) / dur
|
||||
@color.alpha = process[5].alpha + fra * (process[6].alpha - process[5].alpha) / dur
|
||||
when Processes::Hue
|
||||
@hue = (process[6] - process[5]).to_f / dur
|
||||
when Processes::Opacity
|
||||
@opacity = process[5] + fra * (process[6] - process[5]) / dur
|
||||
when Processes::Visible
|
||||
@visible = process[5]
|
||||
when Processes::BlendType
|
||||
@blend_type = process[5]
|
||||
when Processes::SE
|
||||
pbSEPlay(process[5],process[6])
|
||||
when Processes::Name
|
||||
@name = process[5]
|
||||
when Processes::Origin
|
||||
@origin = process[5]
|
||||
when Processes::Src
|
||||
@src_rect.x = process[5]
|
||||
@src_rect.y = process[6]
|
||||
when Processes::SrcSize
|
||||
@src_rect.width = process[5]
|
||||
@src_rect.height = process[6]
|
||||
when Processes::CropBottom
|
||||
@cropBottom = process[5]
|
||||
end
|
||||
# Increase frame counter
|
||||
process[3] += 1
|
||||
if process[3]>process[2]
|
||||
# Process has ended, erase it
|
||||
callback(process[4]) if process[4]
|
||||
@processes[i] = nil
|
||||
procEnded = true
|
||||
end
|
||||
end
|
||||
# Clear out empty spaces in @processes array caused by finished processes
|
||||
@processes.compact! if procEnded
|
||||
# Add the constant rotation speed
|
||||
if @rotate_speed != 0
|
||||
@frameUpdates.push(Processes::Angle) if !@frameUpdates.include?(Processes::Angle)
|
||||
@angle += @rotate_speed
|
||||
while @angle<0; @angle += 360; end
|
||||
@angle %= 360
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def setPictureSprite(sprite, picture, iconSprite=false)
|
||||
return if picture.frameUpdates.length==0
|
||||
for i in 0...picture.frameUpdates.length
|
||||
case picture.frameUpdates[i]
|
||||
when Processes::XY, Processes::DeltaXY
|
||||
sprite.x = picture.x.round
|
||||
sprite.y = picture.y.round
|
||||
when Processes::Z
|
||||
sprite.z = picture.z
|
||||
when Processes::Zoom
|
||||
sprite.zoom_x = picture.zoom_x / 100.0
|
||||
sprite.zoom_y = picture.zoom_y / 100.0
|
||||
when Processes::Angle
|
||||
sprite.angle = picture.angle
|
||||
when Processes::Tone
|
||||
sprite.tone = picture.tone
|
||||
when Processes::Color
|
||||
sprite.color = picture.color
|
||||
when Processes::Hue
|
||||
# This doesn't do anything.
|
||||
when Processes::BlendType
|
||||
sprite.blend_type = picture.blend_type
|
||||
when Processes::Opacity
|
||||
sprite.opacity = picture.opacity
|
||||
when Processes::Visible
|
||||
sprite.visible = picture.visible
|
||||
when Processes::Name
|
||||
sprite.name = picture.name if iconSprite && sprite.name != picture.name
|
||||
when Processes::Origin
|
||||
case picture.origin
|
||||
when PictureOrigin::TopLeft, PictureOrigin::Left, PictureOrigin::BottomLeft
|
||||
sprite.ox = 0
|
||||
when PictureOrigin::Top, PictureOrigin::Center, PictureOrigin::Bottom
|
||||
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width/2 : 0
|
||||
when PictureOrigin::TopRight, PictureOrigin::Right, PictureOrigin::BottomRight
|
||||
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width : 0
|
||||
end
|
||||
case picture.origin
|
||||
when PictureOrigin::TopLeft, PictureOrigin::Top, PictureOrigin::TopRight
|
||||
sprite.oy = 0
|
||||
when PictureOrigin::Left, PictureOrigin::Center, PictureOrigin::Right
|
||||
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height/2 : 0
|
||||
when PictureOrigin::BottomLeft, PictureOrigin::Bottom, PictureOrigin::BottomRight
|
||||
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height : 0
|
||||
end
|
||||
when Processes::Src
|
||||
next unless iconSprite && sprite.src_rect
|
||||
sprite.src_rect.x = picture.src_rect.x
|
||||
sprite.src_rect.y = picture.src_rect.y
|
||||
when Processes::SrcSize
|
||||
next unless iconSprite && sprite.src_rect
|
||||
sprite.src_rect.width = picture.src_rect.width
|
||||
sprite.src_rect.height = picture.src_rect.height
|
||||
end
|
||||
end
|
||||
if iconSprite && sprite.src_rect && picture.cropBottom>=0
|
||||
spriteBottom = sprite.y-sprite.oy+sprite.src_rect.height
|
||||
if spriteBottom>picture.cropBottom
|
||||
sprite.src_rect.height = [picture.cropBottom-sprite.y+sprite.oy,0].max
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setPictureIconSprite(sprite, picture)
|
||||
setPictureSprite(sprite,picture,true)
|
||||
end
|
||||
|
||||
|
||||
|
||||
class PictureOrigin
|
||||
TopLeft = 0
|
||||
Center = 1
|
||||
TopRight = 2
|
||||
BottomLeft = 3
|
||||
LowerLeft = 3
|
||||
BottomRight = 4
|
||||
LowerRight = 4
|
||||
Top = 5
|
||||
Bottom = 6
|
||||
Left = 7
|
||||
Right = 8
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbTextBitmap(text, maxwidth=Graphics.width)
|
||||
dims = []
|
||||
tmp = Bitmap.new(maxwidth,Graphics.height)
|
||||
pbSetSystemFont(tmp)
|
||||
drawFormattedTextEx(tmp,0,0,maxwidth,text,Color.new(248,248,248),Color.new(168,184,184))
|
||||
return tmp
|
||||
end
|
||||
|
||||
|
||||
|
||||
class PictureSprite < SpriteWrapper
|
||||
def initialize(viewport, picture)
|
||||
super(viewport)
|
||||
@picture = picture
|
||||
@pictureBitmap = nil
|
||||
@customBitmap = nil
|
||||
@customBitmapIsBitmap = true
|
||||
@hue = 0
|
||||
update
|
||||
end
|
||||
|
||||
def dispose
|
||||
@pictureBitmap.dispose if @pictureBitmap
|
||||
super
|
||||
end
|
||||
|
||||
# Doesn't free the bitmap
|
||||
def setCustomBitmap(bitmap)
|
||||
@customBitmap = bitmap
|
||||
@customBitmapIsBitmap = @customBitmap.is_a?(Bitmap)
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
@pictureBitmap.update if @pictureBitmap
|
||||
# If picture file name is different from current one
|
||||
if @customBitmap && @picture.name==""
|
||||
self.bitmap = (@customBitmapIsBitmap) ? @customBitmap : @customBitmap.bitmap
|
||||
elsif @picture_name != @picture.name || @picture.hue.to_i != @hue.to_i
|
||||
# Remember file name to instance variables
|
||||
@picture_name = @picture.name
|
||||
@hue = @picture.hue.to_i
|
||||
# If file name is not empty
|
||||
if @picture_name == ""
|
||||
@pictureBitmap.dispose if @pictureBitmap
|
||||
@pictureBitmap = nil
|
||||
self.visible = false
|
||||
return
|
||||
end
|
||||
# Get picture graphic
|
||||
@pictureBitmap.dispose if @pictureBitmap
|
||||
@pictureBitmap = AnimatedBitmap.new(@picture_name, @hue)
|
||||
self.bitmap = (@pictureBitmap) ? @pictureBitmap.bitmap : nil
|
||||
elsif @picture_name == ""
|
||||
# Set sprite to invisible
|
||||
self.visible = false
|
||||
return
|
||||
end
|
||||
setPictureSprite(self,@picture)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class EventScene
|
||||
attr_accessor :onCTrigger,:onBTrigger,:onUpdate
|
||||
|
||||
def initialize(viewport=nil)
|
||||
@viewport = viewport
|
||||
@onCTrigger = Event.new
|
||||
@onBTrigger = Event.new
|
||||
@onUpdate = Event.new
|
||||
@pictures = []
|
||||
@picturesprites = []
|
||||
@usersprites = []
|
||||
@disposed = false
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
for sprite in @picturesprites
|
||||
sprite.dispose
|
||||
end
|
||||
for sprite in @usersprites
|
||||
sprite.dispose
|
||||
end
|
||||
@onCTrigger.clear
|
||||
@onBTrigger.clear
|
||||
@onUpdate.clear
|
||||
@pictures.clear
|
||||
@picturesprites.clear
|
||||
@usersprites.clear
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?
|
||||
return @disposed
|
||||
end
|
||||
|
||||
def addBitmap(x, y, bitmap)
|
||||
# _bitmap_ can be a Bitmap or an AnimatedBitmap
|
||||
# (update method isn't called if it's animated)
|
||||
# EventScene doesn't take ownership of the passed-in bitmap
|
||||
num = @pictures.length
|
||||
picture = PictureEx.new(num)
|
||||
picture.setXY(0,x,y)
|
||||
picture.setVisible(0,true)
|
||||
@pictures[num] = picture
|
||||
@picturesprites[num] = PictureSprite.new(@viewport,picture)
|
||||
@picturesprites[num].setCustomBitmap(bitmap)
|
||||
return picture
|
||||
end
|
||||
|
||||
def addLabel(x, y, width, text)
|
||||
addBitmap(x,y,pbTextBitmap(text,width))
|
||||
end
|
||||
|
||||
def addImage(x, y, name)
|
||||
num = @pictures.length
|
||||
picture = PictureEx.new(num)
|
||||
picture.name = name
|
||||
picture.setXY(0,x,y)
|
||||
picture.setVisible(0,true)
|
||||
@pictures[num] = picture
|
||||
@picturesprites[num] = PictureSprite.new(@viewport,picture)
|
||||
return picture
|
||||
end
|
||||
|
||||
def addUserSprite(sprite)
|
||||
@usersprites.push(sprite)
|
||||
end
|
||||
|
||||
def getPicture(num)
|
||||
return @pictures[num]
|
||||
end
|
||||
|
||||
def wait(frames)
|
||||
frames.times { update }
|
||||
end
|
||||
|
||||
def pictureWait(extraframes=0)
|
||||
loop do
|
||||
hasRunning = false
|
||||
for pic in @pictures
|
||||
hasRunning = true if pic.running?
|
||||
end
|
||||
break if !hasRunning
|
||||
update
|
||||
end
|
||||
extraframes.times { update }
|
||||
end
|
||||
|
||||
def update
|
||||
return if disposed?
|
||||
Graphics.update
|
||||
Input.update
|
||||
for picture in @pictures
|
||||
picture.update
|
||||
end
|
||||
for sprite in @picturesprites
|
||||
sprite.update
|
||||
end
|
||||
for sprite in @usersprites
|
||||
next if !sprite || sprite.disposed? || !sprite.is_a?(Sprite)
|
||||
sprite.update
|
||||
end
|
||||
@onUpdate.trigger(self)
|
||||
if Input.trigger?(Input::B)
|
||||
@onBTrigger.trigger(self)
|
||||
elsif Input.trigger?(Input::C)
|
||||
@onCTrigger.trigger(self)
|
||||
end
|
||||
end
|
||||
|
||||
def main
|
||||
while !disposed?
|
||||
update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbEventScreen(cls)
|
||||
pbFadeOutIn {
|
||||
viewport = Viewport.new(0,0,Graphics.width,Graphics.height)
|
||||
viewport.z = 99999
|
||||
PBDebug.logonerr {
|
||||
cls.new(viewport).main
|
||||
}
|
||||
viewport.dispose
|
||||
}
|
||||
end
|
||||
@@ -0,0 +1,172 @@
|
||||
class Interpolator
|
||||
ZOOM_X = 1
|
||||
ZOOM_Y = 2
|
||||
X = 3
|
||||
Y = 4
|
||||
OPACITY = 5
|
||||
COLOR = 6
|
||||
WAIT = 7
|
||||
|
||||
def initialize
|
||||
@tweening = false
|
||||
@tweensteps = []
|
||||
@sprite = nil
|
||||
@frames = 0
|
||||
@step = 0
|
||||
end
|
||||
|
||||
def tweening?
|
||||
return @tweening
|
||||
end
|
||||
|
||||
def tween(sprite,items,frames)
|
||||
@tweensteps = []
|
||||
if sprite && !sprite.disposed? && frames>0
|
||||
@frames = frames
|
||||
@step = 0
|
||||
@sprite = sprite
|
||||
for item in items
|
||||
case item[0]
|
||||
when ZOOM_X
|
||||
@tweensteps[item[0]] = [sprite.zoom_x,item[1]-sprite.zoom_x]
|
||||
when ZOOM_Y
|
||||
@tweensteps[item[0]] = [sprite.zoom_y,item[1]-sprite.zoom_y]
|
||||
when X
|
||||
@tweensteps[item[0]] = [sprite.x,item[1]-sprite.x]
|
||||
when Y
|
||||
@tweensteps[item[0]] = [sprite.y,item[1]-sprite.y]
|
||||
when OPACITY
|
||||
@tweensteps[item[0]] = [sprite.opacity,item[1]-sprite.opacity]
|
||||
when COLOR
|
||||
@tweensteps[item[0]] = [sprite.color.clone,Color.new(
|
||||
item[1].red-sprite.color.red,
|
||||
item[1].green-sprite.color.green,
|
||||
item[1].blue-sprite.color.blue,
|
||||
item[1].alpha-sprite.color.alpha
|
||||
)]
|
||||
end
|
||||
end
|
||||
@tweening = true
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @tweening
|
||||
t = (@step*1.0)/@frames
|
||||
for i in 0...@tweensteps.length
|
||||
item = @tweensteps[i]
|
||||
next if !item
|
||||
case i
|
||||
when ZOOM_X
|
||||
@sprite.zoom_x = item[0]+item[1]*t
|
||||
when ZOOM_Y
|
||||
@sprite.zoom_y = item[0]+item[1]*t
|
||||
when X
|
||||
@sprite.x = item[0]+item[1]*t
|
||||
when Y
|
||||
@sprite.y = item[0]+item[1]*t
|
||||
when OPACITY
|
||||
@sprite.opacity = item[0]+item[1]*t
|
||||
when COLOR
|
||||
@sprite.color = Color.new(
|
||||
item[0].red+item[1].red*t,
|
||||
item[0].green+item[1].green*t,
|
||||
item[0].blue+item[1].blue*t,
|
||||
item[0].alpha+item[1].alpha*t
|
||||
)
|
||||
end
|
||||
end
|
||||
@step += 1
|
||||
if @step==@frames
|
||||
@step = 0
|
||||
@frames = 0
|
||||
@tweening = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class RectInterpolator
|
||||
def initialize(oldrect,newrect,frames)
|
||||
restart(oldrect,newrect,frames)
|
||||
end
|
||||
|
||||
def restart(oldrect,newrect,frames)
|
||||
@oldrect = oldrect
|
||||
@newrect = newrect
|
||||
@frames = [frames,1].max
|
||||
@curframe = 0
|
||||
@rect = oldrect.clone
|
||||
end
|
||||
|
||||
def set(rect)
|
||||
rect.set(@rect.x,@rect.y,@rect.width,@rect.height)
|
||||
end
|
||||
|
||||
def done?
|
||||
@curframe>@frames
|
||||
end
|
||||
|
||||
def update
|
||||
return if done?
|
||||
t = (@curframe*1.0/@frames)
|
||||
x1 = @oldrect.x
|
||||
x2 = @newrect.x
|
||||
x = x1+t*(x2-x1)
|
||||
y1 = @oldrect.y
|
||||
y2 = @newrect.y
|
||||
y = y1+t*(y2-y1)
|
||||
rx1 = @oldrect.x+@oldrect.width
|
||||
rx2 = @newrect.x+@newrect.width
|
||||
rx = rx1+t*(rx2-rx1)
|
||||
ry1 = @oldrect.y+@oldrect.height
|
||||
ry2 = @newrect.y+@newrect.height
|
||||
ry = ry1+t*(ry2-ry1)
|
||||
minx = x<rx ? x : rx
|
||||
maxx = x>rx ? x : rx
|
||||
miny = y<ry ? y : ry
|
||||
maxy = y>ry ? y : ry
|
||||
@rect.set(minx,miny,maxx-minx,maxy-miny)
|
||||
@curframe += 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
class PointInterpolator
|
||||
attr_reader :x
|
||||
attr_reader :y
|
||||
|
||||
def initialize(oldx,oldy,newx,newy,frames)
|
||||
restart(oldx,oldy,newx,newy,frames)
|
||||
end
|
||||
|
||||
def restart(oldx,oldy,newx,newy,frames)
|
||||
@oldx = oldx
|
||||
@oldy = oldy
|
||||
@newx = newx
|
||||
@newy = newy
|
||||
@frames = frames
|
||||
@curframe = 0
|
||||
@x = oldx
|
||||
@y = oldy
|
||||
end
|
||||
|
||||
def done?
|
||||
@curframe>@frames
|
||||
end
|
||||
|
||||
def update
|
||||
return if done?
|
||||
t = (@curframe*1.0/@frames)
|
||||
rx1 = @oldx
|
||||
rx2 = @newx
|
||||
@x = rx1+t*(rx2-rx1)
|
||||
ry1 = @oldy
|
||||
ry2 = @newy
|
||||
@y = ry1+t*(ry2-ry1)
|
||||
@curframe += 1
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user