More renaming and rearranging, fixed typo from earlier commit, tweaked splash and title screen code

This commit is contained in:
Maruno17
2021-04-05 00:04:18 +01:00
parent 5b0960337a
commit f541a13c9b
69 changed files with 180 additions and 69 deletions

View File

@@ -0,0 +1,119 @@
class Hangup < Exception; end
module RPG
module Cache
def self.debug
t = Time.now
filename = t.strftime("%H %M %S.%L.txt")
File.open("cache_" + filename, "wb") { |f|
@cache.each do |key, value|
if !value
f.write("#{key} (nil)\r\n")
elsif value.disposed?
f.write("#{key} (disposed)\r\n")
else
f.write("#{key} (#{value.refcount}, #{value.width}x#{value.height})\r\n")
end
end
}
end
def self.setKey(key, obj)
@cache[key] = obj
end
def self.fromCache(i)
return nil if !@cache.include?(i)
obj = @cache[i]
return nil if obj && obj.disposed?
return obj
end
def self.load_bitmap(folder_name, filename, hue = 0)
path = folder_name + filename
cached = true
ret = fromCache(path)
if !ret
if filename != ""
ret = BitmapWrapper.new(path)
else
ret = BitmapWrapper.new(32, 32)
end
@cache[path] = ret
cached = false
end
if hue == 0
ret.addRef if cached
return ret
end
key = [path, hue]
ret2 = fromCache(key)
if ret2
ret2.addRef
else
ret2 = ret.copy
ret2.hue_change(hue)
@cache[key] = ret2
end
return ret2
end
def self.tileEx(filename, tile_id, hue, width = 1, height = 1)
key = [filename, tile_id, hue, width, height]
ret = fromCache(key)
if ret
ret.addRef
else
ret = BitmapWrapper.new(32 * width, 32 * height)
x = (tile_id - 384) % 8 * 32
y = (((tile_id - 384) / 8) - height + 1) * 32
tileset = yield(filename)
ret.blt(0, 0, tileset, Rect.new(x, y, 32 * width, 32 * height))
tileset.dispose
ret.hue_change(hue) if hue != 0
@cache[key] = ret
end
return ret
end
def self.tile(filename, tile_id, hue)
return self.tileEx(filename, tile_id, hue) { |f| self.tileset(f) }
end
def self.transition(filename)
self.load_bitmap("Graphics/Transitions/", filename)
end
end
end
class BitmapWrapper < Bitmap
attr_reader :refcount
def dispose
return if self.disposed?
@refcount -= 1
super if @refcount <= 0
end
def initialize(*arg)
super
@refcount = 1
end
def resetRef
@refcount = 1
end
def copy
bm = self.clone
bm.resetRef
return bm
end
def addRef
@refcount += 1
end
end

View File

@@ -0,0 +1,794 @@
module MessageConfig
WindowOpacity = 255
TextSpeed = nil # can be positive to wait frames or negative to
# show multiple characters in a single frame
# 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
LIGHTTEXTBASE = Color.new(248,248,248)
LIGHTTEXTSHADOW = Color.new(72,80,88)
DARKTEXTBASE = Color.new(80,80,88)
DARKTEXTSHADOW = Color.new(160,160,168)
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
begin
return pbResolveBitmap("Graphics/Windowskins/" + Settings::MENU_WINDOWSKINS[$PokemonSystem.frame]) || ""
rescue
return pbResolveBitmap("Graphics/Windowskins/" + Settings::MENU_WINDOWSKINS[0]) || ""
end
end
def self.pbDefaultSpeechFrame
begin
return pbResolveBitmap("Graphics/Windowskins/" + Settings::SPEECH_WINDOWSKINS[$PokemonSystem.textskin]) || ""
rescue
return pbResolveBitmap("Graphics/Windowskins/" + Settings::SPEECH_WINDOWSKINS[0]) || ""
end
end
def self.pbDefaultSystemFontName
begin
return MessageConfig.pbTryFonts(Settings::FONT_OPTIONS[$PokemonSystem.font], "Arial Narrow", "Arial")
rescue
return MessageConfig.pbTryFonts(Settings::FONT_OPTIONS[0], "Arial Narrow", "Arial")
end
end
def self.pbDefaultTextSpeed
return pbSettingToTextSpeed(($PokemonSystem.textspeed rescue nil))
end
def self.pbSettingToTextSpeed(speed)
case speed
when 0 then return 2
when 1 then return 1
when 2 then return -2
end
return TextSpeed || 1
end
def self.pbDefaultWindowskin
skin=($data_system) ? $data_system.windowskin_name : 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
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 = 27
elsif fontname == "Pokemon Emerald Small" || fontname == "Power Green Small"
bitmap.font.size = 29
else
bitmap.font.size = 29
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 = 29
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
#===============================================================================
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
# Similar to pbFadeOutIn, but pauses the music as it fades out.
# Requires scripts "Audio" (for bgm_pause) and "SpriteWindow" (for pbFadeOutIn).
def pbFadeOutInWithMusic(zViewport=99999)
playingBGS = $game_system.getPlayingBGS
playingBGM = $game_system.getPlayingBGM
$game_system.bgm_pause(1.0)
$game_system.bgs_pause(1.0)
pos = $game_system.bgm_position
pbFadeOutIn(zViewport) {
yield
$game_system.bgm_position = pos
$game_system.bgm_resume(playingBGM)
$game_system.bgs_resume(playingBGS)
}
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

View File

@@ -0,0 +1,604 @@
class WindowCursorRect < Rect
def initialize(window)
super(0, 0, 0, 0)
@window = window
end
def empty
return unless needs_update?(0, 0, 0, 0)
set(0, 0, 0, 0)
end
def empty?
return self.x == 0 && self.y == 0 && self.width == 0 && self.height == 0
end
def set(x, y, width, height)
return unless needs_update?(x, y, width, height)
super(x, y, width, height)
@window.width = @window.width
end
def height=(value)
super(value)
@window.width = @window.width
end
def width=(value)
super(value)
@window.width = @window.width
end
def x=(value)
super(value)
@window.width = @window.width
end
def y=(value)
super(value)
@window.width = @window.width
end
private
def needs_update?(x, y, width, height)
return self.x != x || self.y != y || self.width != width || self.height != height
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.empty?
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

View File

