Rearranged some script files

This commit is contained in:
Maruno17
2020-09-05 22:34:32 +01:00
parent 5d3189174c
commit 5073f86190
188 changed files with 250 additions and 239 deletions

View File

@@ -0,0 +1,497 @@
class Hangup < Exception; end
def strsplit(str,re)
ret=[]
tstr=str
while re=~tstr
ret[ret.length]=$~.pre_match
tstr=$~.post_match
end
ret[ret.length]=tstr if ret.length
return ret
end
def canonicalize(c)
csplit = strsplit(c,/[\/\\]/)
pos = -1
ret = []
retstr = ""
for x in csplit
if x=="."
elsif x==".."
if pos>=0
ret.delete_at(pos)
pos -= 1
end
else
ret.push(x)
pos += 1
end
end
for i in 0...ret.length
retstr += "/" if i>0
retstr += ret[i]
end
return retstr
end
#####################################################################
class WeakRef
@@id_map = {}
@@id_rev_map = {}
@@final = lambda { |id|
__old_status = Thread.critical
Thread.critical = true
begin
rids = @@id_map[id]
if rids
for rid in rids
@@id_rev_map.delete(rid)
end
@@id_map.delete(id)
end
rid = @@id_rev_map[id]
if rid
@@id_rev_map.delete(id)
@@id_map[rid].delete(id)
@@id_map.delete(rid) if @@id_map[rid].empty?
end
ensure
Thread.critical = __old_status
end
}
# Create a new WeakRef from +orig+.
def initialize(orig)
__setobj__(orig)
end
def __getobj__
unless @@id_rev_map[self.__id__] == @__id
return nil
end
begin
ObjectSpace._id2ref(@__id)
rescue RangeError
return nil
end
end
def __setobj__(obj)
@__id = obj.__id__
__old_status = Thread.critical
begin
Thread.critical = true
unless @@id_rev_map.key?(self)
ObjectSpace.define_finalizer obj, @@final
ObjectSpace.define_finalizer self, @@final
end
@@id_map[@__id] = [] unless @@id_map[@__id]
ensure
Thread.critical = __old_status
end
@@id_map[@__id].push self.__id__
@@id_rev_map[self.__id__] = @__id
end
# Returns true if the referenced object still exists, and false if it has
# been garbage collected.
def weakref_alive?
@@id_rev_map[self.__id__] == @__id
end
end
class WeakHashtable
include Enumerable
def initialize
@hash={}
end
def clear
@hash.clear
end
def delete(value)
@hash.delete(value)
end
def include?(value)
@hash.include?(value)
end
def each
@hash.each { |i| yield i }
end
def keys
@hash.keys
end
def values
@hash.values
end
def [](key)
o=@hash[key]
return o if !o
if o.weakref_alive?
o=o.__getobj__
else
@hash.delete(key)
o=nil
end
return o
end
def []=(key,o)
if o!=nil
o=WeakRef.new(o)
end
@hash[key]=o
end
end
# Cache from RPG Maker VX library
module Cache
def self.system(x,hue=0)
BitmapCache.load_bitmap("Graphics/System/"+x,hue, true)
end
def self.character(x,hue=0)
BitmapCache.load_bitmap("Graphics/Characters/"+x,hue, true)
end
def self.picture(x,hue=0)
BitmapCache.load_bitmap("Graphics/Pictures/"+x,hue, true)
end
def self.animation(x,hue=0)
BitmapCache.load_bitmap("Graphics/Animations/"+x,hue, true)
end
def self.battler(x,hue=0)
BitmapCache.load_bitmap("Graphics/Battlers/"+x,hue, true)
end
def self.face(x,hue=0)
BitmapCache.load_bitmap("Graphics/Faces/"+x,hue, true)
end
def self.parallax(x,hue=0)
BitmapCache.load_bitmap("Graphics/Parallaxes/"+x,hue, true)
end
def self.clear
BitmapCache.clear()
end
def self.load_bitmap(dir,name,hue=0)
BitmapCache.load_bitmap(dir+name,hue, true)
end
end
# RPG::Cache from RPG Maker XP library
module RPG
module Cache
def self.load_bitmap(folder_name, filename, hue = 0)
BitmapCache.load_bitmap(folder_name+filename.to_s,hue, true)
end
def self.animation(filename, hue)
self.load_bitmap("Graphics/Animations/", filename, hue)
end
def self.autotile(filename)
self.load_bitmap("Graphics/Autotiles/", filename)
end
def self.battleback(filename)
self.load_bitmap("Graphics/Battlebacks/", filename)
end
def self.battler(filename, hue)
self.load_bitmap("Graphics/Battlers/", filename, hue)
end
def self.character(filename, hue)
self.load_bitmap("Graphics/Characters/", filename, hue)
end
def self.fog(filename, hue)
self.load_bitmap("Graphics/Fogs/", filename, hue)
end
def self.gameover(filename)
self.load_bitmap("Graphics/Gameovers/", filename)
end
def self.icon(filename)
self.load_bitmap("Graphics/Icons/", filename)
end
def self.panorama(filename, hue)
self.load_bitmap("Graphics/Panoramas/", filename, hue)
end
def self.picture(filename)
self.load_bitmap("Graphics/Pictures/", filename)
end
def self.tileset(filename)
self.load_bitmap("Graphics/Tilesets/", filename)
end
def self.title(filename)
self.load_bitmap("Graphics/Titles/", filename)
end
def self.windowskin(filename)
self.load_bitmap("Graphics/Windowskins/", filename)
end
def self.tile(filename, tile_id, hue)
BitmapCache.tile(filename,tile_id,hue)
end
def self.clear
BitmapCache.clear()
end
end
end
# A safer version of RPG::Cache, this module loads bitmaps that keep an internal
# reference count. Each call to dispose decrements the reference count and the
# bitmap is freed when the reference count reaches 0.
class Thread
def Thread.exclusive
_old = Thread.critical
begin
Thread.critical = true
return yield
ensure
Thread.critical = _old
end
end
end
class BitmapWrapper < Bitmap
@@disposedBitmaps={}
@@keys={}
=begin
@@final = lambda { |id|
Thread.exclusive {
if @@disposedBitmaps[id]!=true
File.open("debug.txt","ab") { |f|
f.write("Bitmap finalized without being disposed: #{@@keys[id]}\r\n")
}
end
@@disposedBitmaps[id]=nil
}
}
=end
attr_reader :refcount
def dispose
return if self.disposed?
@refcount-=1
if @refcount==0
super
#Thread.exclusive { @@disposedBitmaps[__id__]=true }
end
end
def initialize(*arg)
super
@refcount=1
#Thread.exclusive { @@keys[__id__]=arg.inspect+caller(1).inspect }
#ObjectSpace.define_finalizer(self,@@final)
end
def resetRef # internal
@refcount=1
end
def copy
bm=self.clone
bm.resetRef
return bm
end
def addRef
@refcount+=1
end
end
module BitmapCache
@cache = WeakHashtable.new
def self.fromCache(i)
return nil if !@cache.include?(i)
obj=@cache[i]
return nil if obj && obj.disposed?
return obj
end
def self.setKey(key,obj)
@cache[key]=obj
end
def self.debug
File.open("bitmapcache2.txt","wb") { |f|
for i in @cache.keys
k = fromCache(i)
if !k
f.write("#{i} (nil)\r\n")
elsif k.disposed?
f.write("#{i} (disposed)\r\n")
else
f.write("#{i} (#{k.refcount}, #{k.width}x#{k.height})\r\n")
end
end
}
end
def self.load_bitmap(path, hue = 0, failsafe = false)
cached = true
path = canonicalize(path)
objPath = fromCache(path)
if !objPath
@cleancounter = ((@cleancounter || 0) + 1)%10
if @cleancounter == 0
for i in @cache.keys
@cache.delete(i) if !fromCache(i)
end
end
begin
bm = BitmapWrapper.new(path)
rescue Hangup
begin
bm = BitmapWrapper.new(path)
rescue
raise _INTL("Failed to load the bitmap located at: {1}",path) if !failsafe
bm = BitmapWrapper.new(32,32)
end
rescue
raise _INTL("Failed to load the bitmap located at: {1}",path) if !failsafe
bm = BitmapWrapper.new(32,32)
end
objPath = bm
@cache[path] = objPath
cached=false
end
if hue == 0
objPath.addRef if cached
return objPath
else
key = [path, hue]
objKey = fromCache(key)
if !objKey
bitmap = objPath.copy
bitmap.hue_change(hue) if hue!=0
objKey = bitmap
@cache[key] = objKey
else
objKey.addRef
end
return objKey
end
end
def self.animation(filename, hue)
self.load_bitmap("Graphics/Animations/"+filename, hue)
end
def self.autotile(filename)
self.load_bitmap("Graphics/Autotiles/"+ filename)
end
def self.battleback(filename)
self.load_bitmap("Graphics/Battlebacks/"+ filename)
end
def self.battler(filename, hue)
self.load_bitmap("Graphics/Battlers/"+ filename, hue)
end
def self.character(filename, hue)
self.load_bitmap("Graphics/Characters/"+ filename, hue)
end
def self.fog(filename, hue)
self.load_bitmap("Graphics/Fogs/"+ filename, hue)
end
def self.gameover(filename)
self.load_bitmap("Graphics/Gameovers/"+ filename)
end
def self.icon(filename)
self.load_bitmap("Graphics/Icons/"+ filename)
end
def self.panorama(filename, hue)
self.load_bitmap("Graphics/Panoramas/"+ filename, hue)
end
def self.picture(filename)
self.load_bitmap("Graphics/Pictures/"+ filename)
end
def self.tileset(filename)
self.load_bitmap("Graphics/Tilesets/"+ filename)
end
def self.title(filename)
self.load_bitmap("Graphics/Titles/"+ filename)
end
def self.windowskin(filename)
self.load_bitmap("Graphics/Windowskins/"+ filename)
end
def self.tileEx(filename, tile_id, hue)
key = [filename, tile_id, hue]
objKey=fromCache(key)
if !objKey
bitmap=BitmapWrapper.new(32, 32)
x = (tile_id - 384) % 8 * 32
y = (tile_id - 384) / 8 * 32
rect = Rect.new(x, y, 32, 32)
tileset = yield(filename)
bitmap.blt(0, 0, tileset, rect)
tileset.dispose
bitmap.hue_change(hue) if hue!=0
objKey=bitmap
@cache[key]=objKey
else
objKey.addRef
end
objKey
end
def self.tile(filename, tile_id, hue)
return self.tileEx(filename, tile_id,hue) { |f| self.tileset(f) }
end
def self.clear
@cache = {}
GC.start
end
end

View File

@@ -0,0 +1,608 @@
class WindowCursorRect < Rect
def initialize(window)
@window=window
@x=0
@y=0
@width=0
@height=0
end
attr_reader :x,:y,:width,:height
def empty
needupdate=@x!=0 || @y!=0 || @width!=0 || @height!=0
if needupdate
@x=0
@y=0
@width=0
@height=0
@window.width=@window.width
end
end
def isEmpty?
return @x==0 && @y==0 && @width==0 && @height==0
end
def set(x,y,width,height)
needupdate=@x!=x || @y!=y || @width!=width || @height!=height
if needupdate
@x=x
@y=y
@width=width
@height=height
@window.width=@window.width
end
end
def height=(value)
@height=value; @window.width=@window.width
end
def width=(value)
@width=value; @window.width=@window.width
end
def x=(value)
@x=value; @window.width=@window.width
end
def y=(value)
@y=value; @window.width=@window.width
end
end
class Window
attr_reader :tone
attr_reader :color
attr_reader :blend_type
attr_reader :contents_blend_type
attr_reader :viewport
attr_reader :contents
attr_reader :ox
attr_reader :oy
attr_reader :x
attr_reader :y
attr_reader :z
attr_reader :width
attr_reader :active
attr_reader :pause
attr_reader :height
attr_reader :opacity
attr_reader :back_opacity
attr_reader :contents_opacity
attr_reader :visible
attr_reader :cursor_rect
attr_reader :openness
attr_reader :stretch
def windowskin
@_windowskin
end
def initialize(viewport=nil)
@sprites={}
@spritekeys=[
"back",
"corner0","side0","scroll0",
"corner1","side1","scroll1",
"corner2","side2","scroll2",
"corner3","side3","scroll3",
"cursor","contents","pause"
]
@sidebitmaps=[nil,nil,nil,nil]
@cursorbitmap=nil
@bgbitmap=nil
@viewport=viewport
for i in @spritekeys
@sprites[i]=Sprite.new(@viewport)
end
@disposed=false
@tone=Tone.new(0,0,0)
@color=Color.new(0,0,0,0)
@blankcontents=Bitmap.new(1,1) # RGSS2 requires this
@contents=@blankcontents
@_windowskin=nil
@rpgvx=false # Set to true to emulate RPGVX windows
@x=0
@y=0
@width=0
@openness=255
@height=0
@ox=0
@oy=0
@z=0
@stretch=true
@visible=true
@active=true
@blend_type=0
@contents_blend_type=0
@opacity=255
@back_opacity=255
@contents_opacity=255
@cursor_rect=WindowCursorRect.new(self)
@cursorblink=0
@cursoropacity=255
@pause=false
@pauseopacity=255
@pauseframe=0
privRefresh(true)
end
def dispose
if !self.disposed?
for i in @sprites
i[1].dispose if i[1]
@sprites[i[0]]=nil
end
for i in 0...@sidebitmaps.length
@sidebitmaps[i].dispose if @sidebitmaps[i]
@sidebitmaps[i]=nil
end
@blankcontents.dispose
@cursorbitmap.dispose if @cursorbitmap
@backbitmap.dispose if @backbitmap
@sprites.clear
@sidebitmaps.clear
@_windowskin=nil
@_contents=nil
@disposed=true
end
end
def openness=(value)
@openness=value
@openness=0 if @openness<0
@openness=255 if @openness>255
privRefresh
end
def stretch=(value)
@stretch=value
privRefresh(true)
end
def visible=(value)
@visible=value
privRefresh
end
def viewport=(value)
@viewport=value
for i in @spritekeys
@sprites[i].dispose
if @sprites[i].is_a?(Sprite)
@sprites[i]=Sprite.new(@viewport)
else
@sprites[i]=nil
end
end
privRefresh(true)
end
def z=(value)
@z=value
privRefresh
end
def disposed?
return @disposed
end
def contents=(value)
@contents=value
privRefresh
end
def windowskin=(value)
@_windowskin=value
if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128
@rpgvx=true
else
@rpgvx=false
end
privRefresh(true)
end
def ox=(value)
@ox=value
privRefresh
end
def active=(value)
@active=value
privRefresh(true)
end
def cursor_rect=(value)
if !value
@cursor_rect.empty
else
@cursor_rect.set(value.x,value.y,value.width,value.height)
end
end
def oy=(value)
@oy=value
privRefresh
end
def width=(value)
@width=value
privRefresh(true)
end
def height=(value)
@height=value
privRefresh(true)
end
def pause=(value)
@pause=value
@pauseopacity=0 if !value
privRefresh
end
def x=(value)
@x=value
privRefresh
end
def y=(value)
@y=value
privRefresh
end
def opacity=(value)
@opacity=value
@opacity=0 if @opacity<0
@opacity=255 if @opacity>255
privRefresh
end
def back_opacity=(value)
@back_opacity=value
@back_opacity=0 if @back_opacity<0
@back_opacity=255 if @back_opacity>255
privRefresh
end
def contents_opacity=(value)
@contents_opacity=value
@contents_opacity=0 if @contents_opacity<0
@contents_opacity=255 if @contents_opacity>255
privRefresh
end
def tone=(value)
@tone=value
privRefresh
end
def color=(value)
@color=value
privRefresh
end
def blend_type=(value)
@blend_type=value
privRefresh
end
def flash(color,duration)
return if disposed?
for i in @sprites
i[1].flash(color,duration)
end
end
def update
return if disposed?
mustchange=false
if @active
if @cursorblink==0
@cursoropacity-=8
@cursorblink=1 if @cursoropacity<=128
else
@cursoropacity+=8
@cursorblink=0 if @cursoropacity>=255
end
mustchange=true if !@cursor_rect.isEmpty?
else
mustchange=true if @cursoropacity!=128
@cursoropacity=128
end
if @pause
@pauseframe=(Graphics.frame_count / 8) % 4
@pauseopacity=[@pauseopacity+64,255].min
mustchange=true
end
privRefresh if mustchange
for i in @sprites
i[1].update
end
end
private
def ensureBitmap(bitmap,dwidth,dheight)
if !bitmap||bitmap.disposed?||bitmap.width<dwidth||bitmap.height<dheight
bitmap.dispose if bitmap
bitmap=Bitmap.new([1,dwidth].max,[1,dheight].max)
end
return bitmap
end
def tileBitmap(dstbitmap,dstrect,srcbitmap,srcrect)
return if !srcbitmap || srcbitmap.disposed?
left=dstrect.x
top=dstrect.y
y=0;loop do break unless y<dstrect.height
x=0;loop do break unless x<dstrect.width
dstbitmap.blt(x+left,y+top,srcbitmap,srcrect)
x+=srcrect.width
end
y+=srcrect.height
end
end
def privRefresh(changeBitmap=false)
return if self.disposed?
backopac=self.back_opacity*self.opacity/255
contopac=self.contents_opacity
cursoropac=@cursoropacity*contopac/255
for i in 0...4
@sprites["corner#{i}"].bitmap=@_windowskin
@sprites["scroll#{i}"].bitmap=@_windowskin
end
@sprites["pause"].bitmap=@_windowskin
@sprites["contents"].bitmap=@contents
if @_windowskin && !@_windowskin.disposed?
for i in 0...4
@sprites["corner#{i}"].opacity=@opacity
@sprites["corner#{i}"].tone=@tone
@sprites["corner#{i}"].color=@color
@sprites["corner#{i}"].blend_type=@blend_type
@sprites["corner#{i}"].visible=@visible
@sprites["side#{i}"].opacity=@opacity
@sprites["side#{i}"].tone=@tone
@sprites["side#{i}"].color=@color
@sprites["side#{i}"].blend_type=@blend_type
@sprites["side#{i}"].visible=@visible
@sprites["scroll#{i}"].opacity=@opacity
@sprites["scroll#{i}"].tone=@tone
@sprites["scroll#{i}"].blend_type=@blend_type
@sprites["scroll#{i}"].color=@color
@sprites["scroll#{i}"].visible=@visible
end
for i in ["back","cursor","pause","contents"]
@sprites[i].color=@color
@sprites[i].tone=@tone
@sprites[i].blend_type=@blend_type
end
@sprites["contents"].blend_type=@contents_blend_type
@sprites["back"].opacity=backopac
@sprites["contents"].opacity=contopac
@sprites["cursor"].opacity=cursoropac
@sprites["pause"].opacity=@pauseopacity
@sprites["back"].visible=@visible
@sprites["contents"].visible=@visible && @openness==255
@sprites["pause"].visible=@visible && @pause
@sprites["cursor"].visible=@visible && @openness==255
hascontents=(@contents && !@contents.disposed?)
@sprites["scroll0"].visible = @visible && hascontents && @oy > 0
@sprites["scroll1"].visible = @visible && hascontents && @ox > 0
@sprites["scroll2"].visible = @visible && hascontents &&
(@contents.width - @ox) > @width-32
@sprites["scroll3"].visible = @visible && hascontents &&
(@contents.height - @oy) > @height-32
else
for i in 0...4
@sprites["corner#{i}"].visible=false
@sprites["side#{i}"].visible=false
@sprites["scroll#{i}"].visible=false
end
@sprites["contents"].visible=@visible && @openness==255
@sprites["contents"].color=@color
@sprites["contents"].tone=@tone
@sprites["contents"].blend_type=@contents_blend_type
@sprites["contents"].opacity=contopac
@sprites["back"].visible=false
@sprites["pause"].visible=false
@sprites["cursor"].visible=false
end
for i in @sprites
i[1].z=@z
end
if @rpgvx
@sprites["cursor"].z=@z # For Compatibility
@sprites["contents"].z=@z # For Compatibility
@sprites["pause"].z=@z # For Compatibility
else
@sprites["cursor"].z=@z+1 # For Compatibility
@sprites["contents"].z=@z+2 # For Compatibility
@sprites["pause"].z=@z+2 # For Compatibility
end
if @rpgvx
trimX=64
trimY=0
backRect=Rect.new(0,0,64,64)
blindsRect=Rect.new(0,64,64,64)
else
trimX=128
trimY=0
backRect=Rect.new(0,0,128,128)
blindsRect=nil
end
@sprites["corner0"].src_rect.set(trimX,trimY+0,16,16);
@sprites["corner1"].src_rect.set(trimX+48,trimY+0,16,16);
@sprites["corner2"].src_rect.set(trimX,trimY+48,16,16);
@sprites["corner3"].src_rect.set(trimX+48,trimY+48,16,16);
@sprites["scroll0"].src_rect.set(trimX+24, trimY+16, 16, 8) # up
@sprites["scroll3"].src_rect.set(trimX+24, trimY+40, 16, 8) # down
@sprites["scroll1"].src_rect.set(trimX+16, trimY+24, 8, 16) # left
@sprites["scroll2"].src_rect.set(trimX+40, trimY+24, 8, 16) # right
cursorX=trimX
cursorY=trimY+64
sideRects=[
Rect.new(trimX+16,trimY+0,32,16),
Rect.new(trimX,trimY+16,16,32),
Rect.new(trimX+48,trimY+16,16,32),
Rect.new(trimX+16,trimY+48,32,16)
]
if @width>32 && @height>32
@sprites["contents"].src_rect.set(@ox,@oy,@width-32,@height-32)
else
@sprites["contents"].src_rect.set(0,0,0,0)
end
pauseRects=[
trimX+32,trimY+64,
trimX+48,trimY+64,
trimX+32,trimY+80,
trimX+48,trimY+80,
]
pauseWidth=16
pauseHeight=16
@sprites["pause"].src_rect.set(
pauseRects[@pauseframe*2],
pauseRects[@pauseframe*2+1],
pauseWidth,pauseHeight
)
@sprites["pause"].x=@x+(@width/2)-(pauseWidth/2)
@sprites["pause"].y=@y+@height-16 # 16 refers to skin margin
@sprites["contents"].x=@x+16
@sprites["contents"].y=@y+16
@sprites["corner0"].x=@x
@sprites["corner0"].y=@y
@sprites["corner1"].x=@x+@width-16
@sprites["corner1"].y=@y
@sprites["corner2"].x=@x
@sprites["corner2"].y=@y+@height-16
@sprites["corner3"].x=@x+@width-16
@sprites["corner3"].y=@y+@height-16
@sprites["side0"].x=@x+16
@sprites["side0"].y=@y
@sprites["side1"].x=@x
@sprites["side1"].y=@y+16
@sprites["side2"].x=@x+@width-16
@sprites["side2"].y=@y+16
@sprites["side3"].x=@x+16
@sprites["side3"].y=@y+@height-16
@sprites["scroll0"].x = @x+@width / 2 - 8
@sprites["scroll0"].y = @y+8
@sprites["scroll1"].x = @x+8
@sprites["scroll1"].y = @y+@height / 2 - 8
@sprites["scroll2"].x = @x+@width - 16
@sprites["scroll2"].y = @y+@height / 2 - 8
@sprites["scroll3"].x = @x+@width / 2 - 8
@sprites["scroll3"].y = @y+@height - 16
@sprites["back"].x=@x+2
@sprites["back"].y=@y+2
@sprites["cursor"].x=@x+16+@cursor_rect.x
@sprites["cursor"].y=@y+16+@cursor_rect.y
if changeBitmap && @_windowskin && !@_windowskin.disposed?
width=@cursor_rect.width
height=@cursor_rect.height
if width > 0 && height > 0
cursorrects=[
# sides
Rect.new(cursorX+2, cursorY+0, 28, 2),
Rect.new(cursorX+0, cursorY+2, 2, 28),
Rect.new(cursorX+30, cursorY+2, 2, 28),
Rect.new(cursorX+2, cursorY+30, 28, 2),
# corners
Rect.new(cursorX+0, cursorY+0, 2, 2),
Rect.new(cursorX+30, cursorY+0, 2, 2),
Rect.new(cursorX+0, cursorY+30, 2, 2),
Rect.new(cursorX+30, cursorY+30, 2, 2),
# back
Rect.new(cursorX+2, cursorY+2, 28, 28)
]
margin=2
fullmargin=4
@cursorbitmap = ensureBitmap(@cursorbitmap, width, height)
@cursorbitmap.clear
@sprites["cursor"].bitmap=@cursorbitmap
@sprites["cursor"].src_rect.set(0,0,width,height)
rect = Rect.new(margin,margin,
width - fullmargin, height - fullmargin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[8])
@cursorbitmap.blt(0, 0, @_windowskin, cursorrects[4])# top left
@cursorbitmap.blt(width-margin, 0, @_windowskin, cursorrects[5]) # top right
@cursorbitmap.blt(0, height-margin, @_windowskin, cursorrects[6]) # bottom right
@cursorbitmap.blt(width-margin, height-margin, @_windowskin, cursorrects[7]) # bottom left
rect = Rect.new(margin, 0,
width - fullmargin, margin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[0])
rect = Rect.new(0, margin,
margin, height - fullmargin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[1])
rect = Rect.new(width - margin, margin,
margin, height - fullmargin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[2])
rect = Rect.new(margin, height-margin,
width - fullmargin, margin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[3])
else
@sprites["cursor"].visible=false
@sprites["cursor"].src_rect.set(0,0,0,0)
end
for i in 0...4
dwidth = (i==0 || i==3) ? @width-32 : 16
dheight = (i==0 || i==3) ? 16 : @height-32
@sidebitmaps[i]=ensureBitmap(@sidebitmaps[i],dwidth,dheight)
@sprites["side#{i}"].bitmap=@sidebitmaps[i]
@sprites["side#{i}"].src_rect.set(0,0,dwidth,dheight)
@sidebitmaps[i].clear
if sideRects[i].width>0 && sideRects[i].height>0
@sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect,
@_windowskin,sideRects[i])
end
end
backwidth=@width-4
backheight=@height-4
if backwidth>0 && backheight>0
@backbitmap=ensureBitmap(@backbitmap,backwidth,backheight)
@sprites["back"].bitmap=@backbitmap
@sprites["back"].src_rect.set(0,0,backwidth,backheight)
@backbitmap.clear
if @stretch
@backbitmap.stretch_blt(@sprites["back"].src_rect,@_windowskin,backRect)
else
tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,backRect)
end
if blindsRect
tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,blindsRect)
end
else
@sprites["back"].visible=false
@sprites["back"].src_rect.set(0,0,0,0)
end
end
if @openness!=255
opn=@openness/255.0
for k in @spritekeys
sprite=@sprites[k]
ratio=(@height<=0) ? 0 : (sprite.y-@y)*1.0/@height
sprite.zoom_y=opn
sprite.oy=0
sprite.y=(@y+(@height/2.0)+(@height*ratio*opn)-(@height/2*opn)).floor
end
else
for k in @spritekeys
sprite=@sprites[k]
sprite.zoom_y=1.0
end
end
i=0
# Ensure Z order
for k in @spritekeys
sprite=@sprites[k]
y=sprite.y
sprite.y=i
sprite.oy=(sprite.zoom_y<=0) ? 0 : (i-y)/sprite.zoom_y
end
end
end