@@ -0,0 +1,933 @@
#===============================================================================
# SpriteWindow is a class based on Window which emulates Window's functionality.
# This class is necessary in order to change the viewport of windows (with
# viewport=) and to make windows fade in and out (with tone=).
#===============================================================================
class SpriteWindow < Window
attr_reader :tone
attr_reader :color
attr_reader :viewport
attr_reader :contents
attr_reader :ox
attr_reader :oy
attr_reader :x
attr_reader :y
attr_reader :z
attr_reader :zoom_x
attr_reader :zoom_y
attr_reader :offset_x
attr_reader :offset_y
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 :contents_blend_type
attr_reader :blend_type
attr_reader :openness
def windowskin
@_windowskin
end
# Flags used to preserve compatibility
# with RGSS/RGSS2's version of Window
module CompatBits
CorrectZ = 1
ExpandBack = 2
ShowScrollArrows = 4
StretchSides = 8
ShowPause = 16
ShowCursor = 32
end
attr_reader :compat
def compat=(value)
@compat=value
privRefresh(true)
end
def initialize(viewport=nil)
@sprites={}
@spritekeys=[
"back",
"corner0","side0","scroll0",
"corner1","side1","scroll1",
"corner2","side2","scroll2",
"corner3","side3","scroll3",
"cursor","contents","pause"
]
@viewport=viewport
@sidebitmaps=[nil,nil,nil,nil]
@cursorbitmap=nil
@bgbitmap=nil
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
@compat=CompatBits::ExpandBack|CompatBits::StretchSides
@x=0
@y=0
@width=0
@height=0
@offset_x=0
@offset_y=0
@zoom_x=1.0
@zoom_y=1.0
@ox=0
@oy=0
@z=0
@stretch=true
@visible=true
@active=true
@openness=255
@opacity=255
@back_opacity=255
@blend_type=0
@contents_blend_type=0
@contents_opacity=255
@cursor_rect=WindowCursorRect.new(self)
@cursorblink=0
@cursoropacity=255
@pause=false
@pauseframe=0
@flash=0
@pauseopacity=0
@skinformat=0
@skinrect=Rect.new(0,0,0,0)
@trim=[16,16,16,16]
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
@disposed=true
end
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]
end
for i in @spritekeys
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)
if @contents!=value
@contents=value
privRefresh if @visible
end
end
def ox=(value)
if @ox!=value
@ox=value
privRefresh if @visible
end
end
def oy=(value)
if @oy!=value
@oy=value
privRefresh if @visible
end
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 openness=(value)
@openness=value
@openness=0 if @openness<0
@openness=255 if @openness>255
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 if @visible
end
def x=(value)
@x=value
privRefresh if @visible
end
def y=(value)
@y=value
privRefresh if @visible
end
def zoom_x=(value)
@zoom_x=value
privRefresh if @visible
end
def zoom_y=(value)
@zoom_y=value
privRefresh if @visible
end
def offset_x=(value)
@x=value
privRefresh if @visible
end
def offset_y=(value)
@y=value
privRefresh if @visible
end
def opacity=(value)
@opacity=value
@opacity=0 if @opacity<0
@opacity=255 if @opacity>255
privRefresh if @visible
end
def back_opacity=(value)
@back_opacity=value
@back_opacity=0 if @back_opacity<0
@back_opacity=255 if @back_opacity>255
privRefresh if @visible
end
def contents_opacity=(value)
@contents_opacity=value
@contents_opacity=0 if @contents_opacity<0
@contents_opacity=255 if @contents_opacity>255
privRefresh if @visible
end
def tone=(value)
@tone=value
privRefresh if @visible
end
def color=(value)
@color=value
privRefresh if @visible
end
def blend_type=(value)
@blend_type=value
privRefresh if @visible
end
def flash(color,duration)
return if disposed?
@flash=duration+1
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
privRefreshCursor
else
@cursoropacity=128
privRefreshCursor
end
if @pause
oldpauseframe=@pauseframe
oldpauseopacity=@pauseopacity
@pauseframe=(Graphics.frame_count / 8) % 4
@pauseopacity=[@pauseopacity+64,255].min
mustchange=@pauseframe!=oldpauseframe || @pauseopacity!=oldpauseopacity
end
privRefresh if mustchange
if @flash>0
for i in @sprites.values
i.update
end
@flash-=1
end
end
#############
attr_reader :skinformat
attr_reader :skinrect
def loadSkinFile(_file)
if (self.windowskin.width==80 || self.windowskin.width==96) &&
self.windowskin.height==48
# Body = X, Y, width, height of body rectangle within windowskin
@skinrect.set(32,16,16,16)
# Trim = X, Y, width, height of trim rectangle within windowskin
@trim=[32,16,16,16]
elsif self.windowskin.width==80 && self.windowskin.height==80
@skinrect.set(32,32,16,16)
@trim=[32,16,16,48]
end
end
def windowskin=(value)
oldSkinWidth=(@_windowskin && !@_windowskin.disposed?) ? @_windowskin.width : -1
oldSkinHeight=(@_windowskin && !@_windowskin.disposed?) ? @_windowskin.height : -1
@_windowskin=value
if @skinformat==1
@rpgvx=false
if @_windowskin && !@_windowskin.disposed?
if @_windowskin.width!=oldSkinWidth || @_windowskin.height!=oldSkinHeight
# Update skinrect and trim if windowskin's dimensions have changed
@skinrect.set((@_windowskin.width-16)/2,(@_windowskin.height-16)/2,16,16)
@trim=[@skinrect.x,@skinrect.y,@skinrect.x,@skinrect.y]
end
else
@skinrect.set(16,16,16,16)
@trim=[16,16,16,16]
end
else
if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128
@rpgvx=true
else
@rpgvx=false
end
@trim=[16,16,16,16]
end
privRefresh(true)
end
def skinrect=(value)
@skinrect=value
privRefresh
end
def skinformat=(value)
if @skinformat!=value
@skinformat=value
privRefresh(true)
end
end
def borderX
return 32 if !@trim || skinformat==0
if @_windowskin && !@_windowskin.disposed?
return @trim[0]+(@_windowskin.width-@trim[2]-@trim[0])
end
return 32
end
def borderY
return 32 if !@trim || skinformat==0
if @_windowskin && !@_windowskin.disposed?
return @trim[1]+(@_windowskin.height-@trim[3]-@trim[1])
end
return 32
end
def leftEdge; self.startX; end
def topEdge; self.startY; end
def rightEdge; self.borderX-self.leftEdge; end
def bottomEdge; self.borderY-self.topEdge; end
def startX
return !@trim || skinformat==0 ? 16 : @trim[0]
end
def startY
return !@trim || skinformat==0 ? 16 : @trim[1]
end
def endX
return !@trim || skinformat==0 ? 16 : @trim[2]
end
def endY
return !@trim || skinformat==0 ? 16 : @trim[3]
end
def startX=(value)
@trim[0]=value
privRefresh
end
def startY=(value)
@trim[1]=value
privRefresh
end
def endX=(value)
@trim[2]=value
privRefresh
end
def endY=(value)
@trim[3]=value
privRefresh
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 privRefreshCursor
contopac=self.contents_opacity
cursoropac=@cursoropacity*contopac/255
@sprites["cursor"].opacity=cursoropac
end
def privRefresh(changeBitmap=false)
return if !self || self.disposed?
backopac=self.back_opacity*self.opacity/255
contopac=self.contents_opacity
cursoropac=@cursoropacity*contopac/255
haveskin=@_windowskin && !@_windowskin.disposed?
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 haveskin
for i in 0...4
@sprites["corner#{i}"].opacity=@opacity
@sprites["corner#{i}"].tone=@tone
@sprites["corner#{i}"].color=@color
@sprites["corner#{i}"].visible=@visible
@sprites["corner#{i}"].blend_type=@blend_type
@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}"].color=@color
@sprites["scroll#{i}"].visible=@visible
@sprites["scroll#{i}"].blend_type=@blend_type
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
supported=(@skinformat==0)
hascontents=(@contents && !@contents.disposed?)
@sprites["back"].visible=@visible
@sprites["contents"].visible=@visible && @openness==255
@sprites["pause"].visible=supported && @visible && @pause &&
(@combat & CompatBits::ShowPause)
@sprites["cursor"].visible=supported && @visible && @openness==255 &&
(@combat & CompatBits::ShowCursor)
@sprites["scroll0"].visible = false
@sprites["scroll1"].visible = false
@sprites["scroll2"].visible = false
@sprites["scroll3"].visible = false
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 @spritekeys
@sprites[i].z=@z
end
if (@compat & CompatBits::CorrectZ)>0 && @skinformat==0 && !@rpgvx
# Compatibility Mode: Cursor, pause, and contents have higher Z
@sprites["cursor"].z=@z+1
@sprites["contents"].z=@z+2
@sprites["pause"].z=@z+2
end
if @skinformat==0
startX=16
startY=16
endX=16
endY=16
trimStartX=16
trimStartY=16
trimWidth=32
trimHeight=32
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
if @_windowskin && !@_windowskin.disposed?
@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)
]
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
)
end
else
trimStartX=@trim[0]
trimStartY=@trim[1]
trimWidth=@trim[0]+(@skinrect.width-@trim[2]+@trim[0])
trimHeight=@trim[1]+(@skinrect.height-@trim[3]+@trim[1])
if @_windowskin && !@_windowskin.disposed?
# width of left end of window
startX=@skinrect.x
# width of top end of window
startY=@skinrect.y
cx=@skinrect.x+@skinrect.width # right side of BODY rect
cy=@skinrect.y+@skinrect.height # bottom side of BODY rect
# width of right end of window
endX=(!@_windowskin || @_windowskin.disposed?) ? @skinrect.x : @_windowskin.width-cx
# height of bottom end of window
endY=(!@_windowskin || @_windowskin.disposed?) ? @skinrect.y : @_windowskin.height-cy
@sprites["corner0"].src_rect.set(0,0,startX,startY);
@sprites["corner1"].src_rect.set(cx,0,endX,startY);
@sprites["corner2"].src_rect.set(0,cy,startX,endY);
@sprites["corner3"].src_rect.set(cx,cy,endX,endY);
backRect=Rect.new(@skinrect.x,@skinrect.y,
@skinrect.width,@skinrect.height);
blindsRect=nil
sideRects=[
Rect.new(startX,0,@skinrect.width,startY), # side0 (top)
Rect.new(0,startY,startX,@skinrect.height), # side1 (left)
Rect.new(cx,startY,endX,@skinrect.height), # side2 (right)
Rect.new(startX,cy,@skinrect.width,endY) # side3 (bottom)
]
end
end
if @width>trimWidth && @height>trimHeight
@sprites["contents"].src_rect.set(@ox,@oy,@width-trimWidth,@height-trimHeight)
else
@sprites["contents"].src_rect.set(0,0,0,0)
end
@sprites["contents"].x=@x+trimStartX
@sprites["contents"].y=@y+trimStartY
if (@compat & CompatBits::ShowScrollArrows)>0 && @skinformat==0
# Compatibility mode: Make scroll arrows visible
if @skinformat==0 && @_windowskin && !@_windowskin.disposed? &&
@contents && !@contents.disposed?
@sprites["scroll0"].visible = @visible && hascontents && @oy > 0
@sprites["scroll1"].visible = @visible && hascontents && @ox > 0
@sprites["scroll2"].visible = @visible && (@contents.width - @ox) > @width-trimWidth
@sprites["scroll3"].visible = @visible && (@contents.height - @oy) > @height-trimHeight
end
end
if @_windowskin && !@_windowskin.disposed?
borderX=startX+endX
borderY=startY+endY
@sprites["corner0"].x=@x
@sprites["corner0"].y=@y
@sprites["corner1"].x=@x+@width-endX
@sprites["corner1"].y=@y
@sprites["corner2"].x=@x
@sprites["corner2"].y=@y+@height-endY
@sprites["corner3"].x=@x+@width-endX
@sprites["corner3"].y=@y+@height-endY
@sprites["side0"].x=@x+startX
@sprites["side0"].y=@y
@sprites["side1"].x=@x
@sprites["side1"].y=@y+startY
@sprites["side2"].x=@x+@width-endX
@sprites["side2"].y=@y+startY
@sprites["side3"].x=@x+startX
@sprites["side3"].y=@y+@height-endY
@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["cursor"].x=@x+startX+@cursor_rect.x
@sprites["cursor"].y=@y+startY+@cursor_rect.y
if (@compat & CompatBits::ExpandBack)>0 && @skinformat==0
# Compatibility mode: Expand background
@sprites["back"].x=@x+2
@sprites["back"].y=@y+2
else
@sprites["back"].x=@x+startX
@sprites["back"].y=@y+startY
end
end
if changeBitmap && @_windowskin && !@_windowskin.disposed?
if @skinformat==0
@sprites["cursor"].x=@x+startX+@cursor_rect.x
@sprites["cursor"].y=@y+startY+@cursor_rect.y
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
end
for i in 0..3
case i
when 0
dwidth = @width-startX-endX
dheight = startY
when 1
dwidth = startX
dheight = @height-startY-endY
when 2
dwidth = endX
dheight = @height-startY-endY
when 3
dwidth = @width-startX-endX
dheight = endY
end
@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
if (@compat & CompatBits::StretchSides)>0 && @skinformat==0
# Compatibility mode: Stretch sides
@sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect,
@_windowskin,sideRects[i])
else
tileBitmap(@sidebitmaps[i],@sprites["side#{i}"].src_rect,
@_windowskin,sideRects[i])
end
end
end
if (@compat & CompatBits::ExpandBack)>0 && @skinformat==0
# Compatibility mode: Expand background
backwidth=@width-4
backheight=@height-4
else
backwidth=@width-borderX
backheight=@height-borderY
end
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.zoom_x=1.0
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_x=1.0
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
sprite.zoom_x*=@zoom_x
sprite.zoom_y*=@zoom_y
sprite.x*=@zoom_x
sprite.y*=@zoom_y
sprite.x+=(@offset_x/sprite.zoom_x)
sprite.y+=(@offset_y/sprite.zoom_y)
end
end
end
#===============================================================================
#
#===============================================================================
class SpriteWindow_Base < SpriteWindow
TEXTPADDING=4 # In pixels
def initialize(x, y, width, height)
super()
self.x = x
self.y = y
self.width = width
self.height = height
self.z = 100
@curframe=MessageConfig.pbGetSystemFrame()
@curfont=MessageConfig.pbGetSystemFontName()
@sysframe=AnimatedBitmap.new(@curframe)
@customskin=nil
__setWindowskin(@sysframe.bitmap)
__resolveSystemFrame()
pbSetSystemFont(self.contents) if self.contents
end
def __setWindowskin(skin)
if skin && (skin.width==192 && skin.height==128) || # RPGXP Windowskin
(skin.width==128 && skin.height==128) # RPGVX Windowskin
self.skinformat=0
else
self.skinformat=1
end
self.windowskin=skin
end
def __resolveSystemFrame
if self.skinformat==1
if !@resolvedFrame
@resolvedFrame=MessageConfig.pbGetSystemFrame()
@resolvedFrame.sub!(/\.[^\.\/\\]+$/,"")
end
self.loadSkinFile("#{@resolvedFrame}.txt") if @resolvedFrame!=""
end
end
def setSkin(skin) # Filename of windowskin to apply. Supports XP, VX, and animated skins.
@customskin.dispose if @customskin
@customskin=nil
resolvedName=pbResolveBitmap(skin)
return if !resolvedName || resolvedName==""
@customskin=AnimatedBitmap.new(resolvedName)
__setWindowskin(@customskin.bitmap)
if self.skinformat==1
skinbase=resolvedName.sub(/\.[^\.\/\\]+$/,"")
self.loadSkinFile("#{skinbase}.txt")
end
end
def setSystemFrame
@customskin.dispose if @customskin
@customskin=nil
__setWindowskin(@sysframe.bitmap)
__resolveSystemFrame()
end
def update
super
if self.windowskin
if @customskin
if @customskin.totalFrames>1
@customskin.update
__setWindowskin(@customskin.bitmap)
end
elsif @sysframe
if @sysframe.totalFrames>1
@sysframe.update
__setWindowskin(@sysframe.bitmap)
end
end
end
if @curframe!=MessageConfig.pbGetSystemFrame()
@curframe=MessageConfig.pbGetSystemFrame()
if @sysframe && !@customskin
@sysframe.dispose if @sysframe
@sysframe=AnimatedBitmap.new(@curframe)
@resolvedFrame=nil
__setWindowskin(@sysframe.bitmap)
__resolveSystemFrame()
end
begin
refresh
rescue NoMethodError
end
end
if @curfont!=MessageConfig.pbGetSystemFontName()
@curfont=MessageConfig.pbGetSystemFontName()
if self.contents && !self.contents.disposed?
pbSetSystemFont(self.contents)
end
begin
refresh
rescue NoMethodError
end
end
end
def dispose
self.contents.dispose if self.contents
@sysframe.dispose
@customskin.dispose if @customskin
super
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,121 @@
#===============================================================================
# Displays an icon bitmap in a window. Supports animated images.
#===============================================================================
class IconWindow < SpriteWindow_Base
attr_reader :name
def initialize(x,y,width,height,viewport=nil)
super(x,y,width,height)
self.viewport=viewport
self.contents=nil
@name=""
@_iconbitmap=nil
end
def dispose
clearBitmaps()
super
end
def update
super
if @_iconbitmap
@_iconbitmap.update
self.contents=@_iconbitmap.bitmap
end
end
def clearBitmaps
@_iconbitmap.dispose if @_iconbitmap
@_iconbitmap=nil
self.contents=nil if !self.disposed?
end
# Sets the icon's filename. Alias for setBitmap.
def name=(value)
setBitmap(value)
end
# Sets the icon's filename.
def setBitmap(file,hue=0)
clearBitmaps()
@name=file
return if file==nil
if file!=""
@_iconbitmap=AnimatedBitmap.new(file,hue)
# for compatibility
self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil
else
@_iconbitmap=nil
end
end
end
#===============================================================================
# Displays an icon bitmap in a window. Supports animated images.
# Accepts bitmaps and paths to bitmap files in its constructor.
#===============================================================================
class PictureWindow < SpriteWindow_Base
def initialize(pathOrBitmap)
super(0,0,32,32)
self.viewport=viewport
self.contents=nil
@_iconbitmap=nil
setBitmap(pathOrBitmap)
end
def dispose
clearBitmaps()
super
end
def update
super
if @_iconbitmap
if @_iconbitmap.is_a?(Bitmap)
self.contents=@_iconbitmap
else
@_iconbitmap.update
self.contents=@_iconbitmap.bitmap
end
end
end
def clearBitmaps
@_iconbitmap.dispose if @_iconbitmap
@_iconbitmap=nil
self.contents=nil if !self.disposed?
end
# Sets the icon's bitmap or filename. (hue parameter
# is ignored unless pathOrBitmap is a filename)
def setBitmap(pathOrBitmap,hue=0)
clearBitmaps()
if pathOrBitmap!=nil && pathOrBitmap!=""
if pathOrBitmap.is_a?(Bitmap)
@_iconbitmap=pathOrBitmap
self.contents=@_iconbitmap
self.width=@_iconbitmap.width+self.borderX
self.height=@_iconbitmap.height+self.borderY
elsif pathOrBitmap.is_a?(AnimatedBitmap)
@_iconbitmap=pathOrBitmap
self.contents=@_iconbitmap.bitmap
self.width=@_iconbitmap.bitmap.width+self.borderX
self.height=@_iconbitmap.bitmap.height+self.borderY
else
@_iconbitmap=AnimatedBitmap.new(pathOrBitmap,hue)
self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil
self.width=@_iconbitmap ? @_iconbitmap.bitmap.width+self.borderX :
32+self.borderX
self.height=@_iconbitmap ? @_iconbitmap.bitmap.height+self.borderY :
32+self.borderY
end
else
@_iconbitmap=nil
self.width=32+self.borderX
self.height=32+self.borderY
end
end
end