View File

@@ -0,0 +1,781 @@
module MessageConfig
FontName = "Power Green"
# in Graphics/Windowskins/ (specify empty string to use the default windowskin)
TextSkinName = "speech hgss 1"
ChoiceSkinName = "choice 1"
WindowOpacity = 255
TextSpeed = nil # can be positive to wait frames or negative to
# show multiple characters in a single frame
LIGHTTEXTBASE = Color.new(248,248,248)
LIGHTTEXTSHADOW = Color.new(72,80,88)
DARKTEXTBASE = Color.new(80,80,88)
DARKTEXTSHADOW = Color.new(160,160,168)
# 0 = Pause cursor is displayed at end of text
# 1 = Pause cursor is displayed at bottom right
# 2 = Pause cursor is displayed at lower middle side
CURSORMODE = 1
FontSubstitutes = {
"Power Red and Blue" => "Pokemon RS",
"Power Red and Green" => "Pokemon FireLeaf",
"Power Green" => "Pokemon Emerald",
"Power Green Narrow" => "Pokemon Emerald Narrow",
"Power Green Small" => "Pokemon Emerald Small",
"Power Clear" => "Pokemon DP"
}
@@systemFrame = nil
@@defaultTextSkin = nil
@@systemFont = nil
@@textSpeed = nil
def self.pbTryFonts(*args)
for a in args
if a && a.is_a?(String)
return a if Font.exist?(a)
a=MessageConfig::FontSubstitutes[a] || a
return a if Font.exist?(a)
elsif a && a.is_a?(Array)
for aa in a
ret=MessageConfig.pbTryFonts(aa)
return ret if ret!=""
end
end
end
return ""
end
def self.pbDefaultSystemFrame
return "" if !MessageConfig::ChoiceSkinName
return pbResolveBitmap("Graphics/Windowskins/"+MessageConfig::ChoiceSkinName) || ""
end
def self.pbDefaultSpeechFrame
return "" if !MessageConfig::TextSkinName
return pbResolveBitmap("Graphics/Windowskins/"+MessageConfig::TextSkinName) || ""
end
def self.pbDefaultSystemFontName
return MessageConfig.pbTryFonts(MessageConfig::FontName,"Arial Narrow","Arial")
end
def self.pbDefaultTextSpeed
return (TextSpeed) ? TextSpeed : (Graphics.width>400) ? -2 : 1
end
def self.pbDefaultWindowskin
skin=load_data("Data/System.rxdata").windowskin_name rescue nil
if skin && skin!=""
skin=pbResolveBitmap("Graphics/Windowskins/"+skin) || ""
end
skin=pbResolveBitmap("Graphics/System/Window") if !skin || skin==""
skin=pbResolveBitmap("Graphics/Windowskins/001-Blue01") if !skin || skin==""
return skin || ""
end
def self.pbGetSystemFrame
if !@@systemFrame
skin=MessageConfig.pbDefaultSystemFrame
skin=MessageConfig.pbDefaultWindowskin if !skin || skin==""
@@systemFrame=skin || ""
end
return @@systemFrame
end
def self.pbGetSpeechFrame
if !@@defaultTextSkin
skin=MessageConfig.pbDefaultSpeechFrame
skin=MessageConfig.pbDefaultWindowskin if !skin || skin==""
@@defaultTextSkin=skin || ""
end
return @@defaultTextSkin
end
def self.pbGetSystemFontName
@@systemFont=pbDefaultSystemFontName if !@@systemFont
return @@systemFont
end
def self.pbGetTextSpeed
@@textSpeed=pbDefaultTextSpeed if !@@textSpeed
return @@textSpeed
end
def self.pbSetSystemFrame(value)
@@systemFrame=pbResolveBitmap(value) || ""
end
def self.pbSetSpeechFrame(value)
@@defaultTextSkin=pbResolveBitmap(value) || ""
end
def self.pbSetSystemFontName(value)
@@systemFont=MessageConfig.pbTryFonts(value,"Arial Narrow","Arial")
end
def self.pbSetTextSpeed(value)
@@textSpeed=value
end
end
#===============================================================================
# Position a window
#===============================================================================
def pbBottomRight(window)
window.x=Graphics.width-window.width
window.y=Graphics.height-window.height
end
def pbBottomLeft(window)
window.x=0
window.y=Graphics.height-window.height
end
def pbBottomLeftLines(window,lines,width=nil)
window.x=0
window.width=width ? width : Graphics.width
window.height=(window.borderY rescue 32)+lines*32
window.y=Graphics.height-window.height
end
def pbPositionFaceWindow(facewindow,msgwindow)
return if !facewindow
if msgwindow
if facewindow.height<=msgwindow.height
facewindow.y=msgwindow.y
else
facewindow.y=msgwindow.y+msgwindow.height-facewindow.height
end
facewindow.x=Graphics.width-facewindow.width
msgwindow.x=0
msgwindow.width=Graphics.width-facewindow.width
else
facewindow.height=Graphics.height if facewindow.height>Graphics.height
facewindow.x=0
facewindow.y=0
end
end
def pbPositionNearMsgWindow(cmdwindow,msgwindow,side)
return if !cmdwindow
if msgwindow
height=[cmdwindow.height,Graphics.height-msgwindow.height].min
if cmdwindow.height!=height
cmdwindow.height=height
end
cmdwindow.y=msgwindow.y-cmdwindow.height
if cmdwindow.y<0
cmdwindow.y=msgwindow.y+msgwindow.height
if cmdwindow.y+cmdwindow.height>Graphics.height
cmdwindow.y=msgwindow.y-cmdwindow.height
end
end
case side
when :left
cmdwindow.x=msgwindow.x
when :right
cmdwindow.x=msgwindow.x+msgwindow.width-cmdwindow.width
else
cmdwindow.x=msgwindow.x+msgwindow.width-cmdwindow.width
end
else
cmdwindow.height=Graphics.height if cmdwindow.height>Graphics.height
cmdwindow.x=0
cmdwindow.y=0
end
end
# internal function
def pbRepositionMessageWindow(msgwindow, linecount=2)
msgwindow.height=32*linecount+msgwindow.borderY
msgwindow.y=(Graphics.height)-(msgwindow.height)
if $game_system && $game_system.respond_to?("message_position")
case $game_system.message_position
when 0 # up
msgwindow.y=0
when 1 # middle
msgwindow.y=(Graphics.height/2)-(msgwindow.height/2)
when 2
msgwindow.y=(Graphics.height)-(msgwindow.height)
end
end
if $game_system && $game_system.respond_to?("message_frame")
if $game_system.message_frame != 0
msgwindow.opacity = 0
end
end
if $game_message
case $game_message.background
when 1; msgwindow.opacity=0 # dim
when 2; msgwindow.opacity=0 # transparent
end
end
end
# internal function
def pbUpdateMsgWindowPos(msgwindow,event,eventChanged=false)
if event
if eventChanged
msgwindow.resizeToFit2(msgwindow.text,Graphics.width*2/3,msgwindow.height)
end
msgwindow.y=event.screen_y-48-msgwindow.height
if msgwindow.y<0
msgwindow.y=event.screen_y+24
end
msgwindow.x=event.screen_x-(msgwindow.width/2)
msgwindow.x=0 if msgwindow.x<0
if msgwindow.x>Graphics.width-msgwindow.width
msgwindow.x=Graphics.width-msgwindow.width
end
else
curwidth=msgwindow.width
if curwidth!=Graphics.width
msgwindow.width=Graphics.width
msgwindow.width=Graphics.width
end
end
end
#===============================================================================
# Determine the colour of a background
#===============================================================================
def isDarkBackground(background,rect=nil)
return true if !background || background.disposed?
rect = background.rect if !rect
return true if rect.width<=0 || rect.height<=0
xSeg = (rect.width/16)
xLoop = (xSeg==0) ? 1 : 16
xStart = (xSeg==0) ? rect.x+(rect.width/2) : rect.x+xSeg/2
ySeg = (rect.height/16)
yLoop = (ySeg==0) ? 1 : 16
yStart = (ySeg==0) ? rect.y+(rect.height/2) : rect.y+ySeg/2
count = 0
y = yStart
r = 0; g = 0; b = 0
yLoop.times do
x = xStart
xLoop.times do
clr = background.get_pixel(x,y)
if clr.alpha!=0
r += clr.red
g += clr.green
b += clr.blue
count += 1
end
x += xSeg
end
y += ySeg
end
return true if count==0
r /= count
g /= count
b /= count
return (r*0.299+g*0.587+b*0.114)<160
end
def isDarkWindowskin(windowskin)
return true if !windowskin || windowskin.disposed?
if windowskin.width==192 && windowskin.height==128
return isDarkBackground(windowskin,Rect.new(0,0,128,128))
elsif windowskin.width==128 && windowskin.height==128
return isDarkBackground(windowskin,Rect.new(0,0,64,64))
elsif windowskin.width==96 && windowskin.height==48
return isDarkBackground(windowskin,Rect.new(32,16,16,16))
else
clr = windowskin.get_pixel(windowskin.width/2, windowskin.height/2)
return (clr.red*0.299+clr.green*0.587+clr.blue*0.114)<160
end
end
#===============================================================================
# Determine which text colours to use based on the darkness of the background
#===============================================================================
def getSkinColor(windowskin,color,isDarkSkin)
if !windowskin || windowskin.disposed? ||
windowskin.width!=128 || windowskin.height!=128
# Base color, shadow color (these are reversed on dark windowskins)
textcolors = [
"0070F8","78B8E8", # 1 Blue
"E82010","F8A8B8", # 2 Red
"60B048","B0D090", # 3 Green
"48D8D8","A8E0E0", # 4 Cyan
"D038B8","E8A0E0", # 5 Magenta
"E8D020","F8E888", # 6 Yellow
"A0A0A8","D0D0D8", # 7 Grey
"F0F0F8","C8C8D0", # 8 White
"9040E8","B8A8E0", # 9 Purple
"F89818","F8C898", # 10 Orange
colorToRgb32(MessageConfig::DARKTEXTBASE),
colorToRgb32(MessageConfig::DARKTEXTSHADOW), # 11 Dark default
colorToRgb32(MessageConfig::LIGHTTEXTBASE),
colorToRgb32(MessageConfig::LIGHTTEXTSHADOW) # 12 Light default
]
if color==0 || color>textcolors.length/2 # No special colour, use default
if isDarkSkin # Dark background, light text
return shadowc3tag(MessageConfig::LIGHTTEXTBASE,MessageConfig::LIGHTTEXTSHADOW)
end
# Light background, dark text
return shadowc3tag(MessageConfig::DARKTEXTBASE,MessageConfig::DARKTEXTSHADOW)
end
# Special colour as listed above
if isDarkSkin && color!=12 # Dark background, light text
return sprintf("<c3=%s,%s>",textcolors[2*(color-1)+1],textcolors[2*(color-1)])
end
# Light background, dark text
return sprintf("<c3=%s,%s>",textcolors[2*(color-1)],textcolors[2*(color-1)+1])
else # VX windowskin
color = 0 if color>=32
x = 64 + (color % 8) * 8
y = 96 + (color / 8) * 8
pixel = windowskin.get_pixel(x, y)
return shadowctagFromColor(pixel)
end
end
def getDefaultTextColors(windowskin)
if !windowskin || windowskin.disposed? ||
windowskin.width!=128 || windowskin.height!=128
if isDarkWindowskin(windowskin)
return [MessageConfig::LIGHTTEXTBASE,MessageConfig::LIGHTTEXTSHADOW] # White
else
return [MessageConfig::DARKTEXTBASE,MessageConfig::DARKTEXTSHADOW] # Dark gray
end
else # VX windowskin
color = windowskin.get_pixel(64, 96)
shadow = nil
isDark = (color.red+color.green+color.blue)/3 < 128
if isDark
shadow = Color.new(color.red+64,color.green+64,color.blue+64)
else
shadow = Color.new(color.red-64,color.green-64,color.blue-64)
end
return [color,shadow]
end
end
#===============================================================================
# Makes sure a bitmap exists
#===============================================================================
def pbDoEnsureBitmap(bitmap,dwidth,dheight)
if !bitmap || bitmap.disposed? || bitmap.width<dwidth || bitmap.height<dheight
oldfont = (bitmap && !bitmap.disposed?) ? bitmap.font : nil
bitmap.dispose if bitmap
bitmap = Bitmap.new([1,dwidth].max,[1,dheight].max)
(oldfont) ? bitmap.font = oldfont : pbSetSystemFont(bitmap)
bitmap.font.shadow = false if bitmap.font && bitmap.font.respond_to?("shadow")
end
return bitmap
end
#===============================================================================
# Set a bitmap's font
#===============================================================================
# Gets the name of the system small font.
def pbSmallFontName
return MessageConfig.pbTryFonts("Power Green Small","Pokemon Emerald Small",
"Arial Narrow","Arial")
end
# Gets the name of the system narrow font.
def pbNarrowFontName
return MessageConfig.pbTryFonts("Power Green Narrow","Pokemon Emerald Narrow",
"Arial Narrow","Arial")
end
# Sets a bitmap's font to the system font.
def pbSetSystemFont(bitmap)
fontname=MessageConfig.pbGetSystemFontName
bitmap.font.name=fontname
if fontname=="Pokemon FireLeaf" || fontname=="Power Red and Green"
bitmap.font.size=29
elsif fontname=="Pokemon Emerald Small" || fontname=="Power Green Small"
bitmap.font.size=25
else
bitmap.font.size=31
end
end
# Sets a bitmap's font to the system small font.
def pbSetSmallFont(bitmap)
bitmap.font.name=pbSmallFontName
bitmap.font.size=25
end
# Sets a bitmap's font to the system narrow font.
def pbSetNarrowFont(bitmap)
bitmap.font.name=pbNarrowFontName
bitmap.font.size=31
end
#===============================================================================
# Blend colours, set the colour of all bitmaps in a sprite hash
#===============================================================================
def pbAlphaBlend(dstColor,srcColor)
r=(255*(srcColor.red-dstColor.red)/255)+dstColor.red
g=(255*(srcColor.green-dstColor.green)/255)+dstColor.green
b=(255*(srcColor.blue-dstColor.blue)/255)+dstColor.blue
a=(255*(srcColor.alpha-dstColor.alpha)/255)+dstColor.alpha
return Color.new(r,g,b,a)
end
def pbSrcOver(dstColor,srcColor)
er=srcColor.red*srcColor.alpha/255
eg=srcColor.green*srcColor.alpha/255
eb=srcColor.blue*srcColor.alpha/255
iea=255-srcColor.alpha
cr=dstColor.red*dstColor.alpha/255
cg=dstColor.green*dstColor.alpha/255
cb=dstColor.blue*dstColor.alpha/255
ica=255-dstColor.alpha
a=255-(iea*ica)/255
r=(iea*cr)/255+er
g=(iea*cg)/255+eg
b=(iea*cb)/255+eb
r=(a==0) ? 0 : r*255/a
g=(a==0) ? 0 : g*255/a
b=(a==0) ? 0 : b*255/a
return Color.new(r,g,b,a)
end
def pbSetSpritesToColor(sprites,color)
return if !sprites || !color
colors={}
for i in sprites
next if !i[1] || pbDisposed?(i[1])
colors[i[0]]=i[1].color.clone
i[1].color=pbSrcOver(i[1].color,color)
end
Graphics.update
Input.update
for i in colors
next if !sprites[i[0]]
sprites[i[0]].color=i[1]
end
end
#===============================================================================
# Update and dispose sprite hashes
#===============================================================================
def using(window)
begin
yield if block_given?
ensure
window.dispose
end
end
def pbUpdateSpriteHash(windows)
for i in windows
window=i[1]
if window
if window.is_a?(Sprite) || window.is_a?(Window)
window.update if !pbDisposed?(window)
elsif window.is_a?(Plane)
begin
window.update if !window.disposed?
rescue NoMethodError
end
elsif window.respond_to?("update")
begin
window.update
rescue RGSSError
end
end
end
end
end
# Disposes all objects in the specified hash.
def pbDisposeSpriteHash(sprites)
return if !sprites
for i in sprites.keys
pbDisposeSprite(sprites,i)
end
sprites.clear
end
# Disposes the specified graphics object within the specified hash. Basically
# like: sprites[id].dispose
def pbDisposeSprite(sprites,id)
sprite = sprites[id]
sprite.dispose if sprite && !pbDisposed?(sprite)
sprites[id] = nil
end
def pbDisposed?(x)
return true if !x
return x.disposed? if !x.is_a?(Viewport)
begin
x.rect = x.rect
rescue
return true
end
return false
end
#===============================================================================
# Fades and window activations for sprite hashes
#===============================================================================
class Game_Temp
attr_accessor :fadestate
def fadestate
return (@fadestate) ? @fadestate : 0
end
end
def pbPushFade
$game_temp.fadestate = [$game_temp.fadestate+1,0].max if $game_temp
end
def pbPopFade
$game_temp.fadestate = [$game_temp.fadestate-1,0].max if $game_temp
end
def pbIsFaded?
return ($game_temp) ? $game_temp.fadestate>0 : false
end
# pbFadeOutIn(z) { block }
# Fades out the screen before a block is run and fades it back in after the
# block exits. z indicates the z-coordinate of the viewport used for this effect
def pbFadeOutIn(z=99999,nofadeout=false)
col=Color.new(0,0,0,0)
viewport=Viewport.new(0,0,Graphics.width,Graphics.height)
viewport.z=z
numFrames = (Graphics.frame_rate*0.4).floor
alphaDiff = (255.0/numFrames).ceil
for j in 0..numFrames
col.set(0,0,0,j*alphaDiff)
viewport.color=col
Graphics.update
Input.update
end
pbPushFade
begin
yield if block_given?
ensure
pbPopFade
if !nofadeout
for j in 0..numFrames
col.set(0,0,0,(numFrames-j)*alphaDiff)
viewport.color=col
Graphics.update
Input.update
end
end
viewport.dispose
end
end
def pbFadeOutInWithUpdate(z,sprites,nofadeout=false)
col=Color.new(0,0,0,0)
viewport=Viewport.new(0,0,Graphics.width,Graphics.height)
viewport.z=z
numFrames = (Graphics.frame_rate*0.4).floor
alphaDiff = (255.0/numFrames).ceil
for j in 0..numFrames
col.set(0,0,0,j*alphaDiff)
viewport.color=col
pbUpdateSpriteHash(sprites)
Graphics.update
Input.update
end
pbPushFade
begin
yield if block_given?
ensure
pbPopFade
if !nofadeout
for j in 0..numFrames
col.set(0,0,0,(numFrames-j)*alphaDiff)
viewport.color=col
pbUpdateSpriteHash(sprites)
Graphics.update
Input.update
end
end
viewport.dispose
end
end
def pbFadeOutAndHide(sprites)
visiblesprites = {}
numFrames = (Graphics.frame_rate*0.4).floor
alphaDiff = (255.0/numFrames).ceil
pbDeactivateWindows(sprites) {
for j in 0..numFrames
pbSetSpritesToColor(sprites,Color.new(0,0,0,j*alphaDiff))
(block_given?) ? yield : pbUpdateSpriteHash(sprites)
end
}
for i in sprites
next if !i[1]
next if pbDisposed?(i[1])
visiblesprites[i[0]] = true if i[1].visible
i[1].visible = false
end
return visiblesprites
end
def pbFadeInAndShow(sprites,visiblesprites=nil)
if visiblesprites
for i in visiblesprites
if i[1] && sprites[i[0]] && !pbDisposed?(sprites[i[0]])
sprites[i[0]].visible = true
end
end
end
numFrames = (Graphics.frame_rate*0.4).floor
alphaDiff = (255.0/numFrames).ceil
pbDeactivateWindows(sprites) {
for j in 0..numFrames
pbSetSpritesToColor(sprites,Color.new(0,0,0,((numFrames-j)*alphaDiff)))
(block_given?) ? yield : pbUpdateSpriteHash(sprites)
end
}
end
# Restores which windows are active for the given sprite hash.
# _activeStatuses_ is the result of a previous call to pbActivateWindows
def pbRestoreActivations(sprites,activeStatuses)
return if !sprites || !activeStatuses
for k in activeStatuses.keys
if sprites[k] && sprites[k].is_a?(Window) && !pbDisposed?(sprites[k])
sprites[k].active=activeStatuses[k] ? true : false
end
end
end
# Deactivates all windows. If a code block is given, deactivates all windows,
# runs the code in the block, and reactivates them.
def pbDeactivateWindows(sprites)
if block_given?
pbActivateWindow(sprites,nil) { yield }
else
pbActivateWindow(sprites,nil)
end
end
# Activates a specific window of a sprite hash. _key_ is the key of the window
# in the sprite hash. If a code block is given, deactivates all windows except
# the specified window, runs the code in the block, and reactivates them.
def pbActivateWindow(sprites,key)
return if !sprites
activeStatuses={}
for i in sprites
if i[1] && i[1].is_a?(Window) && !pbDisposed?(i[1])
activeStatuses[i[0]]=i[1].active
i[1].active=(i[0]==key)
end
end
if block_given?
begin
yield
ensure
pbRestoreActivations(sprites,activeStatuses)
end
return {}
else
return activeStatuses
end
end
#===============================================================================
# Create background planes for a sprite hash
#===============================================================================
# Adds a background to the sprite hash.
# _planename_ is the hash key of the background.
# _background_ is a filename within the Graphics/Pictures/ folder and can be
# an animated image.
# _viewport_ is a viewport to place the background in.
def addBackgroundPlane(sprites,planename,background,viewport=nil)
sprites[planename]=AnimatedPlane.new(viewport)
bitmapName=pbResolveBitmap("Graphics/Pictures/#{background}")
if bitmapName==nil
# Plane should exist in any case
sprites[planename].bitmap=nil
sprites[planename].visible=false
else
sprites[planename].setBitmap(bitmapName)
for spr in sprites.values
if spr.is_a?(Window)
spr.windowskin=nil
end
end
end
end
# Adds a background to the sprite hash.
# _planename_ is the hash key of the background.
# _background_ is a filename within the Graphics/Pictures/ folder and can be
# an animated image.
# _color_ is the color to use if the background can't be found.
# _viewport_ is a viewport to place the background in.
def addBackgroundOrColoredPlane(sprites,planename,background,color,viewport=nil)
bitmapName=pbResolveBitmap("Graphics/Pictures/#{background}")
if bitmapName==nil
# Plane should exist in any case
sprites[planename]=ColoredPlane.new(color,@viewport)
else
sprites[planename]=AnimatedPlane.new(viewport)
sprites[planename].setBitmap(bitmapName)
for spr in sprites.values
if spr.is_a?(Window)
spr.windowskin=nil
end
end
end
end
#===============================================================================
# Ensure required method definitions
#===============================================================================
module Graphics
if !self.respond_to?("width")
def self.width; return 640; end
end
if !self.respond_to?("height")
def self.height; return 480; end
end
end
if !defined?(_INTL)
def _INTL(*args)
string=args[0].clone
for i in 1...args.length
string.gsub!(/\{#{i}\}/,"#{args[i]}")
end
return string
end
end
if !defined?(_ISPRINTF)
def _ISPRINTF(*args)
string=args[0].clone
for i in 1...args.length
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
next sprintf("%"+$1,args[i])
}
end
return string
end
end
if !defined?(_MAPINTL)
def _MAPINTL(*args)
string=args[1].clone
for i in 2...args.length
string.gsub!(/\{#{i}\}/,"#{args[i+1]}")
end
return string
end
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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); proc.call(self)
elsif cb.is_a?(Array); cb[0].method(cb[1]).call(self)
elsif cb.is_a?(Method); cb.call(self)
end
end
def setCallback(delay, cb=nil)
delay = ensureDelayAndDuration(delay)
@processes.push([nil,delay,0,0,cb])
end
def running?
return @processes.length>0
end
def totalDuration
ret = 0
for process in @processes
dur = process[1]+process[2]
ret = dur if dur>ret
end
ret *= 20.0/Graphics.frame_rate
return ret.to_i
end
def ensureDelayAndDuration(delay, duration=nil)
delay = self.totalDuration if delay<0
delay *= Graphics.frame_rate/20.0
if !duration.nil?
duration *= Graphics.frame_rate/20.0
return delay.to_i, duration.to_i
end
return delay.to_i
end
def ensureDelay(delay)
return ensureDelayAndDuration(delay)
end
# speed is the angle to change by in 1/20 of a second. @rotate_speed is the
# angle to change by per frame.
# NOTE: This is not compatible with manually changing the angle at a certain
# point. If you make a sprite auto-rotate, you should not try to alter
# the angle another way too.
def rotate(speed)
@rotate_speed = speed*20.0/Graphics.frame_rate
while @rotate_speed<0; @rotate_speed += 360; end
@rotate_speed %= 360
end
def erase
self.name = ""
end
def clearProcesses
@processes = []
end
def adjustPosition(xOffset, yOffset)
for process in @processes
next if process[0]!=Processes::XY
process[5] += xOffset
process[6] += yOffset
process[7] += xOffset
process[8] += yOffset
end
end
def move(delay, duration, origin, x, y, zoom_x=100.0, zoom_y=100.0, opacity=255)
setOrigin(delay,duration,origin)
moveXY(delay,duration,x,y)
moveZoomXY(delay,duration,zoom_x,zoom_y)
moveOpacity(delay,duration,opacity)
end
def moveXY(delay, duration, x, y, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
@processes.push([Processes::XY,delay,duration,0,cb,@x,@y,x,y])
end
def setXY(delay, x, y, cb=nil)
moveXY(delay,0,x,y,cb)
end
def moveCurve(delay, duration, x1, y1, x2, y2, x3, y3, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
@processes.push([Processes::Curve,delay,duration,0,cb,[@x,@y,x1,y1,x2,y2,x3,y3]])
end
def moveDelta(delay, duration, x, y, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
@processes.push([Processes::DeltaXY,delay,duration,0,cb,@x,@y,x,y])
end
def setDelta(delay, x, y, cb=nil)
moveDelta(delay,0,x,y,cb)
end
def moveZ(delay, duration, z, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
@processes.push([Processes::Z,delay,duration,0,cb,@z,z])
end
def setZ(delay, z, cb=nil)
moveZ(delay,0,z,cb)
end
def moveZoomXY(delay, duration, zoom_x, zoom_y, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
@processes.push([Processes::Zoom,delay,duration,0,cb,@zoom_x,@zoom_y,zoom_x,zoom_y])
end
def setZoomXY(delay, zoom_x, zoom_y, cb=nil)
moveZoomXY(delay,0,zoom_x,zoom_y,cb)
end
def moveZoom(delay, duration, zoom, cb=nil)
moveZoomXY(delay,duration,zoom,zoom,cb)
end
def setZoom(delay, zoom, cb=nil)
moveZoomXY(delay,0,zoom,zoom,cb)
end
def moveAngle(delay, duration, angle, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
@processes.push([Processes::Angle,delay,duration,0,cb,@angle,angle])
end
def setAngle(delay, angle, cb=nil)
moveAngle(delay,0,angle,cb)
end
def moveTone(delay, duration, tone, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
target = (tone) ? tone.clone : Tone.new(0,0,0,0)
@processes.push([Processes::Tone,delay,duration,0,cb,@tone.clone,target])
end
def setTone(delay, tone, cb=nil)
moveTone(delay,0,tone,cb)
end
def moveColor(delay, duration, color, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
target = (color) ? color.clone : Color.new(0,0,0,0)
@processes.push([Processes::Color,delay,duration,0,cb,@color.clone,target])
end
def setColor(delay, color, cb=nil)
moveColor(delay,0,color,cb)
end
# Hue changes don't actually work.
def moveHue(delay, duration, hue, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
@processes.push([Processes::Hue,delay,duration,0,cb,@hue,hue])
end
# Hue changes don't actually work.
def setHue(delay, hue, cb=nil)
moveHue(delay,0,hue,cb)
end
def moveOpacity(delay, duration, opacity, cb=nil)
delay, duration = ensureDelayAndDuration(delay,duration)
@processes.push([Processes::Opacity,delay,duration,0,cb,@opacity,opacity])
end
def setOpacity(delay, opacity, cb=nil)
moveOpacity(delay,0,opacity,cb)
end
def setVisible(delay, visible, cb=nil)
delay = ensureDelay(delay)
@processes.push([Processes::Visible,delay,0,0,cb,visible])
end
# Only values of 0 (normal), 1 (additive) and 2 (subtractive) are allowed.
def setBlendType(delay, blend, cb=nil)
delay = ensureDelayAndDuration(delay)
@processes.push([Processes::BlendType,delay,0,0,cb,blend])
end
def setSE(delay, seFile, volume=nil, cb=nil)
delay = ensureDelay(delay)
@processes.push([Processes::SE,delay,0,0,cb,seFile,volume])
end
def setName(delay, name, cb=nil)
delay = ensureDelay(delay)
@processes.push([Processes::Name,delay,0,0,cb,name])
end
def setOrigin(delay, origin, cb=nil)
delay = ensureDelay(delay)
@processes.push([Processes::Origin,delay,0,0,cb,origin])
end
def setSrc(delay, srcX, srcY, cb=nil)
delay = ensureDelay(delay)
@processes.push([Processes::Src,delay,0,0,cb,srcX,srcY])
end
def setSrcSize(delay, srcWidth, srcHeight, cb=nil)
delay = ensureDelay(delay)
@processes.push([Processes::SrcSize,delay,0,0,cb,srcWidth,srcHeight])
end
# Used to cut Pokémon sprites off when they faint and sink into the ground.
def setCropBottom(delay, y, cb=nil)
delay = ensureDelay(delay)
@processes.push([Processes::CropBottom,delay,0,0,cb,y])
end
def update
procEnded = false
@frameUpdates.clear
for i in 0...@processes.length
process = @processes[i]
# Decrease delay of processes that are scheduled to start later
if process[1]>=0
# Set initial values if the process will start this frame
if process[1]==0
case process[0]
when Processes::XY
process[5] = @x
process[6] = @y
when Processes::DeltaXY
process[5] = @x
process[6] = @y
process[7] += @x
process[8] += @y
when Processes::Curve
process[5][0] = @x
process[5][1] = @y
when Processes::Z
process[5] = @z
when Processes::Zoom
process[5] = @zoom_x
process[6] = @zoom_y
when Processes::Angle
process[5] = @angle
when Processes::Tone
process[5] = @tone.clone
when Processes::Color
process[5] = @color.clone
when Processes::Hue
process[5] = @hue
when Processes::Opacity
process[5] = @opacity
end
end
# Decrease delay counter
process[1] -= 1
# Process hasn't started yet, skip to the next one
next if process[1]>=0
end
# Update process
@frameUpdates.push(process[0]) if !@frameUpdates.include?(process[0])
fra = (process[2]==0) ? 1 : process[3] # Frame counter
dur = (process[2]==0) ? 1 : process[2] # Total duration of process
case process[0]
when Processes::XY, Processes::DeltaXY
@x = process[5] + fra * (process[7] - process[5]) / dur
@y = process[6] + fra * (process[8] - process[6]) / dur
when Processes::Curve
@x, @y = getCubicPoint2(process[5],fra.to_f/dur)
when Processes::Z
@z = process[5] + fra * (process[6] - process[5]) / dur
when Processes::Zoom
@zoom_x = process[5] + fra * (process[7] - process[5]) / dur
@zoom_y = process[6] + fra * (process[8] - process[6]) / dur
when Processes::Angle
@angle = process[5] + fra * (process[6] - process[5]) / dur
when Processes::Tone
@tone.red = process[5].red + fra * (process[6].red - process[5].red) / dur
@tone.green = process[5].green + fra * (process[6].green - process[5].green) / dur
@tone.blue = process[5].blue + fra * (process[6].blue - process[5].blue) / dur
@tone.gray = process[5].gray + fra * (process[6].gray - process[5].gray) / dur
when Processes::Color
@color.red = process[5].red + fra * (process[6].red - process[5].red) / dur
@color.green = process[5].green + fra * (process[6].green - process[5].green) / dur
@color.blue = process[5].blue + fra * (process[6].blue - process[5].blue) / dur
@color.alpha = process[5].alpha + fra * (process[6].alpha - process[5].alpha) / dur
when Processes::Hue
@hue = (process[6] - process[5]).to_f / dur
when Processes::Opacity
@opacity = process[5] + fra * (process[6] - process[5]) / dur
when Processes::Visible
@visible = process[5]
when Processes::BlendType
@blend_type = process[5]
when Processes::SE
pbSEPlay(process[5],process[6])
when Processes::Name
@name = process[5]
when Processes::Origin
@origin = process[5]
when Processes::Src
@src_rect.x = process[5]
@src_rect.y = process[6]
when Processes::SrcSize
@src_rect.width = process[5]
@src_rect.height = process[6]
when Processes::CropBottom
@cropBottom = process[5]
end
# Increase frame counter
process[3] += 1
if process[3]>process[2]
# Process has ended, erase it
callback(process[4]) if process[4]
@processes[i] = nil
procEnded = true
end
end
# Clear out empty spaces in @processes array caused by finished processes
@processes.compact! if procEnded
# Add the constant rotation speed
if @rotate_speed != 0
@frameUpdates.push(Processes::Angle) if !@frameUpdates.include?(Processes::Angle)
@angle += @rotate_speed
while @angle<0; @angle += 360; end
@angle %= 360
end
end
end
#===============================================================================
#
#===============================================================================
def setPictureSprite(sprite, picture, iconSprite=false)
return if picture.frameUpdates.length==0
for i in 0...picture.frameUpdates.length
case picture.frameUpdates[i]
when Processes::XY, Processes::DeltaXY
sprite.x = picture.x.round
sprite.y = picture.y.round
when Processes::Z
sprite.z = picture.z
when Processes::Zoom
sprite.zoom_x = picture.zoom_x / 100.0
sprite.zoom_y = picture.zoom_y / 100.0
when Processes::Angle
sprite.angle = picture.angle
when Processes::Tone
sprite.tone = picture.tone
when Processes::Color
sprite.color = picture.color
when Processes::Hue
# This doesn't do anything.
when Processes::BlendType
sprite.blend_type = picture.blend_type
when Processes::Opacity
sprite.opacity = picture.opacity
when Processes::Visible
sprite.visible = picture.visible
when Processes::Name
sprite.name = picture.name if iconSprite && sprite.name != picture.name
when Processes::Origin
case picture.origin
when PictureOrigin::TopLeft, PictureOrigin::Left, PictureOrigin::BottomLeft
sprite.ox = 0
when PictureOrigin::Top, PictureOrigin::Center, PictureOrigin::Bottom
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width/2 : 0
when PictureOrigin::TopRight, PictureOrigin::Right, PictureOrigin::BottomRight
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width : 0
end
case picture.origin
when PictureOrigin::TopLeft, PictureOrigin::Top, PictureOrigin::TopRight
sprite.oy = 0
when PictureOrigin::Left, PictureOrigin::Center, PictureOrigin::Right
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height/2 : 0
when PictureOrigin::BottomLeft, PictureOrigin::Bottom, PictureOrigin::BottomRight
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height : 0
end
when Processes::Src
next unless iconSprite && sprite.src_rect
sprite.src_rect.x = picture.src_rect.x
sprite.src_rect.y = picture.src_rect.y
when Processes::SrcSize
next unless iconSprite && sprite.src_rect
sprite.src_rect.width = picture.src_rect.width
sprite.src_rect.height = picture.src_rect.height
end
end
if iconSprite && sprite.src_rect && picture.cropBottom>=0
spriteBottom = sprite.y-sprite.oy+sprite.src_rect.height
if spriteBottom>picture.cropBottom
sprite.src_rect.height = [picture.cropBottom-sprite.y+sprite.oy,0].max
end
end
end
def setPictureIconSprite(sprite, picture)
setPictureSprite(sprite,picture,true)
end

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