View File

@@ -0,0 +1,359 @@
#===============================================================================
# SpriteWrapper is a class which wraps (most of) Sprite's properties.
#===============================================================================
class SpriteWrapper
def initialize(viewport=nil)
@sprite = Sprite.new(viewport)
end
def dispose; @sprite.dispose; end
def disposed?; return @sprite.disposed?; end
def viewport; return @sprite.viewport; end
def flash(color,duration); return @sprite.flash(color,duration); end
def update; return @sprite.update; end
def x; @sprite.x; end
def x=(value); @sprite.x = value; end
def y; @sprite.y; end
def y=(value); @sprite.y = value; end
def bitmap; @sprite.bitmap; end
def bitmap=(value); @sprite.bitmap = value; end
def src_rect; @sprite.src_rect; end
def src_rect=(value); @sprite.src_rect = value; end
def visible; @sprite.visible; end
def visible=(value); @sprite.visible = value; end
def z; @sprite.z; end
def z=(value); @sprite.z = value; end
def ox; @sprite.ox; end
def ox=(value); @sprite.ox = value; end
def oy; @sprite.oy; end
def oy=(value); @sprite.oy = value; end
def zoom_x; @sprite.zoom_x; end
def zoom_x=(value); @sprite.zoom_x = value; end
def zoom_y; @sprite.zoom_y; end
def zoom_y=(value); @sprite.zoom_y = value; end
def angle; @sprite.angle; end
def angle=(value); @sprite.angle = value; end
def mirror; @sprite.mirror; end
def mirror=(value); @sprite.mirror = value; end
def bush_depth; @sprite.bush_depth; end
def bush_depth=(value); @sprite.bush_depth = value; end
def opacity; @sprite.opacity; end
def opacity=(value); @sprite.opacity = value; end
def blend_type; @sprite.blend_type; end
def blend_type=(value); @sprite.blend_type = value; end
def color; @sprite.color; end
def color=(value); @sprite.color = value; end
def tone; @sprite.tone; end
def tone=(value); @sprite.tone = value; end
def viewport=(value)
return if self.viewport==value
bitmap = @sprite.bitmap
src_rect = @sprite.src_rect
visible = @sprite.visible
x = @sprite.x
y = @sprite.y
z = @sprite.z
ox = @sprite.ox
oy = @sprite.oy
zoom_x = @sprite.zoom_x
zoom_y = @sprite.zoom_y
angle = @sprite.angle
mirror = @sprite.mirror
bush_depth = @sprite.bush_depth
opacity = @sprite.opacity
blend_type = @sprite.blend_type
color = @sprite.color
tone = @sprite.tone
@sprite.dispose
@sprite = Sprite.new(value)
@sprite.bitmap = bitmap
@sprite.src_rect = src_rect
@sprite.visible = visible
@sprite.x = x
@sprite.y = y
@sprite.z = z
@sprite.ox = ox
@sprite.oy = oy
@sprite.zoom_x = zoom_x
@sprite.zoom_y = zoom_y
@sprite.angle = angle
@sprite.mirror = mirror
@sprite.bush_depth = bush_depth
@sprite.opacity = opacity
@sprite.blend_type = blend_type
@sprite.color = color
@sprite.tone = tone
end
end
#===============================================================================
# Sprite class that maintains a bitmap of its own.
# This bitmap can't be changed to a different one.
#===============================================================================
class BitmapSprite < SpriteWrapper
def initialize(width,height,viewport=nil)
super(viewport)
self.bitmap=Bitmap.new(width,height)
@initialized=true
end
def bitmap=(value)
super(value) if !@initialized
end
def dispose
self.bitmap.dispose if !self.disposed?
super
end
end
#===============================================================================
#
#===============================================================================
class AnimatedSprite < SpriteWrapper
attr_reader :frame
attr_reader :framewidth
attr_reader :frameheight
attr_reader :framecount
attr_reader :animname
def initializeLong(animname,framecount,framewidth,frameheight,frameskip)
@animname=pbBitmapName(animname)
@realframes=0
@frameskip=[1,frameskip].max
@frameskip *= Graphics.frame_rate/20
raise _INTL("Frame width is 0") if framewidth==0
raise _INTL("Frame height is 0") if frameheight==0
begin
@animbitmap=AnimatedBitmap.new(animname).deanimate
rescue
@animbitmap=Bitmap.new(framewidth,frameheight)
end
if @animbitmap.width%framewidth!=0
raise _INTL("Bitmap's width ({1}) is not a multiple of frame width ({2}) [Bitmap={3}]",
@animbitmap.width,framewidth,animname)
end
if @animbitmap.height%frameheight!=0
raise _INTL("Bitmap's height ({1}) is not a multiple of frame height ({2}) [Bitmap={3}]",
@animbitmap.height,frameheight,animname)
end
@framecount=framecount
@framewidth=framewidth
@frameheight=frameheight
@framesperrow=@animbitmap.width/@framewidth
@playing=false
self.bitmap=@animbitmap
self.src_rect.width=@framewidth
self.src_rect.height=@frameheight
self.frame=0
end
# Shorter version of AnimationSprite. All frames are placed on a single row
# of the bitmap, so that the width and height need not be defined beforehand
def initializeShort(animname,framecount,frameskip)
@animname=pbBitmapName(animname)
@realframes=0
@frameskip=[1,frameskip].max
@frameskip *= Graphics.frame_rate/20
begin
@animbitmap=AnimatedBitmap.new(animname).deanimate
rescue
@animbitmap=Bitmap.new(framecount*4,32)
end
if @animbitmap.width%framecount!=0
raise _INTL("Bitmap's width ({1}) is not a multiple of frame count ({2}) [Bitmap={3}]",
@animbitmap.width,framewidth,animname)
end
@framecount=framecount
@framewidth=@animbitmap.width/@framecount
@frameheight=@animbitmap.height
@framesperrow=framecount
@playing=false
self.bitmap=@animbitmap
self.src_rect.width=@framewidth
self.src_rect.height=@frameheight
self.frame=0
end
def initialize(*args)
if args.length==1
super(args[0][3])
initializeShort(args[0][0],args[0][1],args[0][2])
else
super(args[5])
initializeLong(args[0],args[1],args[2],args[3],args[4])
end
end
def self.create(animname,framecount,frameskip,viewport=nil)
return self.new([animname,framecount,frameskip,viewport])
end
def dispose
return if disposed?
@animbitmap.dispose
@animbitmap=nil
super
end
def playing?
return @playing
end
def frame=(value)
@frame=value
@realframes=0
self.src_rect.x=@frame%@framesperrow*@framewidth
self.src_rect.y=@frame/@framesperrow*@frameheight
end
def start
@playing=true
@realframes=0
end
alias play start
def stop
@playing=false
end
def update
super
if @playing
@realframes+=1
if @realframes==@frameskip
@realframes=0
self.frame+=1
self.frame%=self.framecount
end
end
end
end
#===============================================================================
# Displays an icon bitmap in a sprite. Supports animated images.
#===============================================================================
class IconSprite < SpriteWrapper
attr_reader :name
def initialize(*args)
if args.length==0
super(nil)
self.bitmap=nil
elsif args.length==1
super(args[0])
self.bitmap=nil
elsif args.length==2
super(nil)
self.x=args[0]
self.y=args[1]
else
super(args[2])
self.x=args[0]
self.y=args[1]
end
@name=""
@_iconbitmap=nil
end
def dispose
clearBitmaps()
super
end
# Sets the icon's filename. Alias for setBitmap.
def name=(value)
setBitmap(value)
end
# Sets the icon's filename.
def setBitmap(file,hue=0)
oldrc=self.src_rect
clearBitmaps()
@name=file
return if file==nil
if file!=""
@_iconbitmap=AnimatedBitmap.new(file,hue)
# for compatibility
self.bitmap=@_iconbitmap ? @_iconbitmap.bitmap : nil
self.src_rect=oldrc
else
@_iconbitmap=nil
end
end
def clearBitmaps
@_iconbitmap.dispose if @_iconbitmap
@_iconbitmap=nil
self.bitmap=nil if !self.disposed?
end
def update
super
return if !@_iconbitmap
@_iconbitmap.update
if self.bitmap!=@_iconbitmap.bitmap
oldrc=self.src_rect
self.bitmap=@_iconbitmap.bitmap
self.src_rect=oldrc
end
end
end
#===============================================================================
# Old GifSprite class, retained for compatibility
#===============================================================================
class GifSprite < IconSprite
def initialize(path)
super(0,0)
setBitmap(path)
end
end
#===============================================================================
# SpriteWrapper that stores multiple bitmaps, and displays only one at once.
#===============================================================================
class ChangelingSprite < SpriteWrapper
def initialize(x=0,y=0,viewport=nil)
super(viewport)
self.x = x
self.y = y
@bitmaps = {}
@currentBitmap = nil
end
def addBitmap(key,path)
@bitmaps[key].dispose if @bitmaps[key]
@bitmaps[key] = AnimatedBitmap.new(path)
end
def changeBitmap(key)
@currentBitmap = @bitmaps[key]
self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil
end
def dispose
return if disposed?
for bm in @bitmaps.values; bm.dispose; end
@bitmaps.clear
super
end
def update
return if disposed?
for bm in @bitmaps.values; bm.update; end
self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil
end
end

View File

@@ -0,0 +1,369 @@
# Disabling animated GIF stuff because gif.dll is awful,
# but leaving the code here just in case someone wants
# to make Linux and macOS versions of it for some reason
=begin
module GifLibrary
@@loadlib = Win32API.new("Kernel32.dll","LoadLibrary",'p','')
if safeExists?("gif.dll")
PngDll = @@loadlib.call("gif.dll")
GifToPngFiles = Win32API.new("gif.dll","GifToPngFiles",'pp','l')
GifToPngFilesInMemory = Win32API.new("gif.dll","GifToPngFilesInMemory",'plp','l')
CopyDataString = Win32API.new("gif.dll","CopyDataString",'lpl','l')
FreeDataString = Win32API.new("gif.dll","FreeDataString",'l','')
else
PngDll=nil
end
def self.getDataFromResult(result)
datasize=CopyDataString.call(result,"",0)
ret=nil
if datasize!=0
data="0"*datasize
CopyDataString.call(result,data,datasize)
ret=data.unpack("V*")
end
FreeDataString.call(result)
return ret
end
end
=end
class AnimatedBitmap
def initialize(file,hue=0)
if file==nil
raise "Filename is nil (missing graphic)."
end
if file.split(/[\\\/]/)[-1][/^\[\d+(?:,\d+)?\]/] # Starts with 1 or 2 numbers in square brackets
@bitmap = PngAnimatedBitmap.new(file,hue)
else
@bitmap = GifBitmap.new(file,hue)
end
end
def [](index); @bitmap[index]; end
def width; @bitmap.bitmap.width; end
def height; @bitmap.bitmap.height; end
def length; @bitmap.length; end
def each; @bitmap.each { |item| yield item }; end
def bitmap; @bitmap.bitmap; end
def currentIndex; @bitmap.currentIndex; end
def frameDelay; @bitmap.frameDelay; end
def totalFrames; @bitmap.totalFrames; end
def disposed?; @bitmap.disposed?; end
def update; @bitmap.update; end
def dispose; @bitmap.dispose; end
def deanimate; @bitmap.deanimate; end
def copy; @bitmap.copy; end
end
class PngAnimatedBitmap
# Creates an animated bitmap from a PNG file.
def initialize(file,hue=0)
@frames=[]
@currentFrame=0
@framecount=0
panorama=RPG::Cache.load_bitmap("",file,hue)
if file.split(/[\\\/]/)[-1][/^\[(\d+)(?:,(\d+))?\]/] # Starts with 1 or 2 numbers in brackets
# File has a frame count
numFrames = $1.to_i
delay = $2.to_i
delay = 10 if delay == 0
raise "Invalid frame count in #{file}" if numFrames<=0
raise "Invalid frame delay in #{file}" if delay<=0
if panorama.width % numFrames != 0
raise "Bitmap's width (#{panorama.width}) is not divisible by frame count: #{file}"
end
@frameDelay = delay
subWidth=panorama.width/numFrames
for i in 0...numFrames
subBitmap=BitmapWrapper.new(subWidth,panorama.height)
subBitmap.blt(0,0,panorama,Rect.new(subWidth*i,0,subWidth,panorama.height))
@frames.push(subBitmap)
end
panorama.dispose
else
@frames=[panorama]
end
end
def [](index)
return @frames[index]
end
def width; self.bitmap.width; end
def height; self.bitmap.height; end
def deanimate
for i in 1...@frames.length
@frames[i].dispose
end
@frames=[@frames[0]]
@currentFrame=0
return @frames[0]
end
def bitmap
@frames[@currentFrame]
end
def currentIndex
@currentFrame
end
def frameDelay(_index)
return @frameDelay
end
def length
@frames.length
end
def each
@frames.each { |item| yield item}
end
def totalFrames
@frameDelay*@frames.length
end
def disposed?
@disposed
end
def update
return if disposed?
if @frames.length>1
@framecount+=1
if @framecount>=@frameDelay
@framecount=0
@currentFrame+=1
@currentFrame%=@frames.length
end
end
end
def dispose
if !@disposed
for i in @frames
i.dispose
end
end
@disposed=true
end
attr_accessor :frames # internal
def copy
x=self.clone
x.frames=x.frames.clone
for i in 0...x.frames.length
x.frames[i]=x.frames[i].copy
end
return x
end
end
#internal class
class GifBitmap
# Creates a bitmap from a GIF file with the specified
# optional viewport. Can also load non-animated bitmaps.
def initialize(file,hue=0)
@gifbitmaps=[]
@gifdelays=[]
@totalframes=0
@framecount=0
@currentIndex=0
@disposed=false
bitmap=nil
filestring=nil
filestrName=nil
file="" if !file
file=canonicalize(file)
begin
bitmap=RPG::Cache.load_bitmap("",file,hue)
rescue
bitmap=nil
end
if !bitmap || (bitmap.width==32 && bitmap.height==32)
if !file || file.length<1 || file[file.length-1]!=0x2F
if (filestring=pbGetFileChar(file))
filestrName=file
elsif (filestring=pbGetFileChar(file+".gif"))
filestrName=file+".gif"
elsif (filestring=pbGetFileChar(file+".png"))
filestrName=file+".png"
# elsif (filestring=pbGetFileChar(file+".jpg"))
# filestrName=file+".jpg"
# elsif (filestring=pbGetFileChar(file+".bmp"))
# filestrName=file+".bmp"
end
end
end
if bitmap && filestring && filestring[0].ord==0x47 &&
bitmap.width==32 && bitmap.height==32
#File.open("debug.txt","ab") { |f| f.puts("rejecting bitmap") }
bitmap.dispose
bitmap=nil
end
# Note: MKXP can open .gif files just fine, first frame only
if bitmap
#File.open("debug.txt","ab") { |f| f.puts("reusing bitmap") }
# Have a regular non-animated bitmap
@totalframes=1
@framecount=0
@gifbitmaps=[bitmap]
@gifdelays=[1]
else
tmpBase=File.basename(file)+"_tmp_"
filestring=pbGetFileString(filestrName) if filestring
=begin
Dir.chdir(ENV["TEMP"]) { # navigate to temp folder since game might be on a CD-ROM
if filestring && filestring[0]==0x47 && GifLibrary::PngDll
result=GifLibrary::GifToPngFilesInMemory.call(filestring,
filestring.length,tmpBase)
else
result=0
end
if result>0
@gifdelays=GifLibrary.getDataFromResult(result)
@totalframes=@gifdelays.pop
for i in 0...@gifdelays.length
@gifdelays[i]=[@gifdelays[i],1].max
bmfile=sprintf("%s%d.png",tmpBase,i)
if safeExists?(bmfile)
gifbitmap=BitmapWrapper.new(bmfile)
@gifbitmaps.push(gifbitmap)
bmfile.hue_change(hue) if hue!=0
if hue==0 && @gifdelays.length==1
RPG::Cache.setKey(file,gifbitmap)
end
File.delete(bmfile)
else
@gifbitmaps.push(BitmapWrapper.new(32,32))
end
end
end
}
=end
if @gifbitmaps.length==0
@gifbitmaps=[BitmapWrapper.new(32,32)]
@gifdelays=[1]
end
if @gifbitmaps.length==1
RPG::Cache.setKey(file,@gifbitmaps[0])
end
end
end
def [](index)
return @gifbitmaps[index]
end
def deanimate
for i in 1...@gifbitmaps.length
@gifbitmaps[i].dispose
end
@gifbitmaps=[@gifbitmaps[0]]
@currentIndex=0
return @gifbitmaps[0]
end
def bitmap
@gifbitmaps[@currentIndex]
end
def currentIndex
@currentIndex
end
def frameDelay(index)
return @gifdelay[index]/2 # Due to frame count being incremented by 2
end
def length
@gifbitmaps.length
end
def each
@gifbitmaps.each { |item| yield item }
end
def totalFrames
@totalframes/2 # Due to frame count being incremented by 2
end
def disposed?
@disposed
end
def width
@gifbitmaps.length==0 ? 0 : @gifbitmaps[0].width
end
def height
@gifbitmaps.length==0 ? 0 : @gifbitmaps[0].height
end
# This function must be called in order to animate the GIF image.
def update
return if disposed?
if @gifbitmaps.length>0
@framecount+=2
@framecount=@totalframes<=0 ? 0 : @framecount%@totalframes
frametoshow=0
for i in 0...@gifdelays.length
frametoshow=i if @gifdelays[i]<=@framecount
end
@currentIndex=frametoshow
end
end
def dispose
if !@disposed
for i in @gifbitmaps
i.dispose
end
end
@disposed=true
end
attr_accessor :gifbitmaps # internal
attr_accessor :gifdelays # internal
def copy
x=self.clone
x.gifbitmaps=x.gifbitmaps.clone
x.gifdelays=x.gifdelays.clone
for i in 0...x.gifbitmaps.length
x.gifbitmaps[i]=x.gifbitmaps[i].copy
end
return x
end
end
def pbGetTileBitmap(filename, tile_id, hue, width = 1, height = 1)
return RPG::Cache.tileEx(filename, tile_id, hue, width, height) { |f|
AnimatedBitmap.new("Graphics/Tilesets/"+filename).deanimate
}
end
def pbGetTileset(name,hue=0)
return AnimatedBitmap.new("Graphics/Tilesets/"+name,hue).deanimate
end
def pbGetAutotile(name,hue=0)
return AnimatedBitmap.new("Graphics/Autotiles/"+name,hue).deanimate
end
def pbGetAnimation(name,hue=0)
return AnimatedBitmap.new("Graphics/Animations/"+name,hue).deanimate
end

View File

@@ -0,0 +1,232 @@
#===============================================================================
#
#===============================================================================
class Plane
def update; end
def refresh; end
end
#===============================================================================
# This class works around a limitation that planes are always
# 640 by 480 pixels in size regardless of the window's size.
#===============================================================================
class LargePlane < Plane
attr_accessor :borderX
attr_accessor :borderY
def initialize(viewport=nil)
@__sprite=Sprite.new(viewport)
@__disposed=false
@__ox=0
@__oy=0
@__bitmap=nil
@__visible=true
@__sprite.visible=false
@borderX=0
@borderY=0
end
def disposed?
return @__disposed
end
def dispose
if !@__disposed
@__sprite.bitmap.dispose if @__sprite.bitmap
@__sprite.dispose
@__sprite=nil
@__bitmap=nil
@__disposed=true
end
#super
end
def ox; @__ox; end
def oy; @__oy; end
def ox=(value);
return if @__ox==value
@__ox = value
refresh
end
def oy=(value);
return if @__oy==value
@__oy = value
refresh
end
def bitmap
return @__bitmap
end
def bitmap=(value)
if value==nil
if @__bitmap!=nil
@__bitmap=nil
@__sprite.visible=(@__visible && !@__bitmap.nil?)
end
elsif @__bitmap!=value && !value.disposed?
@__bitmap=value
refresh
elsif value.disposed?
if @__bitmap!=nil
@__bitmap=nil
@__sprite.visible=(@__visible && !@__bitmap.nil?)
end
end
end
def viewport; @__sprite.viewport; end
def zoom_x; @__sprite.zoom_x; end
def zoom_y; @__sprite.zoom_y; end
def opacity; @__sprite.opacity; end
def blend_type; @__sprite.blend_type; end
def visible; @__visible; end
def z; @__sprite.z; end
def color; @__sprite.color; end
def tone; @__sprite.tone; end
def zoom_x=(v);
return if @__sprite.zoom_x==v
@__sprite.zoom_x = v
refresh
end
def zoom_y=(v);
return if @__sprite.zoom_y==v
@__sprite.zoom_y = v
refresh
end
def opacity=(v); @__sprite.opacity=(v); end
def blend_type=(v); @__sprite.blend_type=(v); end
def visible=(v); @__visible=v; @__sprite.visible=(@__visible && !@__bitmap.nil?); end
def z=(v); @__sprite.z=(v); end
def color=(v); @__sprite.color=(v); end
def tone=(v); @__sprite.tone=(v); end
def update; ;end
def refresh
@__sprite.visible = (@__visible && !@__bitmap.nil?)
if @__bitmap
if !@__bitmap.disposed?
@__ox += @__bitmap.width*@__sprite.zoom_x if @__ox<0
@__oy += @__bitmap.height*@__sprite.zoom_y if @__oy<0
@__ox -= @__bitmap.width*@__sprite.zoom_x if @__ox>@__bitmap.width
@__oy -= @__bitmap.height*@__sprite.zoom_y if @__oy>@__bitmap.height
dwidth = (Graphics.width/@__sprite.zoom_x+@borderX).to_i # +2
dheight = (Graphics.height/@__sprite.zoom_y+@borderY).to_i # +2
@__sprite.bitmap = ensureBitmap(@__sprite.bitmap,dwidth,dheight)
@__sprite.bitmap.clear
tileBitmap(@__sprite.bitmap,@__bitmap,@__bitmap.rect)
else
@__sprite.visible = false
end
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,srcbitmap,srcrect)
return if !srcbitmap || srcbitmap.disposed?
dstrect = dstbitmap.rect
left = (dstrect.x-@__ox/@__sprite.zoom_x).to_i
top = (dstrect.y-@__oy/@__sprite.zoom_y).to_i
while left>0; left -= srcbitmap.width; end
while top>0; top -= srcbitmap.height; end
y = top
while y<dstrect.height
x = left
while x<dstrect.width
dstbitmap.blt(x+@borderX,y+@borderY,srcbitmap,srcrect)
x += srcrect.width
end
y += srcrect.height
end
end
end
#===============================================================================
# A plane class that displays a single color.
#===============================================================================
class ColoredPlane < LargePlane
def initialize(color,viewport=nil)
super(viewport)
self.bitmap=Bitmap.new(32,32)
setPlaneColor(color)
end
def dispose
self.bitmap.dispose if self.bitmap
super
end
def update; super; end
def setPlaneColor(value)
self.bitmap.fill_rect(0,0,self.bitmap.width,self.bitmap.height,value)
self.refresh
end
end
#===============================================================================
# A plane class that supports animated images.
#===============================================================================
class AnimatedPlane < LargePlane
def initialize(viewport)
super(viewport)
@bitmap=nil
end
def dispose
clearBitmaps()
super
end
def update
super
if @bitmap
@bitmap.update
self.bitmap=@bitmap.bitmap
end
end
def clearBitmaps
@bitmap.dispose if @bitmap
@bitmap=nil
self.bitmap=nil if !self.disposed?
end
def setPanorama(file, hue=0)
clearBitmaps()
return if file==nil
@bitmap=AnimatedBitmap.new("Graphics/Panoramas/"+file,hue)
end
def setFog(file, hue=0)
clearBitmaps()
return if file==nil
@bitmap=AnimatedBitmap.new("Graphics/Fogs/"+file,hue)
end
def setBitmap(file, hue=0)
clearBitmaps()
return if file==nil
@bitmap=AnimatedBitmap.new(file,hue)
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,923 @@
#===============================================================================
#
#===============================================================================
class Scene_Map
def updatemini
oldmws=$game_temp.message_window_showing
oldvis=false
$game_temp.message_window_showing=true
loop do
$game_map.update
$game_player.update
$game_system.update
if $game_screen
$game_screen.update
else
$game_map.screen.update
end
break unless $game_temp.player_transferring
transfer_player
break if $game_temp.transition_processing
end
$game_temp.message_window_showing=oldmws
@spriteset.update if @spriteset
@message_window.update if @message_window
end
end
class Scene_Battle
def updatemini
if self.respond_to?("update_basic")
update_basic(true)
update_info_viewport # Update information viewport
else
oldmws=$game_temp.message_window_showing
$game_temp.message_window_showing=true
# Update system (timer) and screen
$game_system.update
if $game_screen
$game_screen.update
else
$game_map.screen.update
end
# If timer has reached 0
if $game_system.timer_working and $game_system.timer == 0
# Abort battle
$game_temp.battle_abort = true
end
# Update windows
@help_window.update if @help_window
@party_command_window.update if @party_command_window
@actor_command_window.update if @actor_command_window
@status_window.update if @status_window
$game_temp.message_window_showing=oldmws
@message_window.update if @message_window
# Update sprite set
@spriteset.update if @spriteset
end
end
end
def pbMapInterpreter
if $game_map.respond_to?("interpreter")
return $game_map.interpreter
elsif $game_system
return $game_system.map_interpreter
end
return nil
end
def pbMapInterpreterRunning?
interp = pbMapInterpreter
return interp && interp.running?
end
def pbRefreshSceneMap
if $scene && $scene.is_a?(Scene_Map)
if $scene.respond_to?("miniupdate")
$scene.miniupdate
else
$scene.updatemini
end
elsif $scene && $scene.is_a?(Scene_Battle)
$scene.updatemini
end
end
def pbUpdateSceneMap
if $scene && $scene.is_a?(Scene_Map) && !pbIsFaded?
if $scene.respond_to?("miniupdate")
$scene.miniupdate
else
$scene.updatemini
end
elsif $scene && $scene.is_a?(Scene_Battle)
$scene.updatemini
end
end
#===============================================================================
#
#===============================================================================
def pbEventCommentInput(*args)
parameters = []
list = *args[0].list # Event or event page
elements = *args[1] # Number of elements
trigger = *args[2] # Trigger
return nil if list == nil
return nil unless list.is_a?(Array)
for item in list
next unless item.code == 108 || item.code == 408
if item.parameters[0] == trigger
start = list.index(item) + 1
finish = start + elements
for id in start...finish
next if !list[id]
parameters.push(list[id].parameters[0])
end
return parameters
end
end
return nil
end
def pbCurrentEventCommentInput(elements,trigger)
return nil if !pbMapInterpreterRunning?
event = pbMapInterpreter.get_character(0)
return nil if !event
return pbEventCommentInput(event,elements,trigger)
end
#===============================================================================
#
#===============================================================================
class ChooseNumberParams
def initialize
@maxDigits=0
@minNumber=0
@maxNumber=0
@skin=nil
@messageSkin=nil
@negativesAllowed=false
@initialNumber=0
@cancelNumber=nil
end
def setMessageSkin(value)
@messageSkin=value
end
def messageSkin # Set the full path for the message's window skin
@messageSkin
end
def setSkin(value)
@skin=value
end
def skin
@skin
end
def setNegativesAllowed(value)
@negativeAllowed=value
end
def negativesAllowed
@negativeAllowed ? true : false
end
def setRange(minNumber,maxNumber)
maxNumber=minNumber if minNumber>maxNumber
@maxDigits=0
@minNumber=minNumber
@maxNumber=maxNumber
end
def setDefaultValue(number)
@initialNumber=number
@cancelNumber=nil
end
def setInitialValue(number)
@initialNumber=number
end
def setCancelValue(number)
@cancelNumber=number
end
def initialNumber
return clamp(@initialNumber,self.minNumber,self.maxNumber)
end
def cancelNumber
return @cancelNumber || self.initialNumber
end
def minNumber
ret=0
if @maxDigits>0
ret=-((10**@maxDigits)-1)
else
ret=@minNumber
end
ret=0 if !@negativeAllowed && ret<0
return ret
end
def maxNumber
ret=0
if @maxDigits>0
ret=((10**@maxDigits)-1)
else
ret=@maxNumber
end
ret=0 if !@negativeAllowed && ret<0
return ret
end
def setMaxDigits(value)
@maxDigits=[1,value].max
end
def maxDigits
if @maxDigits>0
return @maxDigits
else
return [numDigits(self.minNumber),numDigits(self.maxNumber)].max
end
end
private
def clamp(v,mn,mx)
return v<mn ? mn : (v>mx ? mx : v)
end
def numDigits(number)
ans = 1
number=number.abs
while number >= 10
ans+=1
number/=10
end
return ans
end
end
def pbChooseNumber(msgwindow,params)
return 0 if !params
ret=0
maximum=params.maxNumber
minimum=params.minNumber
defaultNumber=params.initialNumber
cancelNumber=params.cancelNumber
cmdwindow=Window_InputNumberPokemon.new(params.maxDigits)
cmdwindow.z=99999
cmdwindow.visible=true
cmdwindow.setSkin(params.skin) if params.skin
cmdwindow.sign=params.negativesAllowed # must be set before number
cmdwindow.number=defaultNumber
pbPositionNearMsgWindow(cmdwindow,msgwindow,:right)
loop do
Graphics.update
Input.update
pbUpdateSceneMap
cmdwindow.update
msgwindow.update if msgwindow
yield if block_given?
if Input.trigger?(Input::USE)
ret=cmdwindow.number
if ret>maximum
pbPlayBuzzerSE()
elsif ret<minimum
pbPlayBuzzerSE()
else
pbPlayDecisionSE()
break
end
elsif Input.trigger?(Input::BACK)
pbPlayCancelSE()
ret=cancelNumber
break
end
end
cmdwindow.dispose
Input.update
return ret
end
#===============================================================================
#
#===============================================================================
class FaceWindowVX < SpriteWindow_Base
def initialize(face)
super(0,0,128,128)
faceinfo=face.split(",")
facefile=pbResolveBitmap("Graphics/Faces/"+faceinfo[0])
facefile=pbResolveBitmap("Graphics/Pictures/"+faceinfo[0]) if !facefile
self.contents.dispose if self.contents
@faceIndex=faceinfo[1].to_i
@facebitmaptmp=AnimatedBitmap.new(facefile)
@facebitmap=BitmapWrapper.new(96,96)
@facebitmap.blt(0,0,@facebitmaptmp.bitmap,Rect.new(
(@faceIndex % 4) * 96,
(@faceIndex / 4) * 96, 96, 96
))
self.contents=@facebitmap
end
def update
super
if @facebitmaptmp.totalFrames>1
@facebitmaptmp.update
@facebitmap.blt(0,0,@facebitmaptmp.bitmap,Rect.new(
(@faceIndex % 4) * 96,
(@faceIndex / 4) * 96, 96, 96
))
end
end
def dispose
@facebitmaptmp.dispose
@facebitmap.dispose if @facebitmap
super
end
end
#===============================================================================
#
#===============================================================================
def pbGetBasicMapNameFromId(id)
begin
map = pbLoadMapInfos
return "" if !map
return map[id].name
rescue
return ""
end
end
def pbGetMapNameFromId(id)
map=pbGetBasicMapNameFromId(id)
map.gsub!(/\\PN/,$Trainer.name) if $Trainer
return map
end
def pbCsvField!(str)
ret=""
str.sub!(/\A\s*/,"")
if str[0,1]=="\""
str[0,1]=""
escaped=false
fieldbytes=0
str.scan(/./) do |s|
fieldbytes+=s.length
break if s=="\"" && !escaped
if s=="\\" && !escaped
escaped=true
else
ret+=s
escaped=false
end
end
str[0,fieldbytes]=""
if !str[/\A\s*,/] && !str[/\A\s*$/]
raise _INTL("Invalid quoted field (in: {1})",ret)
end
str[0,str.length]=$~.post_match
else
if str[/,/]
str[0,str.length]=$~.post_match
ret=$~.pre_match
else
ret=str.clone
str[0,str.length]=""
end
ret.gsub!(/\s+$/,"")
end
return ret
end
def pbCsvPosInt!(str)
ret=pbCsvField!(str)
if !ret[/\A\d+$/]
raise _INTL("Field {1} is not a positive integer",ret)
end
return ret.to_i
end
#===============================================================================
# Money and coins windows
#===============================================================================
def pbGetGoldString
moneyString=""
begin
moneyString=_INTL("${1}",$Trainer.money.to_s_formatted)
rescue
if $data_system.respond_to?("words")
moneyString=_INTL("{1} {2}",$game_party.gold,$data_system.words.gold)
else
moneyString=_INTL("{1} {2}",$game_party.gold,Vocab.gold)
end
end
return moneyString
end
def pbDisplayGoldWindow(msgwindow)
moneyString=pbGetGoldString()
goldwindow=Window_AdvancedTextPokemon.new(_INTL("Money:\n<ar>{1}</ar>",moneyString))
goldwindow.setSkin("Graphics/Windowskins/goldskin")
goldwindow.resizeToFit(goldwindow.text,Graphics.width)
goldwindow.width=160 if goldwindow.width<=160
if msgwindow.y==0
goldwindow.y=Graphics.height-goldwindow.height
else
goldwindow.y=0
end
goldwindow.viewport=msgwindow.viewport
goldwindow.z=msgwindow.z
return goldwindow
end
def pbDisplayCoinsWindow(msgwindow,goldwindow)
coinString=($PokemonGlobal) ? $PokemonGlobal.coins.to_s_formatted : "0"
coinwindow=Window_AdvancedTextPokemon.new(_INTL("Coins:\n<ar>{1}</ar>",coinString))
coinwindow.setSkin("Graphics/Windowskins/goldskin")
coinwindow.resizeToFit(coinwindow.text,Graphics.width)
coinwindow.width=160 if coinwindow.width<=160
if msgwindow.y==0
coinwindow.y=(goldwindow) ? goldwindow.y-coinwindow.height : Graphics.height-coinwindow.height
else
coinwindow.y=(goldwindow) ? goldwindow.height : 0
end
coinwindow.viewport=msgwindow.viewport
coinwindow.z=msgwindow.z
return coinwindow
end
#===============================================================================
#
#===============================================================================
def pbCreateStatusWindow(viewport=nil)
msgwindow=Window_AdvancedTextPokemon.new("")
if !viewport
msgwindow.z=99999
else
msgwindow.viewport=viewport
end
msgwindow.visible=false
msgwindow.letterbyletter=false
pbBottomLeftLines(msgwindow,2)
skinfile=MessageConfig.pbGetSpeechFrame()
msgwindow.setSkin(skinfile)
return msgwindow
end
def pbCreateMessageWindow(viewport=nil,skin=nil)
msgwindow=Window_AdvancedTextPokemon.new("")
if !viewport
msgwindow.z=99999
else
msgwindow.viewport=viewport
end
msgwindow.visible=true
msgwindow.letterbyletter=true
msgwindow.back_opacity=MessageConfig::WindowOpacity
pbBottomLeftLines(msgwindow,2)
$game_temp.message_window_showing=true if $game_temp
skin=MessageConfig.pbGetSpeechFrame() if !skin
msgwindow.setSkin(skin)
return msgwindow
end
def pbDisposeMessageWindow(msgwindow)
$game_temp.message_window_showing=false if $game_temp
msgwindow.dispose
end
#===============================================================================
# Main message-displaying function
#===============================================================================
def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
return if !msgwindow
oldletterbyletter=msgwindow.letterbyletter
msgwindow.letterbyletter=(letterbyletter) ? true : false
ret=nil
commands=nil
facewindow=nil
goldwindow=nil
coinwindow=nil
cmdvariable=0
cmdIfCancel=0
msgwindow.waitcount=0
autoresume=false
text=message.clone
msgback=nil
linecount=(Graphics.height>400) ? 3 : 2
### Text replacement
text.gsub!(/\\sign\[([^\]]*)\]/i) { # \sign[something] gets turned into
next "\\op\\cl\\ts[]\\w["+$1+"]" # \op\cl\ts[]\w[something]
}
text.gsub!(/\\\\/,"\5")
text.gsub!(/\\1/,"\1")
if $game_actors
text.gsub!(/\\n\[([1-8])\]/i) {
m = $1.to_i
next $game_actors[m].name
}
end
text.gsub!(/\\pn/i,$Trainer.name) if $Trainer
text.gsub!(/\\pm/i,_INTL("${1}",$Trainer.money.to_s_formatted)) if $Trainer
text.gsub!(/\\n/i,"\n")
text.gsub!(/\\\[([0-9a-f]{8,8})\]/i) { "<c2="+$1+">" }
text.gsub!(/\\pg/i,"\\b") if $Trainer && $Trainer.male?
text.gsub!(/\\pg/i,"\\r") if $Trainer && $Trainer.female?
text.gsub!(/\\pog/i,"\\r") if $Trainer && $Trainer.male?
text.gsub!(/\\pog/i,"\\b") if $Trainer && $Trainer.female?
text.gsub!(/\\pg/i,"")
text.gsub!(/\\pog/i,"")
text.gsub!(/\\b/i,"<c3=3050C8,D0D0C8>")
text.gsub!(/\\r/i,"<c3=E00808,D0D0C8>")
text.gsub!(/\\[Ww]\[([^\]]*)\]/) {
w = $1.to_s
if w==""
msgwindow.windowskin = nil
else
msgwindow.setSkin("Graphics/Windowskins/#{w}",false)
end
next ""
}
isDarkSkin = isDarkWindowskin(msgwindow.windowskin)
text.gsub!(/\\[Cc]\[([0-9]+)\]/) {
m = $1.to_i
next getSkinColor(msgwindow.windowskin,m,isDarkSkin)
}
loop do
last_text = text.clone
text.gsub!(/\\v\[([0-9]+)\]/i) { $game_variables[$1.to_i] }
break if text == last_text
end
loop do
last_text = text.clone
text.gsub!(/\\l\[([0-9]+)\]/i) {
linecount = [1,$1.to_i].max
next ""
}
break if text == last_text
end
colortag = ""
if $game_system && $game_system.respond_to?("message_frame") &&
$game_system.message_frame != 0
colortag = getSkinColor(msgwindow.windowskin,0,true)
else
colortag = getSkinColor(msgwindow.windowskin,0,isDarkSkin)
end
text = colortag+text
### Controls
textchunks=[]
controls=[]
while text[/(?:\\(f|ff|ts|cl|me|se|wt|wtnp|ch)\[([^\]]*)\]|\\(g|cn|wd|wm|op|cl|wu|\.|\||\!|\^))/i]
textchunks.push($~.pre_match)
if $~[1]
controls.push([$~[1].downcase,$~[2],-1])
else
controls.push([$~[3].downcase,"",-1])
end
text=$~.post_match
end
textchunks.push(text)
for chunk in textchunks
chunk.gsub!(/\005/,"\\")
end
textlen = 0
for i in 0...controls.length
control = controls[i][0]
case control
when "wt", "wtnp", ".", "|"
textchunks[i] += "\2"
when "!"
textchunks[i] += "\1"
end
textlen += toUnformattedText(textchunks[i]).scan(/./m).length
controls[i][2] = textlen
end
text = textchunks.join("")
unformattedText = toUnformattedText(text)
signWaitCount = 0
signWaitTime = Graphics.frame_rate/2
haveSpecialClose = false
specialCloseSE = ""
for i in 0...controls.length
control = controls[i][0]
param = controls[i][1]
case control
when "op"
signWaitCount = signWaitTime+1
when "cl"
text = text.sub(/\001\z/,"") # fix: '$' can match end of line as well
haveSpecialClose = true
specialCloseSE = param
when "f"
facewindow.dispose if facewindow
facewindow = PictureWindow.new("Graphics/Pictures/#{param}")
when "ff"
facewindow.dispose if facewindow
facewindow = FaceWindowVX.new(param)
when "ch"
cmds = param.clone
cmdvariable = pbCsvPosInt!(cmds)
cmdIfCancel = pbCsvField!(cmds).to_i
commands = []
while cmds.length>0
commands.push(pbCsvField!(cmds))
end
when "wtnp", "^"
text = text.sub(/\001\z/,"") # fix: '$' can match end of line as well
when "se"
if controls[i][2]==0
startSE = param
controls[i] = nil
end
end
end
if startSE!=nil
pbSEPlay(pbStringToAudioFile(startSE))
elsif signWaitCount==0 && letterbyletter
pbPlayDecisionSE()
end
########## Position message window ##############
pbRepositionMessageWindow(msgwindow,linecount)
if facewindow
pbPositionNearMsgWindow(facewindow,msgwindow,:left)
facewindow.viewport = msgwindow.viewport
facewindow.z = msgwindow.z
end
atTop = (msgwindow.y==0)
########## Show text #############################
msgwindow.text = text
Graphics.frame_reset if Graphics.frame_rate>40
loop do
if signWaitCount>0
signWaitCount -= 1
if atTop
msgwindow.y = -msgwindow.height*signWaitCount/signWaitTime
else
msgwindow.y = Graphics.height-msgwindow.height*(signWaitTime-signWaitCount)/signWaitTime
end
end
for i in 0...controls.length
next if !controls[i]
next if controls[i][2]>msgwindow.position || msgwindow.waitcount!=0
control = controls[i][0]
param = controls[i][1]
case control
when "f"
facewindow.dispose if facewindow
facewindow = PictureWindow.new("Graphics/Pictures/#{param}")
pbPositionNearMsgWindow(facewindow,msgwindow,:left)
facewindow.viewport = msgwindow.viewport
facewindow.z = msgwindow.z
when "ff"
facewindow.dispose if facewindow
facewindow = FaceWindowVX.new(param)
pbPositionNearMsgWindow(facewindow,msgwindow,:left)
facewindow.viewport = msgwindow.viewport
facewindow.z = msgwindow.z
when "g" # Display gold window
goldwindow.dispose if goldwindow
goldwindow = pbDisplayGoldWindow(msgwindow)
when "cn" # Display coins window
coinwindow.dispose if coinwindow
coinwindow = pbDisplayCoinsWindow(msgwindow,goldwindow)
when "wu"
msgwindow.y = 0
atTop = true
msgback.y = msgwindow.y if msgback
pbPositionNearMsgWindow(facewindow,msgwindow,:left)
msgwindow.y = -msgwindow.height*signWaitCount/signWaitTime
when "wm"
atTop = false
msgwindow.y = (Graphics.height-msgwindow.height)/2
msgback.y = msgwindow.y if msgback
pbPositionNearMsgWindow(facewindow,msgwindow,:left)
when "wd"
atTop = false
msgwindow.y = Graphics.height-msgwindow.height
msgback.y = msgwindow.y if msgback
pbPositionNearMsgWindow(facewindow,msgwindow,:left)
msgwindow.y = Graphics.height-msgwindow.height*(signWaitTime-signWaitCount)/signWaitTime
when "ts" # Change text speed
msgwindow.textspeed = (param=="") ? -999 : param.to_i
when "." # Wait 0.25 seconds
msgwindow.waitcount += Graphics.frame_rate/4
when "|" # Wait 1 second
msgwindow.waitcount += Graphics.frame_rate
when "wt" # Wait X/20 seconds
param = param.sub(/\A\s+/,"").sub(/\s+\z/,"")
msgwindow.waitcount += param.to_i*Graphics.frame_rate/20
when "wtnp" # Wait X/20 seconds, no pause
param = param.sub(/\A\s+/,"").sub(/\s+\z/,"")
msgwindow.waitcount = param.to_i*Graphics.frame_rate/20
autoresume = true
when "^" # Wait, no pause
autoresume = true
when "se" # Play SE
pbSEPlay(pbStringToAudioFile(param))
when "me" # Play ME
pbMEPlay(pbStringToAudioFile(param))
end
controls[i] = nil
end
break if !letterbyletter
Graphics.update
Input.update
facewindow.update if facewindow
if autoresume && msgwindow.waitcount==0
msgwindow.resume if msgwindow.busy?
break if !msgwindow.busy?
end
if Input.trigger?(Input::USE) || Input.trigger?(Input::BACK)
if msgwindow.busy?
pbPlayDecisionSE if msgwindow.pausing?
msgwindow.resume
else
break if signWaitCount==0
end
end
pbUpdateSceneMap
msgwindow.update
yield if block_given?
break if (!letterbyletter || commandProc || commands) && !msgwindow.busy?
end
Input.update # Must call Input.update again to avoid extra triggers
msgwindow.letterbyletter=oldletterbyletter
if commands
$game_variables[cmdvariable]=pbShowCommands(msgwindow,commands,cmdIfCancel)
$game_map.need_refresh = true if $game_map
end
if commandProc
ret=commandProc.call(msgwindow)
end
msgback.dispose if msgback
goldwindow.dispose if goldwindow
coinwindow.dispose if coinwindow
facewindow.dispose if facewindow
if haveSpecialClose
pbSEPlay(pbStringToAudioFile(specialCloseSE))
atTop = (msgwindow.y==0)
for i in 0..signWaitTime
if atTop
msgwindow.y = -msgwindow.height*i/signWaitTime
else
msgwindow.y = Graphics.height-msgwindow.height*(signWaitTime-i)/signWaitTime
end
Graphics.update
Input.update
pbUpdateSceneMap
msgwindow.update
end
end
return ret
end
#===============================================================================
# Message-displaying functions
#===============================================================================
def pbMessage(message,commands=nil,cmdIfCancel=0,skin=nil,defaultCmd=0,&block)
ret = 0
msgwindow = pbCreateMessageWindow(nil,skin)
if commands
ret = pbMessageDisplay(msgwindow,message,true,
proc { |msgwindow|
next Kernel.pbShowCommands(msgwindow,commands,cmdIfCancel,defaultCmd,&block)
},&block)
else
pbMessageDisplay(msgwindow,message,&block)
end
pbDisposeMessageWindow(msgwindow)
Input.update
return ret
end
def pbConfirmMessage(message,&block)
return (pbMessage(message,[_INTL("Yes"),_INTL("No")],2,&block)==0)
end
def pbConfirmMessageSerious(message,&block)
return (pbMessage(message,[_INTL("No"),_INTL("Yes")],1,&block)==1)
end
def pbMessageChooseNumber(message,params,&block)
msgwindow = pbCreateMessageWindow(nil,params.messageSkin)
ret = pbMessageDisplay(msgwindow,message,true,
proc { |msgwindow|
next pbChooseNumber(msgwindow,params,&block)
},&block)
pbDisposeMessageWindow(msgwindow)
return ret
end
def pbShowCommands(msgwindow,commands=nil,cmdIfCancel=0,defaultCmd=0)
return 0 if !commands
cmdwindow=Window_CommandPokemonEx.new(commands)
cmdwindow.z=99999
cmdwindow.visible=true
cmdwindow.resizeToFit(cmdwindow.commands)
pbPositionNearMsgWindow(cmdwindow,msgwindow,:right)
cmdwindow.index=defaultCmd
command=0
loop do
Graphics.update
Input.update
cmdwindow.update
msgwindow.update if msgwindow
yield if block_given?
if Input.trigger?(Input::BACK)
if cmdIfCancel>0
command=cmdIfCancel-1
break
elsif cmdIfCancel<0
command=cmdIfCancel
break
end
end
if Input.trigger?(Input::USE)
command=cmdwindow.index
break
end
pbUpdateSceneMap
end
ret=command
cmdwindow.dispose
Input.update
return ret
end
def pbShowCommandsWithHelp(msgwindow,commands,help,cmdIfCancel=0,defaultCmd=0)
msgwin=msgwindow
msgwin=pbCreateMessageWindow(nil) if !msgwindow
oldlbl=msgwin.letterbyletter
msgwin.letterbyletter=false
if commands
cmdwindow=Window_CommandPokemonEx.new(commands)
cmdwindow.z=99999
cmdwindow.visible=true
cmdwindow.resizeToFit(cmdwindow.commands)
cmdwindow.height=msgwin.y if cmdwindow.height>msgwin.y
cmdwindow.index=defaultCmd
command=0
msgwin.text=help[cmdwindow.index]
msgwin.width=msgwin.width # Necessary evil to make it use the proper margins
loop do
Graphics.update
Input.update
oldindex=cmdwindow.index
cmdwindow.update
if oldindex!=cmdwindow.index
msgwin.text=help[cmdwindow.index]
end
msgwin.update
yield if block_given?
if Input.trigger?(Input::BACK)
if cmdIfCancel>0
command=cmdIfCancel-1
break
elsif cmdIfCancel<0
command=cmdIfCancel
break
end
end
if Input.trigger?(Input::USE)
command=cmdwindow.index
break
end
pbUpdateSceneMap
end
ret=command
cmdwindow.dispose
Input.update
end
msgwin.letterbyletter=oldlbl
msgwin.dispose if !msgwindow
return ret
end
# frames is the number of 1/20 seconds to wait for
def pbMessageWaitForInput(msgwindow,frames,showPause=false)
return if !frames || frames<=0
msgwindow.startPause if msgwindow && showPause
frames = frames*Graphics.frame_rate/20
frames.times do
Graphics.update
Input.update
msgwindow.update if msgwindow
pbUpdateSceneMap
if Input.trigger?(Input::USE) || Input.trigger?(Input::BACK)
break
end
yield if block_given?
end
msgwindow.stopPause if msgwindow && showPause
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,519 @@
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
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
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
#===============================================================================
# PictureEx
#===============================================================================
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); cb.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, pitch=nil, cb=nil)
delay = ensureDelay(delay)
@processes.push([Processes::SE,delay,0,0,cb,seFile,volume,pitch])
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],process[7])
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

View File

@@ -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