Advertisement
Guest User

Untitled

a guest
Sep 21st, 2015
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 128.19 KB | None | 0 0
  1. module MessageConfig
  2.   FontName        = "Power Green" # Power Green
  3.   # in Graphics/Windowskins/ (specify empty string to use the default windowskin)
  4.   TextSkinName    = "speech hgss 1"
  5.   ChoiceSkinName  = "choice 1"
  6.   WindowOpacity   = 255
  7.   TextSpeed       = nil # can be positive to wait frames or negative to
  8.                         # show multiple characters in a single frame
  9.   LIGHTTEXTBASE   = Color.new(248,248,248)
  10.   LIGHTTEXTSHADOW = Color.new(72,80,88)
  11.   DARKTEXTBASE    = Color.new(90,82,82)
  12.   DARKTEXTSHADOW  = Color.new(165,165,173)
  13.   # 0 = Pause cursor is displayed at end of text
  14.   # 1 = Pause cursor is displayed at bottom right
  15.   # 2 = Pause cursor is displayed at lower middle side
  16.   CURSORMODE      = 1
  17.   FontSubstitutes = {
  18.      "Power Red and Blue"=>"Pokemon RS",
  19.      "Power Red and Green"=>"Pokemon FireLeaf",
  20.      "Power Green"=>"Pokemon Emerald",
  21.      "Power Green Narrow"=>"Pokemon Emerald Narrow",
  22.      "Power Green Small"=>"Pokemon Emerald Small",
  23.      "Power Clear"=>"Pokemon DP"
  24.   }
  25.   @@systemFrame     = nil
  26.   @@defaultTextSkin = nil
  27.   @@systemFont      = nil
  28.   @@textSpeed       = nil
  29.  
  30.   def self.pbTryFonts(*args)
  31.     for a in args
  32.       if a && a.is_a?(String)
  33.         return a if Font.exist?(a)
  34.         a=MessageConfig::FontSubstitutes[a] || a
  35.         return a if Font.exist?(a)
  36.       elsif a && a.is_a?(Array)
  37.         for aa in a
  38.           ret=MessageConfig.pbTryFonts(aa)
  39.           return ret if ret!=""
  40.         end
  41.       end
  42.     end
  43.     return ""
  44.   end
  45.  
  46.   def self.pbDefaultTextSpeed
  47.     return TextSpeed ? TextSpeed : (Graphics.width > 400) ? -2 : 1
  48.   end
  49.  
  50.   def self.pbDefaultSystemFrame
  51.     return "" if !MessageConfig::ChoiceSkinName
  52.     return pbResolveBitmap("Graphics/Windowskins/"+MessageConfig::ChoiceSkinName)||""
  53.   end
  54.  
  55.   def self.pbDefaultSpeechFrame
  56.     return "" if !MessageConfig::TextSkinName
  57.     return pbResolveBitmap("Graphics/Windowskins/"+MessageConfig::TextSkinName)||""
  58.   end
  59.  
  60.   def self.pbDefaultSystemFontName
  61.     return MessageConfig.pbTryFonts(MessageConfig::FontName,"Arial Narrow","Arial")
  62.   end
  63.  
  64.   def self.pbDefaultWindowskin
  65.     skin=load_data("Data/System.rxdata").windowskin_name rescue nil
  66.     if skin && skin!=""
  67.       skin=pbResolveBitmap("Graphics/Windowskins/"+skin) || ""
  68.     end
  69.     if !skin || skin==""
  70.       skin=pbResolveBitmap("Graphics/System/Window")
  71.     end
  72.     if !skin || skin==""
  73.       skin=pbResolveBitmap("Graphics/Windowskins/001-Blue01")
  74.     end
  75.     return skin || ""
  76.   end
  77.  
  78.   def self.pbGetSpeechFrame
  79.     if !@@defaultTextSkin
  80.       skin=MessageConfig.pbDefaultSpeechFrame()
  81.       if !skin || skin==""
  82.         skin=MessageConfig.pbDefaultWindowskin()
  83.       end
  84.       @@defaultTextSkin=skin || ""
  85.     end
  86.     return @@defaultTextSkin
  87.   end
  88.  
  89.   def self.pbGetTextSpeed
  90.     if !@@textSpeed
  91.       @@textSpeed=pbDefaultTextSpeed()
  92.     end
  93.     return @@textSpeed
  94.   end
  95.  
  96.   def self.pbGetSystemFontName
  97.     if !@@systemFont
  98.       @@systemFont=pbDefaultSystemFontName()
  99.     end
  100.     return @@systemFont
  101.   end
  102.  
  103.   def self.pbGetSystemFrame
  104.     if !@@systemFrame
  105.       skin=MessageConfig.pbDefaultSystemFrame()
  106.       if !skin || skin==""
  107.         skin=MessageConfig.pbDefaultWindowskin()
  108.       end
  109.       @@systemFrame=skin || ""
  110.     end
  111.     return @@systemFrame
  112.   end
  113.  
  114.   def self.pbSetSystemFrame(value)
  115.     @@systemFrame=pbResolveBitmap(value) || ""
  116.   end
  117.  
  118.   def self.pbSetSpeechFrame(value)
  119.     @@defaultTextSkin=pbResolveBitmap(value) || ""
  120.   end
  121.  
  122.   def self.pbSetSystemFontName(value)
  123.     @@systemFont=MessageConfig.pbTryFonts(value,"Arial Narrow","Arial")
  124.   end
  125.  
  126.   def self.pbSetTextSpeed(value)
  127.     @@textSpeed=value
  128.   end
  129. end
  130.  
  131.  
  132. #############################
  133. #############################
  134.  
  135.  
  136. # Works around a problem with FileTest.directory if directory contains accent marks
  137. def safeIsDirectory?(f)
  138.   ret=false
  139.   Dir.chdir(f) { ret=true } rescue nil
  140.   return ret
  141. end
  142.  
  143. # Works around a problem with FileTest.exist if path contains accent marks
  144. def safeExists?(f)
  145.   ret=false
  146.   if f[/\A[\x20-\x7E]*\z/]
  147.     return FileTest.exist?(f)
  148.   end
  149.   begin
  150.     File.open(f,"rb") { ret=true }
  151.   rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
  152.     ret=false
  153.   end
  154.   return ret
  155. end
  156.  
  157. # Similar to "Dir.glob", but designed to work around a problem with accessing
  158. # files if a path contains accent marks.
  159. # "dir" is the directory path, "wildcard" is the filename pattern to match.
  160. def safeGlob(dir,wildcard)
  161.   ret=[]
  162.   afterChdir=false
  163.   begin
  164.     Dir.chdir(dir){
  165.        afterChdir=true
  166.        Dir.glob(wildcard){|f|
  167.           ret.push(dir+"/"+f)
  168.        }
  169.     }
  170.   rescue Errno::ENOENT
  171.     raise if afterChdir
  172.   end
  173.   if block_given?
  174.     ret.each{|f|
  175.        yield(f)
  176.     }
  177.   end
  178.   return (block_given?) ? nil : ret
  179. end
  180.  
  181.  
  182. #############################
  183. #############################
  184.  
  185.  
  186. module GifLibrary
  187.   @@loadlib=Win32API.new("Kernel32.dll","LoadLibrary",'p','')
  188.   if safeExists?("gif.dll")
  189.     PngDll=@@loadlib.call("gif.dll")
  190.     GifToPngFiles=Win32API.new("gif.dll","GifToPngFiles",'pp','l')
  191.     GifToPngFilesInMemory=Win32API.new("gif.dll","GifToPngFilesInMemory",'plp','l')
  192.     CopyDataString=Win32API.new("gif.dll","CopyDataString",'lpl','l')
  193.     FreeDataString=Win32API.new("gif.dll","FreeDataString",'l','')
  194.   else
  195.     PngDll=nil
  196.   end
  197.  
  198.   def self.getDataFromResult(result)
  199.     datasize=CopyDataString.call(result,"",0)
  200.     ret=nil
  201.     if datasize!=0
  202.       data="0"*datasize
  203.       CopyDataString.call(result,data,datasize)
  204.       ret=data.unpack("V*")
  205.     end
  206.     FreeDataString.call(result)
  207.     return ret
  208.   end
  209. end
  210.  
  211.  
  212. #############################
  213. #############################
  214.  
  215.  
  216. class AnimatedBitmap
  217.   def initialize(file,hue=0)
  218.     raise "filename is nil" if file==nil
  219.     if file[/^\[(\d+)\]/]
  220.       @bitmap=PngAnimatedBitmap.new(file,hue)
  221.     else
  222.       @bitmap=GifBitmap.new(file,hue)
  223.     end
  224.   end
  225.  
  226.   def [](index); @bitmap[index]; end
  227.   def width; @bitmap.bitmap.width; end
  228.   def height; @bitmap.bitmap.height; end
  229.   def length; @bitmap.length; end
  230.   def each; @bitmap.each {|item| yield item }; end
  231.   def bitmap; @bitmap.bitmap; end
  232.   def currentIndex; @bitmap.currentIndex; end
  233.   def frameDelay; @bitmap.frameDelay; end
  234.   def totalFrames; @bitmap.totalFrames; end
  235.   def disposed?; @bitmap.disposed?; end
  236.   def update; @bitmap.update; end
  237.   def dispose; @bitmap.dispose; end
  238.   def deanimate; @bitmap.deanimate; end
  239.   def copy; @bitmap.copy; end
  240. end
  241.  
  242.  
  243.  
  244. def pbGetTileBitmap(filename, tile_id, hue)
  245.   return BitmapCache.tileEx(filename, tile_id, hue){|f|
  246.      AnimatedBitmap.new("Graphics/Tilesets/"+filename).deanimate;
  247.   }
  248. end
  249.  
  250. def pbGetAnimation(name,hue=0)
  251.   return AnimatedBitmap.new("Graphics/Animations/"+name,hue).deanimate
  252. end
  253.  
  254. def pbGetTileset(name,hue=0)
  255.   return AnimatedBitmap.new("Graphics/Tilesets/"+name,hue).deanimate
  256. end
  257.  
  258. def pbGetAutotile(name,hue=0)
  259.   return AnimatedBitmap.new("Graphics/Autotiles/"+name,hue).deanimate
  260. end
  261.  
  262. #########################
  263. #
  264. # Message support
  265. #
  266. #########################
  267. if !defined?(_INTL)
  268.   def _INTL(*args);
  269.     string=args[0].clone
  270.     for i in 1...args.length
  271.       string.gsub!(/\{#{i}\}/,"#{args[i]}")
  272.     end
  273.     return string    
  274.   end
  275. end
  276.  
  277. if !defined?(_ISPRINTF)
  278.   def _ISPRINTF(*args);
  279.     string=args[0].clone
  280.     for i in 1...args.length
  281.       string.gsub!(/\{#{i}\:([^\}]+?)\}/){|m|
  282.          next sprintf("%"+$1,args[i])
  283.       }
  284.     end
  285.     return string
  286.   end
  287. end
  288.  
  289. if !defined?(_MAPINTL)
  290.   def _MAPINTL(*args);
  291.     string=args[1].clone
  292.     for i in 2...args.length
  293.       string.gsub!(/\{#{i}\}/,"#{args[i+1]}")
  294.     end
  295.     return string  
  296.   end
  297. end
  298.  
  299.  
  300.  
  301. module Graphics
  302.   if !self.respond_to?("width")
  303.     def self.width; return 640; end
  304.   end
  305.   if !self.respond_to?("height")
  306.     def self.height; return 480; end
  307.   end
  308. end
  309.  
  310.  
  311. #############################
  312. #############################
  313.  
  314.  
  315. module MiniRegistry
  316.   HKEY_CLASSES_ROOT = 0x80000000
  317.   HKEY_CURRENT_USER = 0x80000001
  318.   HKEY_LOCAL_MACHINE = 0x80000002
  319.   HKEY_USERS = 0x80000003
  320.   FormatMessageA=Win32API.new("kernel32","FormatMessageA","LPLLPLP","L")
  321.   RegOpenKeyExA=Win32API.new("advapi32","RegOpenKeyExA","LPLLP","L")
  322.   RegCloseKey=Win32API.new("advapi32","RegCloseKey","L","L")
  323.   RegQueryValueExA=Win32API.new("advapi32","RegQueryValueExA","LPLPPP","L")
  324.  
  325.   def self.open(hkey,subkey,bit64=false)
  326.     key=0.chr*4
  327.     flag=bit64 ? 0x20119 : 0x20019
  328.     rg=RegOpenKeyExA.call(hkey, subkey, 0, flag, key)
  329.     if rg!=0
  330.       return nil
  331.     end
  332.     key=key.unpack("V")[0]
  333.     if block_given?
  334.       begin
  335.         yield(key)
  336.       ensure
  337.         check(RegCloseKey.call(key))
  338.       end
  339.     else
  340.       return key
  341.     end
  342.   end
  343.  
  344.   def self.close(hkey); check(RegCloseKey.call(hkey)) if hkey; end
  345.  
  346.   def self.get(hkey,subkey,name,defaultValue=nil,bit64=false)
  347.     self.open(hkey,subkey,bit64){|key|
  348.        return self.read(key,name) rescue defaultValue
  349.     }
  350.     return defaultValue
  351.   end
  352.  
  353.   def self.read(hkey,name)
  354.     hkey=0 if !hkey
  355.     type=0.chr*4; size=0.chr*4
  356.     check(RegQueryValueExA.call(hkey,name,0,type,0,size))
  357.     data=" "*size.unpack("V")[0]
  358.     check(RegQueryValueExA.call(hkey,name,0,type,data,size))
  359.     type=type.unpack("V")[0]
  360.     data=data[0,size.unpack("V")[0]]
  361.     case type
  362.     when 1; return data.chop # REG_SZ
  363.     when 2; return data.gsub(/%([^%]+)%/) { ENV[$1] || $& } # REG_EXPAND_SZ
  364.     when 3; return data # REG_BINARY
  365.     when 4; return data.unpack("V")[0] # REG_DWORD
  366.     when 5; return data.unpack("V")[0] # REG_DWORD_BIG_ENDIAN
  367.     when 11; qw=data.unpack("VV"); return (data[1]<<32|data[0]) # REG_QWORD
  368.     else; raise "Type #{type} not supported."
  369.     end
  370.   end
  371.  
  372.   private
  373.  
  374.   def self.check(code)
  375.     if code!=0
  376.       msg="\0"*1024
  377.       len = FormatMessageA.call(0x1200, 0, code, 0, msg, 1024, 0)
  378.       raise msg[0, len].tr("\r", '').chomp
  379.     end
  380.   end
  381. end
  382.  
  383.  
  384.  
  385. def getUnicodeStringFromAnsi(addr)
  386.   return "" if addr==0
  387.   rtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
  388.   ret=""
  389.   data="x"
  390.   index=(addr.is_a?(String)) ? 0 : addr
  391.   loop do
  392.     if addr.is_a?(String)
  393.       data=addr[index,1]
  394.     else
  395.       rtlMoveMemory_pi.call(data, index, 1)
  396.     end
  397.     index+=1
  398.     codepoint=data.unpack("C")[0]
  399.     break if codepoint==0 || !codepoint
  400.     break if codepoint==0
  401.     if codepoint<=0x7F
  402.       ret+=codepoint.chr
  403.     else
  404.       ret+=(0xC0|((codepoint>>6)&0x1F)).chr
  405.       ret+=(0x80|(codepoint   &0x3F)).chr
  406.     end
  407.   end
  408.   return ret
  409. end
  410.  
  411. def getUnicodeString(addr)
  412.   return "" if addr==0
  413.   rtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
  414.   ret=""
  415.   data="xx"
  416.   index=(addr.is_a?(String)) ? 0 : addr
  417.   loop do
  418.     if addr.is_a?(String)
  419.       data=addr[index,2]
  420.     else
  421.       rtlMoveMemory_pi.call(data, index, 2)
  422.     end
  423.     codepoint=data.unpack("v")[0]
  424.     break if codepoint==0
  425.     index+=2
  426.     if codepoint<=0x7F
  427.       ret+=codepoint.chr
  428.     elsif codepoint<=0x7FF
  429.       ret+=(0xC0|((codepoint>>6)&0x1F)).chr
  430.       ret+=(0x80|(codepoint   &0x3F)).chr
  431.     elsif codepoint<=0xFFFF
  432.       ret+=(0xE0|((codepoint>>12)&0x0F)).chr
  433.       ret+=(0x80|((codepoint>>6)&0x3F)).chr
  434.       ret+=(0x80|(codepoint   &0x3F)).chr
  435.     elsif codepoint<=0x10FFFF
  436.       ret+=(0xF0|((codepoint>>18)&0x07)).chr
  437.       ret+=(0x80|((codepoint>>12)&0x3F)).chr
  438.       ret+=(0x80|((codepoint>>6)&0x3F)).chr
  439.       ret+=(0x80|(codepoint   &0x3F)).chr
  440.     end
  441.   end
  442.   return ret
  443. end
  444.  
  445. def getKnownFolder(guid)
  446.   packedGuid=guid.pack("VvvC*")
  447.   shGetKnownFolderPath=Win32API.new("shell32.dll","SHGetKnownFolderPath","pllp","i") rescue nil
  448.   coTaskMemFree=Win32API.new("ole32.dll","CoTaskMemFree","i","") rescue nil
  449.   if shGetKnownFolderPath && coTaskMemFree
  450.     path="\0"*4
  451.     ret=shGetKnownFolderPath.call(packedGuid,0,0,path)
  452.     path=path.unpack("V")[0]
  453.     ret=getUnicodeString(path)
  454.     coTaskMemFree.call(path)
  455.     return ret
  456.   end
  457.   return ""
  458. end
  459.  
  460.  
  461.  
  462. module RTP
  463.   @rtpPaths=nil
  464.  
  465.   def self.exists?(filename,extensions=[])
  466.     return false if !filename || filename==""
  467.     eachPathFor(filename) {|path|
  468.        return true if safeExists?(path)
  469.        for ext in extensions
  470.          return true if safeExists?(path+ext)
  471.        end
  472.     }
  473.     return false
  474.   end
  475.  
  476.   def self.getImagePath(filename)
  477.     return self.getPath(filename,["",".png",".jpg",".gif",".bmp",".jpeg"])
  478.   end
  479.  
  480.   def self.getAudioPath(filename)
  481.     return self.getPath(filename,["",".mp3",".wav",".wma",".mid",".ogg",".midi"])
  482.   end
  483.  
  484.   def self.getPath(filename,extensions=[])
  485.     return filename if !filename || filename==""
  486.     eachPathFor(filename) {|path|
  487.        return path if safeExists?(path)
  488.        for ext in extensions
  489.          file=path+ext
  490.          return file if safeExists?(file)
  491.        end
  492.     }
  493.     return filename
  494.   end
  495.  
  496.  # Gets the absolute RGSS paths for the given file name
  497.   def self.eachPathFor(filename)
  498.     return if !filename
  499.     if filename[/^[A-Za-z]\:[\/\\]/] || filename[/^[\/\\]/]
  500.       # filename is already absolute
  501.       yield filename
  502.     else
  503.       # relative path
  504.       RTP.eachPath {|path|
  505.          if path=="./"
  506.            yield filename
  507.          else
  508.            yield path+filename
  509.          end
  510.       }
  511.     end
  512.   end
  513.  
  514.   # Gets all RGSS search paths
  515.   def self.eachPath
  516.     # XXX: Use "." instead of Dir.pwd because of problems retrieving files if
  517.     # the current directory contains an accent mark
  518.     yield ".".gsub(/[\/\\]/,"/").gsub(/[\/\\]$/,"")+"/"
  519.     if !@rtpPaths
  520.       tmp=Sprite.new
  521.       isRgss2=tmp.respond_to?("wave_amp")
  522.       tmp.dispose
  523.       @rtpPaths=[]
  524.       if isRgss2
  525.         rtp=getGameIniValue("Game","RTP")
  526.         if rtp!=""
  527.           rtp=MiniRegistry.get(MiniRegistry::HKEY_LOCAL_MACHINE,
  528.              "SOFTWARE\\Enterbrain\\RGSS2\\RTP",rtp,nil)
  529.           if rtp && safeIsDirectory?(rtp)
  530.             @rtpPaths.push(rtp.sub(/[\/\\]$/,"")+"/")
  531.           end
  532.         end
  533.       else
  534.         %w( RTP1 RTP2 RTP3 ).each{|v|
  535.            rtp=getGameIniValue("Game",v)
  536.            if rtp!=""
  537.              rtp=MiniRegistry.get(MiniRegistry::HKEY_LOCAL_MACHINE,
  538.                 "SOFTWARE\\Enterbrain\\RGSS\\RTP",rtp,nil)
  539.              if rtp && safeIsDirectory?(rtp)
  540.                @rtpPaths.push(rtp.sub(/[\/\\]$/,"")+"/")
  541.              end
  542.            end
  543.         }
  544.       end
  545.     end
  546.     @rtpPaths.each{|x| yield x }
  547.   end
  548.  
  549.   private
  550.  
  551.   def self.getGameIniValue(section,key)
  552.     val = "\0"*256
  553.     gps = Win32API.new('kernel32', 'GetPrivateProfileString',%w(p p p p l p), 'l')
  554.     gps.call(section, key, "", val, 256, ".\\Game.ini")
  555.     val.delete!("\0")
  556.     return val
  557.   end
  558.  
  559.   @@folder=nil
  560.  
  561.   def self.isDirWritable(dir)
  562.     return false if !dir || dir==""
  563.     loop do
  564.       name=dir.gsub(/[\/\\]$/,"")+"/writetest"
  565.       for i in 0...12
  566.         name+=sprintf("%02X",rand(256))
  567.       end
  568.       name+=".tmp"
  569.       if !safeExists?(name)
  570.         retval=false
  571.         begin
  572.           File.open(name,"wb"){retval=true}
  573.         rescue Errno::EINVAL, Errno::EACCES, Errno::ENOENT
  574.         ensure
  575.           File.delete(name) rescue nil
  576.         end
  577.         return retval
  578.       end
  579.     end
  580.   end
  581.  
  582.   def self.ensureGameDir(dir)
  583.     title=RTP.getGameIniValue("Game","Title")
  584.     title="RGSS Game" if title==""
  585.     title=title.gsub(/[^\w ]/,"_")
  586.     newdir=dir.gsub(/[\/\\]$/,"")+"/"+title
  587.     # Convert to UTF-8 because of ANSI function
  588.     newdir=getUnicodeStringFromAnsi(newdir)
  589.     Dir.mkdir(newdir) rescue nil
  590.     ret=safeIsDirectory?(newdir) ? newdir : dir
  591.     return ret
  592.   end
  593.  
  594.   def self.getSaveFileName(fileName)
  595.     return getSaveFolder().gsub(/[\/\\]$/,"")+"/"+fileName
  596.   end
  597.  
  598.   def self.getSaveFolder
  599.     if !@@folder
  600.       # XXX: Use "." instead of Dir.pwd because of problems retrieving files if
  601.       # the current directory contains an accent mark
  602.       pwd="."
  603.       # Get the known folder path for saved games
  604.       savedGames=getKnownFolder([0x4c5c32ff,0xbb9d,0x43b0,
  605.          0xb5,0xb4,0x2d,0x72,0xe5,0x4e,0xaa,0xa4])
  606.       if savedGames && savedGames!="" && isDirWritable(savedGames)
  607.         pwd=ensureGameDir(savedGames)
  608.       end
  609.       if isDirWritable(pwd)
  610.         @@folder=pwd
  611.       else
  612.         appdata=ENV["LOCALAPPDATA"]
  613.         if isDirWritable(appdata)
  614.           appdata=ensureGameDir(appdata)
  615.         else
  616.           appdata=ENV["APPDATA"]
  617.           if isDirWritable(appdata)
  618.             appdata=ensureGameDir(appdata)
  619.           elsif isDirWritable(pwd)
  620.             appdata=pwd
  621.           else
  622.             appdata="."
  623.           end
  624.         end
  625.         @@folder=appdata
  626.       end
  627.     end
  628.     return @@folder
  629.   end
  630. end
  631.  
  632.  
  633.  
  634. module FileTest
  635.   Image_ext = ['.bmp', '.png', '.jpg', '.jpeg', '.gif']
  636.   Audio_ext = ['.mp3', '.mid', '.midi', '.ogg', '.wav', '.wma']
  637.  
  638.   def self.audio_exist?(filename)
  639.     return RTP.exists?(filename,Audio_ext)
  640.   end
  641.  
  642.   def self.image_exist?(filename)
  643.     return RTP.exists?(filename,Image_ext)
  644.   end
  645. end
  646.  
  647.  
  648. ###########
  649.  
  650.  
  651. class PngAnimatedBitmap # :nodoc:
  652.   # Creates an animated bitmap from a PNG file.  
  653.   def initialize(file,hue=0)
  654.     @frames=[]
  655.     @currentFrame=0
  656.     @framecount=0
  657.     panorama=BitmapCache.load_bitmap(file,hue)
  658.     if file[/^\[(\d+)\]/]
  659.       # File has a frame count
  660.       numFrames=$1.to_i
  661.       if numFrames<=0
  662.         raise "Invalid frame count in #{file}"
  663.       end
  664.       if panorama.width % numFrames != 0
  665.         raise "Bitmap's width (#{panorama.width}) is not divisible by frame count: #{file}"
  666.       end
  667.       subWidth=panorama.width/numFrames
  668.       for i in 0...numFrames
  669.         subBitmap=BitmapWrapper.new(subWidth,panorama.height)
  670.         subBitmap.blt(0,0,panorama,Rect.new(subWidth*i,0,subWidth,panorama.height))
  671.         @frames.push(subBitmap)
  672.       end
  673.       panorama.dispose
  674.     else
  675.       @frames=[panorama]
  676.     end
  677.   end
  678.  
  679.   def [](index)
  680.     return @frames[index]
  681.   end
  682.  
  683.   def width; self.bitmap.width; end
  684.  
  685.   def height; self.bitmap.height; end
  686.  
  687.   def deanimate
  688.     for i in 1...@frames.length
  689.       @frames[i].dispose
  690.     end
  691.     @frames=[@frames[0]]
  692.     @currentFrame=0
  693.     return @frames[0]
  694.   end
  695.  
  696.   def bitmap
  697.     @frames[@currentFrame]
  698.   end
  699.  
  700.   def currentIndex
  701.     @currentFrame
  702.   end
  703.  
  704.   def frameDelay(index)
  705.     return 10
  706.   end
  707.  
  708.   def length
  709.     @frames.length
  710.   end
  711.  
  712.   def each
  713.     @frames.each {|item| yield item}
  714.   end
  715.  
  716.   def totalFrames
  717.     10*@frames.length
  718.   end
  719.  
  720.   def disposed?
  721.     @disposed
  722.   end
  723.  
  724.   def update
  725.     return if disposed?
  726.     if @frames.length>1
  727.       @framecount+=1
  728.       if @framecount>=10
  729.         @framecount=0
  730.         @currentFrame+=1
  731.         @currentFrame%=@frames.length
  732.       end
  733.     end
  734.   end
  735.  
  736.   def dispose
  737.     if !@disposed
  738.       for i in @frames
  739.         i.dispose
  740.       end
  741.     end
  742.     @disposed=true
  743.   end
  744.  
  745.   attr_accessor :frames # internal
  746.  
  747.   def copy
  748.     x=self.clone
  749.     x.frames=x.frames.clone
  750.     for i in 0...x.frames.length
  751.       x.frames[i]=x.frames[i].copy
  752.     end
  753.     return x
  754.   end
  755. end
  756.  
  757.  
  758.  
  759. #internal class
  760. class GifBitmap
  761.   # Creates a bitmap from a GIF file with the specified
  762.   # optional viewport.  Can also load non-animated bitmaps.
  763.   def initialize(file,hue=0)
  764.     @gifbitmaps=[]
  765.     @gifdelays=[]
  766.     @totalframes=0
  767.     @framecount=0
  768.     @currentIndex=0
  769.     @disposed=false
  770.     bitmap=nil
  771.     filestring=nil
  772.     filestrName=nil
  773.     file="" if !file
  774.     file=canonicalize(file)
  775.     begin
  776.       bitmap=BitmapCache.load_bitmap(file,hue)
  777.     rescue
  778.       bitmap=nil
  779.     end
  780.     if !bitmap || (bitmap.width==32 && bitmap.height==32)
  781.       if !file || file.length<1 || file[file.length-1]!=0x2F
  782.         if (filestring=pbGetFileChar(file))
  783.           filestrName=file
  784.         elsif (filestring=pbGetFileChar(file+".gif"))
  785.           filestrName=file+".gif"
  786.         elsif (filestring=pbGetFileChar(file+".png"))
  787.           filestrName=file+".png"
  788.         elsif (filestring=pbGetFileChar(file+".jpg"))
  789.           filestrName=file+".jpg"
  790.         elsif (filestring=pbGetFileChar(file+".bmp"))
  791.           filestrName=file+".bmp"
  792.         end
  793.       end
  794.     end
  795.     if bitmap && filestring && filestring[0]==0x47 &&
  796.        bitmap.width==32 && bitmap.height==32
  797.       #File.open("debug.txt","ab"){|f| f.puts("rejecting bitmap") }
  798.       bitmap.dispose
  799.       bitmap=nil
  800.     end
  801.     if bitmap
  802.       #File.open("debug.txt","ab"){|f| f.puts("reusing bitmap") }
  803.       # Have a regular non-animated bitmap
  804.       @totalframes=1
  805.       @framecount=0
  806.       @gifbitmaps=[bitmap]
  807.       @gifdelays=[1]
  808.     else
  809.       tmpBase=File.basename(file)+"_tmp_"
  810.       filestring=pbGetFileString(filestrName) if filestring
  811.       Dir.chdir(ENV["TEMP"]){ # navigate to temp folder since game might be on a CD-ROM
  812.          if filestring && filestring[0]==0x47 && GifLibrary::PngDll
  813.            result=GifLibrary::GifToPngFilesInMemory.call(filestring,
  814.               filestring.length,tmpBase)
  815.          else
  816.            result=0
  817.          end
  818.          if result>0
  819.            @gifdelays=GifLibrary.getDataFromResult(result)
  820.            @totalframes=@gifdelays.pop
  821.            for i in 0...@gifdelays.length
  822.              @gifdelays[i]=[@gifdelays[i],1].max
  823.              bmfile=sprintf("%s%d.png",tmpBase,i);
  824.              if safeExists?(bmfile)
  825.                gifbitmap=BitmapWrapper.new(bmfile)
  826.                @gifbitmaps.push(gifbitmap)
  827.                bmfile.hue_change(hue) if hue!=0
  828.                if hue==0 && @gifdelays.length==1
  829.                  BitmapCache.setKey(file,gifbitmap)
  830.                end
  831.                File.delete(bmfile)
  832.              else
  833.                @gifbitmaps.push(BitmapWrapper.new(32,32))
  834.              end
  835.            end
  836.          end
  837.       }
  838.       if @gifbitmaps.length==0
  839.         @gifbitmaps=[BitmapWrapper.new(32,32)]
  840.         @gifdelays=[1]
  841.       end
  842.       if @gifbitmaps.length==1
  843.         BitmapCache.setKey(file,@gifbitmaps[0])
  844.       end
  845.     end
  846.   end
  847.  
  848.   def [](index)
  849.     return @gifbitmaps[index]
  850.   end
  851.  
  852.   def width; self.bitmap.width; end
  853.  
  854.   def height; self.bitmap.height; end
  855.  
  856.   def deanimate
  857.     for i in 1...@gifbitmaps.length
  858.       @gifbitmaps[i].dispose
  859.     end
  860.     @gifbitmaps=[@gifbitmaps[0]]
  861.     @currentIndex=0
  862.     return @gifbitmaps[0]
  863.   end
  864.  
  865.   def bitmap
  866.     @gifbitmaps[@currentIndex]
  867.   end
  868.  
  869.   def currentIndex
  870.     @currentIndex
  871.   end
  872.  
  873.   def frameDelay(index)
  874.     return @gifdelay[index]/2 # Due to frame count being incremented by 2
  875.   end
  876.  
  877.   def length
  878.     @gifbitmaps.length
  879.   end
  880.  
  881.   def each
  882.     @gifbitmaps.each {|item| yield item }
  883.   end
  884.  
  885.   def totalFrames
  886.     @totalframes/2 # Due to frame count being incremented by 2
  887.   end
  888.  
  889.   def disposed?
  890.     @disposed
  891.   end
  892.  
  893.   def width
  894.     @gifbitmaps.length==0 ? 0 : @gifbitmaps[0].width
  895.   end
  896.  
  897.   def height
  898.     @gifbitmaps.length==0 ? 0 : @gifbitmaps[0].height
  899.   end
  900.  
  901.  # This function must be called in order to animate the GIF image.
  902.   def update
  903.     return if disposed?
  904.     if @gifbitmaps.length>0
  905.       @framecount+=2
  906.       @framecount=@totalframes<=0 ? 0 : @framecount%@totalframes
  907.       frametoshow=0
  908.       for i in 0...@gifdelays.length
  909.         frametoshow=i if @gifdelays[i]<=@framecount
  910.       end
  911.       @currentIndex=frametoshow
  912.     end
  913.   end
  914.  
  915.   def dispose
  916.     if !@disposed
  917.       for i in @gifbitmaps
  918.         i.dispose
  919.       end
  920.     end
  921.     @disposed=true
  922.   end
  923.  
  924.  attr_accessor :gifbitmaps # internal
  925.  attr_accessor :gifdelays # internal
  926.  
  927.   def copy
  928.     x=self.clone
  929.     x.gifbitmaps=x.gifbitmaps.clone
  930.     x.gifdelays=x.gifdelays.clone
  931.     for i in 0...x.gifbitmaps.length
  932.       x.gifbitmaps[i]=x.gifbitmaps[i].copy
  933.     end
  934.     return x
  935.   end
  936. end
  937.  
  938.  
  939. ########################
  940. ########################
  941.  
  942.  
  943. def pbStringToAudioFile(str)
  944.   if str[/^(.*)\:\s*(\d+)\s*\:\s*(\d+)\s*$/]
  945.     file=$1
  946.     volume=$2.to_i
  947.     pitch=$3.to_i
  948.     return RPG::AudioFile.new(file,volume,pitch)
  949.   elsif str[/^(.*)\:\s*(\d+)\s*$/]
  950.     file=$1
  951.     volume=$2.to_i
  952.     return RPG::AudioFile.new(file,volume,100)
  953.   else
  954.     return RPG::AudioFile.new(str,100,100)
  955.   end
  956. end
  957.  
  958. # Converts an object to an audio file.
  959. # str -- Either a string showing the filename or an RPG::AudioFile object.
  960. # Possible formats for _str_:
  961. # filename                        volume and pitch 100
  962. # filename:volume           pitch 100
  963. # filename:volume:pitch
  964. # volume -- Volume of the file, up to 100
  965. # pitch -- Pitch of the file, normally 100
  966. def pbResolveAudioFile(str,volume=nil,pitch=nil)
  967.   if str.is_a?(String)
  968.     str=pbStringToAudioFile(str)
  969.     str.volume=100
  970.     str.volume=volume if volume
  971.     str.pitch=100
  972.     str.pitch=pitch if pitch
  973.   end
  974.   if str.is_a?(RPG::AudioFile)
  975.     if volume || pitch
  976.       return RPG::AudioFile.new(str.name,
  977.                                 volume||str.volume||100,
  978.                                 pitch||str.pitch||100)
  979.     else
  980.       return str
  981.     end
  982.   end
  983.   return str
  984. end
  985.  
  986. # Plays a BGM file.
  987. # param -- Either a string showing the filename
  988. # (relative to Audio/BGM/) or an RPG::AudioFile object.
  989. # Possible formats for _param_:
  990. # filename                        volume and pitch 100
  991. # filename:volume           pitch 100
  992. # filename:volume:pitch
  993. # volume -- Volume of the file, up to 100
  994. # pitch -- Pitch of the file, normally 100
  995. def pbBGMPlay(param,volume=nil,pitch=nil)
  996.   return if !param
  997.   param=pbResolveAudioFile(param,volume,pitch)
  998.   if param.name && param.name!=""
  999.     if $game_system && $game_system.respond_to?("bgm_play")
  1000.       $game_system.bgm_play(param)
  1001.       return
  1002.     elsif (RPG.const_defined?(:BGM) rescue false)
  1003.       b=RPG::BGM.new(param.name,param.volume,param.pitch)
  1004.       if b && b.respond_to?("play")
  1005.         b.play; return
  1006.       end
  1007.     end
  1008.     Audio.bgm_play(canonicalize("Audio/BGM/"+param.name),param.volume,param.pitch)
  1009.   end
  1010. end
  1011.  
  1012. # Plays an ME file.
  1013. # param -- Either a string showing the filename
  1014. # (relative to Audio/ME/) or an RPG::AudioFile object.
  1015. # Possible formats for _param_:
  1016. # filename                        volume and pitch 100
  1017. # filename:volume           pitch 100
  1018. # filename:volume:pitch
  1019. # volume -- Volume of the file, up to 100
  1020. # pitch -- Pitch of the file, normally 100
  1021. def pbMEPlay(param,volume=nil,pitch=nil)
  1022.   return if !param
  1023.   param=pbResolveAudioFile(param,volume,pitch)
  1024.   if param.name && param.name!=""
  1025.     if $game_system && $game_system.respond_to?("me_play")
  1026.       $game_system.me_play(param)
  1027.       return
  1028.     elsif (RPG.const_defined?(:ME) rescue false)
  1029.       b=RPG::ME.new(param.name,param.volume,param.pitch)
  1030.       if b && b.respond_to?("play")
  1031.         b.play; return
  1032.       end
  1033.     end
  1034.     Audio.me_play(canonicalize("Audio/ME/"+param.name),param.volume,param.pitch)
  1035.   end
  1036. end
  1037.  
  1038. # Plays a BGS file.
  1039. # param -- Either a string showing the filename
  1040. # (relative to Audio/BGS/) or an RPG::AudioFile object.
  1041. # Possible formats for _param_:
  1042. # filename                        volume and pitch 100
  1043. # filename:volume           pitch 100
  1044. # filename:volume:pitch
  1045. # volume -- Volume of the file, up to 100
  1046. # pitch -- Pitch of the file, normally 100
  1047. def pbBGSPlay(param,volume=nil,pitch=nil)
  1048.   return if !param
  1049.   param=pbResolveAudioFile(param,volume,pitch)
  1050.   if param.name && param.name!=""
  1051.     if $game_system && $game_system.respond_to?("bgs_play")
  1052.       $game_system.bgs_play(param)
  1053.       return
  1054.     elsif (RPG.const_defined?(:BGS) rescue false)
  1055.       b=RPG::BGS.new(param.name,param.volume,param.pitch)
  1056.       if b && b.respond_to?("play")
  1057.         b.play; return
  1058.       end
  1059.     end
  1060.     Audio.bgs_play(canonicalize("Audio/BGS/"+param.name),param.volume,param.pitch)
  1061.   end
  1062. end
  1063.  
  1064. # Plays an SE file.
  1065. # param -- Either a string showing the filename
  1066. # (relative to Audio/SE/) or an RPG::AudioFile object.
  1067. # Possible formats for _param_:
  1068. # filename                        volume and pitch 100
  1069. # filename:volume           pitch 100
  1070. # filename:volume:pitch
  1071. # volume -- Volume of the file, up to 100
  1072. # pitch -- Pitch of the file, normally 100
  1073. def pbSEPlay(param,volume=nil,pitch=nil)
  1074.   return if !param
  1075.   param=pbResolveAudioFile(param,volume,pitch)
  1076.   if param.name && param.name!=""
  1077.     if $game_system && $game_system.respond_to?("se_play")
  1078.       $game_system.se_play(param)
  1079.       return
  1080.     elsif (RPG.const_defined?(:SE) rescue false)
  1081.       b=RPG::SE.new(param.name,param.volume,param.pitch)
  1082.       if b && b.respond_to?("play")
  1083.         b.play; return
  1084.       end
  1085.     end
  1086.     Audio.se_play(canonicalize("Audio/SE/"+param.name),param.volume,param.pitch)
  1087.   end
  1088. end
  1089.  
  1090. # Stops SE playback.
  1091. def pbSEFade(x=0.0); pbSEStop(x);end
  1092.  
  1093. # Fades out or stops ME playback. 'x' is the time in seconds to fade out.
  1094. def pbMEFade(x=0.0); pbMEStop(x);end
  1095.  
  1096. # Fades out or stops BGM playback. 'x' is the time in seconds to fade out.
  1097. def pbBGMFade(x=0.0); pbBGMStop(x);end
  1098.  
  1099. # Fades out or stops BGS playback. 'x' is the time in seconds to fade out.
  1100. def pbBGSFade(x=0.0); pbBGSStop(x);end
  1101.  
  1102. # Stops SE playback.
  1103. def pbSEStop(timeInSeconds=0.0)
  1104.   if $game_system
  1105.     $game_system.se_stop
  1106.   elsif (RPG.const_defined?(:SE) rescue false)
  1107.     RPG::SE.stop rescue nil
  1108.   else
  1109.     Audio.se_stop
  1110.   end
  1111. end
  1112.  
  1113. # Fades out or stops ME playback. 'x' is the time in seconds to fade out.
  1114. def pbMEStop(timeInSeconds=0.0)
  1115.   if $game_system && timeInSeconds>0.0 && $game_system.respond_to?("me_fade")
  1116.     $game_system.me_fade(timeInSeconds)
  1117.     return
  1118.   elsif $game_system && $game_system.respond_to?("me_stop")
  1119.     $game_system.me_stop(nil)
  1120.     return
  1121.   elsif (RPG.const_defined?(:ME) rescue false)
  1122.     begin
  1123.       (timeInSeconds>0.0) ? RPG::ME.fade((timeInSeconds*1000).floor) : RPG::ME.stop
  1124.       return
  1125.     rescue
  1126.     end
  1127.   end
  1128.   (timeInSeconds>0.0) ? Audio.me_fade((timeInSeconds*1000).floor) : Audio.me_stop
  1129. end
  1130.  
  1131. # Fades out or stops BGM playback. 'x' is the time in seconds to fade out.
  1132. def pbBGMStop(timeInSeconds=0.0)
  1133.   if $game_system && timeInSeconds>0.0 && $game_system.respond_to?("bgm_fade")
  1134.     $game_system.bgm_fade(timeInSeconds)
  1135.     return
  1136.   elsif $game_system && $game_system.respond_to?("bgm_stop")
  1137.     $game_system.bgm_stop
  1138.     return
  1139.   elsif (RPG.const_defined?(:BGM) rescue false)
  1140.     begin
  1141.       (timeInSeconds>0.0) ? RPG::BGM.fade((timeInSeconds*1000).floor) : RPG::BGM.stop
  1142.       return
  1143.     rescue
  1144.     end
  1145.   end
  1146.   (timeInSeconds>0.0) ? Audio.bgm_fade((timeInSeconds*1000).floor) : Audio.bgm_stop
  1147. end
  1148.  
  1149. # Fades out or stops BGS playback. 'x' is the time in seconds to fade out.
  1150. def pbBGSStop(timeInSeconds=0.0)
  1151.   if $game_system && timeInSeconds>0.0 && $game_system.respond_to?("bgs_fade")
  1152.     $game_system.bgs_fade(timeInSeconds)
  1153.     return
  1154.   elsif $game_system && $game_system.respond_to?("bgs_play")
  1155.     $game_system.bgs_play(nil)
  1156.     return
  1157.   elsif (RPG.const_defined?(:BGS) rescue false)
  1158.     begin
  1159.       (timeInSeconds>0.0) ? RPG::BGS.fade((timeInSeconds*1000).floor) : RPG::BGS.stop
  1160.       return
  1161.     rescue
  1162.     end
  1163.   end
  1164.   (timeInSeconds>0.0) ? Audio.bgs_fade((timeInSeconds*1000).floor) : Audio.bgs_stop
  1165. end
  1166.  
  1167. # Plays a sound effect that plays when a decision is confirmed or a choice is made.
  1168. def pbPlayDecisionSE()
  1169.   if $data_system && $data_system.respond_to?("decision_se") &&
  1170.      $data_system.decision_se && $data_system.decision_se.name!=""
  1171.     pbSEPlay($data_system.decision_se)
  1172.   elsif $data_system && $data_system.respond_to?("sounds") &&
  1173.      $data_system.sounds && $data_system.sounds[1] && $data_system.sounds[1].name!=""
  1174.     pbSEPlay($data_system.sounds[1])
  1175.   elsif FileTest.audio_exist?("Audio/SE/Choose")
  1176.     pbSEPlay("Choose",80)
  1177.   end
  1178. end
  1179.  
  1180. # Plays a sound effect that plays when the player moves the cursor.
  1181. def pbPlayCursorSE()
  1182.   if $data_system && $data_system.respond_to?("cursor_se") &&
  1183.      $data_system.cursor_se && $data_system.cursor_se.name!=""
  1184.     pbSEPlay($data_system.cursor_se)
  1185.   elsif $data_system && $data_system.respond_to?("sounds") &&
  1186.      $data_system.sounds && $data_system.sounds[0] && $data_system.sounds[0].name!=""
  1187.     pbSEPlay($data_system.sounds[0])
  1188.   elsif FileTest.audio_exist?("Audio/SE/Choose")
  1189.     pbSEPlay("Choose",80)
  1190.   end
  1191. end
  1192.  
  1193. # Plays a sound effect that plays when a choice is canceled.
  1194. def pbPlayCancelSE()
  1195.   if $data_system && $data_system.respond_to?("cancel_se") &&
  1196.      $data_system.cancel_se && $data_system.cancel_se.name!=""
  1197.     pbSEPlay($data_system.cancel_se)
  1198.   elsif $data_system && $data_system.respond_to?("sounds") &&
  1199.      $data_system.sounds && $data_system.sounds[2] && $data_system.sounds[2].name!=""
  1200.     pbSEPlay($data_system.sounds[2])
  1201.   elsif FileTest.audio_exist?("Audio/SE/Choose")
  1202.     pbSEPlay("Choose",80)
  1203.   end
  1204. end
  1205.  
  1206. # Plays a buzzer sound effect.
  1207. def pbPlayBuzzerSE()
  1208.   if $data_system && $data_system.respond_to?("buzzer_se") &&
  1209.      $data_system.buzzer_se && $data_system.buzzer_se.name!=""
  1210.     pbSEPlay($data_system.buzzer_se)
  1211.   elsif $data_system && $data_system.respond_to?("sounds") &&
  1212.      $data_system.sounds && $data_system.sounds[3] && $data_system.sounds[3].name!=""
  1213.     pbSEPlay($data_system.sounds[3])
  1214.   elsif FileTest.audio_exist?("Audio/SE/buzzer")
  1215.     pbSEPlay("buzzer",80)
  1216.   end
  1217. end
  1218.  
  1219.  
  1220. #########################
  1221.  
  1222.  
  1223. def pbDrawShadow(bitmap,x,y,width,height,string)
  1224.   return if !bitmap || !string
  1225.   pbDrawShadowText(bitmap,x,y,width,height,string,nil,bitmap.font.color)
  1226. end
  1227.  
  1228. def pbDrawShadowText(bitmap,x,y,width,height,string,baseColor,shadowColor=nil,align=0)
  1229.   return if !bitmap || !string
  1230.   width=(width<0) ? bitmap.text_size(string).width+4 : width
  1231.   height=(height<0) ? bitmap.text_size(string).height+4 : height
  1232.   if shadowColor
  1233.     bitmap.font.color=shadowColor
  1234.     bitmap.draw_text(x+2,y,width,height,string,align)
  1235.     bitmap.draw_text(x,y+2,width,height,string,align)
  1236.     bitmap.draw_text(x+2,y+2,width,height,string,align)
  1237.   end
  1238.   if baseColor
  1239.     bitmap.font.color=baseColor
  1240.     bitmap.draw_text(x,y,width,height,string,align)
  1241.   end
  1242. end
  1243.  
  1244. def pbDrawOutlineText(bitmap,x,y,width,height,string,baseColor,shadowColor=nil,align=0)
  1245.   return if !bitmap || !string
  1246.   width=(width<0) ? bitmap.text_size(string).width+4 : width
  1247.   height=(height<0) ? bitmap.text_size(string).height+4 : height
  1248.   if shadowColor
  1249.     bitmap.font.color=shadowColor
  1250.     bitmap.draw_text(x-2,y-2,width,height,string,align)
  1251.     bitmap.draw_text(x,y-2,width,height,string,align)
  1252.     bitmap.draw_text(x+2,y-2,width,height,string,align)
  1253.     bitmap.draw_text(x-2,y,width,height,string,align)
  1254.     bitmap.draw_text(x+2,y,width,height,string,align)
  1255.     bitmap.draw_text(x-2,y+2,width,height,string,align)
  1256.     bitmap.draw_text(x,y+2,width,height,string,align)
  1257.     bitmap.draw_text(x+2,y+2,width,height,string,align)
  1258.   end
  1259.   if baseColor
  1260.     bitmap.font.color=baseColor
  1261.     bitmap.draw_text(x,y,width,height,string,align)
  1262.   end
  1263. end
  1264.  
  1265. def pbCopyBitmap(dstbm,srcbm,x,y,opacity=255)
  1266.   rc=Rect.new(0,0,srcbm.width,srcbm.height)
  1267.   dstbm.blt(x,y,srcbm,rc,opacity)
  1268. end
  1269.  
  1270. def pbCopyBitmapPokemonIcon(dstbm,srcbm,x,y,opacity=255)
  1271.     rc=Rect.new(0,0,srcbm.width/2,srcbm.height)
  1272.     dstbm.blt(x,y,srcbm,rc,opacity)
  1273. end
  1274.  
  1275. def using(window)
  1276.   begin
  1277.     yield if block_given?
  1278.   ensure
  1279.     window.dispose
  1280.   end
  1281. end
  1282.  
  1283. def pbBottomRight(window)
  1284.   window.x=Graphics.width-window.width
  1285.   window.y=Graphics.height-window.height
  1286. end
  1287.  
  1288. def pbBottomLeft(window)
  1289.   window.x=0
  1290.   window.y=Graphics.height-window.height
  1291. end
  1292.  
  1293. def pbBottomLeftLines(window,lines,width=nil)
  1294.   window.x=0
  1295.   window.width=width ? width : Graphics.width
  1296.   window.height=(window.borderY rescue 32)+lines*32
  1297.   window.y=Graphics.height-window.height
  1298. end
  1299.  
  1300. def pbDisposed?(x)
  1301.   return true if !x
  1302.   if x.is_a?(Viewport)
  1303.     begin
  1304.       x.rect=x.rect
  1305.     rescue
  1306.       return true
  1307.     end
  1308.     return false
  1309.   else
  1310.     return x.disposed?
  1311.   end
  1312. end
  1313.  
  1314. def isDarkBackground(background,rect=nil)
  1315.   if !background || background.disposed?
  1316.     return true
  1317.   end
  1318.   rect=background.rect if !rect
  1319.   if rect.width<=0 || rect.height<=0
  1320.     return true
  1321.   end
  1322.   xSeg=(rect.width/16)
  1323.   xLoop=(xSeg==0) ? 1 : 16
  1324.   xStart=(xSeg==0) ? rect.x+(rect.width/2) : rect.x+xSeg/2
  1325.   ySeg=(rect.height/16)
  1326.   yLoop=(ySeg==0) ? 1 : 16
  1327.   yStart=(ySeg==0) ? rect.y+(rect.height/2) : rect.y+ySeg/2
  1328.   count=0
  1329.   y=yStart
  1330.   r=0; g=0; b=0
  1331.   yLoop.times {
  1332.      x=xStart
  1333.      xLoop.times {
  1334.         clr=background.get_pixel(x,y)
  1335.         if clr.alpha!=0
  1336.           r+=clr.red; g+=clr.green; b+=clr.blue
  1337.           count+=1
  1338.         end
  1339.         x+=xSeg
  1340.      }
  1341.      y+=ySeg
  1342.   }
  1343.   return true if count==0
  1344.   r/=count
  1345.   g/=count
  1346.   b/=count
  1347.   return (r*0.299+g*0.587+b*0.114)<128
  1348. end
  1349.  
  1350. def isDarkWindowskin(windowskin)
  1351.   if !windowskin || windowskin.disposed?
  1352.     return true
  1353.   end
  1354.   if windowskin.width==192 && windowskin.height==128
  1355.     return isDarkBackground(windowskin,Rect.new(0,0,128,128))
  1356.   elsif windowskin.width==128 && windowskin.height==128
  1357.     return isDarkBackground(windowskin,Rect.new(0,0,64,64))
  1358.   else
  1359.     clr=windowskin.get_pixel(windowskin.width/2, windowskin.height/2)
  1360.     return (clr.red*0.299+clr.green*0.587+clr.blue*0.114)<128
  1361.   end
  1362. end
  1363.  
  1364. def getDefaultTextColors(windowskin)
  1365.   if !windowskin || windowskin.disposed? ||
  1366.      windowskin.width!=128 || windowskin.height!=128
  1367.     if isDarkWindowskin(windowskin)
  1368.       return [MessageConfig::LIGHTTEXTBASE,MessageConfig::LIGHTTEXTSHADOW] # White
  1369.     else
  1370.       return [MessageConfig::DARKTEXTBASE,MessageConfig::DARKTEXTSHADOW] # Dark gray
  1371.     end
  1372.   else # VX windowskin
  1373.     color=windowskin.get_pixel(64, 96)
  1374.     shadow=nil
  1375.     isdark=(color.red+color.green+color.blue)/3 < 128
  1376.     if isdark
  1377.       shadow=Color.new(color.red+64,color.green+64,color.blue+64)
  1378.     else
  1379.       shadow=Color.new(color.red-64,color.green-64,color.blue-64)
  1380.     end
  1381.     return [color,shadow]
  1382.   end
  1383. end
  1384.  
  1385. def pbDoEnsureBitmap(bitmap,dwidth,dheight)
  1386.   if !bitmap || bitmap.disposed? || bitmap.width<dwidth || bitmap.height<dheight
  1387.     oldfont=(bitmap && !bitmap.disposed?) ? bitmap.font : nil
  1388.     bitmap.dispose if bitmap
  1389.     bitmap=Bitmap.new([1,dwidth].max,[1,dheight].max)
  1390.     if !oldfont
  1391.       pbSetSystemFont(bitmap)
  1392.     else
  1393.       bitmap.font=oldfont
  1394.     end
  1395.     if bitmap.font && bitmap.font.respond_to?("shadow")
  1396.       bitmap.font.shadow=false
  1397.     end
  1398.   end
  1399.   return bitmap
  1400. end
  1401.  
  1402. def pbUpdateSpriteHash(windows)
  1403.   for i in windows
  1404.     window=i[1]
  1405.     if window
  1406.       if window.is_a?(Sprite) || window.is_a?(Window)
  1407.         window.update if !pbDisposed?(window)
  1408.       elsif window.is_a?(Plane)
  1409.         begin
  1410.           window.update if !window.disposed?
  1411.         rescue NoMethodError
  1412.         end
  1413.       elsif window.respond_to?("update")
  1414.         begin
  1415.           window.update
  1416.         rescue RGSSError
  1417.         end
  1418.       end
  1419.     end
  1420.   end
  1421. end
  1422.  
  1423. # Disposes all objects in the specified hash.
  1424. def pbDisposeSpriteHash(sprites)
  1425.   if sprites
  1426.     for i in sprites.keys
  1427.       pbDisposeSprite(sprites,i)
  1428.     end
  1429.     sprites.clear
  1430.   end
  1431. end
  1432.  
  1433. # Disposes the specified graphics object within the specified hash. Basically like:
  1434. #   sprites[id].dispose
  1435. def pbDisposeSprite(sprites,id)
  1436.   sprite=sprites[id]
  1437.   if sprite && !pbDisposed?(sprite)
  1438.     sprite.dispose
  1439.   end
  1440.   sprites[id]=nil
  1441. end
  1442.  
  1443. # Draws text on a bitmap. _textpos_ is an array
  1444. # of text commands. Each text command is an array
  1445. # that contains the following:
  1446. #  0 - Text to draw
  1447. #  1 - X coordinate
  1448. #  2 - Y coordinate
  1449. #  3 - If true or 1, the text is right aligned. If 2, the text is centered.
  1450. #      Otherwise, the text is left aligned.
  1451. #  4 - Base color
  1452. #  5 - Shadow color
  1453. def pbDrawTextPositions(bitmap,textpos)
  1454.   for i in textpos
  1455.     textsize=bitmap.text_size(i[0])
  1456.     x=i[1]
  1457.     y=i[2]
  1458.     if i[3]==true || i[3]==1 # right align
  1459.       x-=textsize.width
  1460.     elsif i[3]==2 # centered
  1461.       x-=(textsize.width/2)
  1462.     end
  1463.     if i[6]==true || i[6]==1 # outline text
  1464.       pbDrawOutlineText(bitmap,x,y,textsize.width,textsize.height,i[0],i[4],i[5])
  1465.     else
  1466.       pbDrawShadowText(bitmap,x,y,textsize.width,textsize.height,i[0],i[4],i[5])
  1467.     end
  1468.   end
  1469. end
  1470.  
  1471. def pbDrawImagePositions(bitmap,textpos)
  1472.   for i in textpos
  1473.     srcbitmap=AnimatedBitmap.new(pbBitmapName(i[0]))
  1474.     x=i[1]
  1475.     y=i[2]
  1476.     srcx=i[3]
  1477.     srcy=i[4]
  1478.     width=i[5]>=0 ? i[5] : srcbitmap.width
  1479.     height=i[6]>=0 ? i[6] : srcbitmap.height
  1480.     srcrect=Rect.new(srcx,srcy,width,height)
  1481.     bitmap.blt(x,y,srcbitmap.bitmap,srcrect)
  1482.     srcbitmap.dispose
  1483.   end
  1484. end
  1485.  
  1486.  
  1487.  
  1488. class Game_Temp
  1489.   attr_accessor :fadestate
  1490.  
  1491.   def fadestate
  1492.     return @fadestate ? @fadestate : 0
  1493.   end
  1494. end
  1495.  
  1496.  
  1497.  
  1498. def pbPushFade
  1499.   if $game_temp
  1500.     $game_temp.fadestate=[$game_temp.fadestate+1,0].max
  1501.   end
  1502. end
  1503.  
  1504. def pbPopFade
  1505.   if $game_temp
  1506.     $game_temp.fadestate=[$game_temp.fadestate-1,0].max
  1507.   end
  1508. end
  1509.  
  1510. def pbIsFaded?
  1511.   if $game_temp
  1512.     return $game_temp.fadestate>0
  1513.   else
  1514.     return false
  1515.   end
  1516. end
  1517.  
  1518. # pbFadeOutIn(z) { block }
  1519. # Fades out the screen before a block is run and fades it back in after the
  1520. # block exits.  z indicates the z-coordinate of the viewport used for this effect
  1521. def pbFadeOutIn(z)
  1522.   col=Color.new(0,0,0,0)
  1523.   viewport=Viewport.new(0,0,Graphics.width,Graphics.height)
  1524.   viewport.z=z
  1525.   for j in 0..17
  1526.     col.set(0,0,0,j*15)
  1527.     viewport.color=col
  1528.     Graphics.update
  1529.     Input.update
  1530.   end
  1531.   pbPushFade
  1532.   begin
  1533.     yield if block_given?
  1534.   ensure
  1535.     pbPopFade
  1536.     for j in 0..17
  1537.       col.set(0,0,0,(17-j)*15)
  1538.       viewport.color=col
  1539.       Graphics.update
  1540.       Input.update
  1541.     end
  1542.     viewport.dispose
  1543.   end
  1544. end
  1545.  
  1546. def pbFadeOutAndHide(sprites)
  1547.   visiblesprites={}
  1548.   pbDeactivateWindows(sprites){
  1549.      for j in 0..17
  1550.        pbSetSpritesToColor(sprites,Color.new(0,0,0,j*15))
  1551.        block_given? ? yield : pbUpdateSpriteHash(sprites)
  1552.      end
  1553.   }
  1554.   for i in sprites
  1555.     next if !i[1]
  1556.     next if pbDisposed?(i[1])
  1557.     visiblesprites[i[0]]=true if i[1].visible
  1558.     i[1].visible=false
  1559.   end
  1560.   return visiblesprites
  1561. end
  1562.  
  1563. def pbFadeInAndShow(sprites,visiblesprites=nil)
  1564.   if visiblesprites
  1565.     for i in visiblesprites
  1566.       if i[1] && sprites[i[0]] && !pbDisposed?(sprites[i[0]])
  1567.         sprites[i[0]].visible=true
  1568.       end
  1569.     end
  1570.   end
  1571.   pbDeactivateWindows(sprites){
  1572.      for j in 0..17
  1573.        pbSetSpritesToColor(sprites,Color.new(0,0,0,((17-j)*15)))
  1574.        block_given? ? yield : pbUpdateSpriteHash(sprites)
  1575.      end
  1576.   }
  1577. end
  1578.  
  1579. # Restores which windows are active for the given sprite hash.
  1580. # _activeStatuses_ is the result of a previous call to pbActivateWindows
  1581. def pbRestoreActivations(sprites,activeStatuses)
  1582.   return if !sprites || !activeStatuses
  1583.   for k in activeStatuses.keys
  1584.     if sprites[k] && sprites[k].is_a?(Window) && !pbDisposed?(sprites[k])
  1585.       sprites[k].active=activeStatuses[k] ? true : false
  1586.     end
  1587.   end
  1588. end
  1589.  
  1590. # Deactivates all windows. If a code block is given, deactivates all windows,
  1591. # runs the code in the block, and reactivates them.
  1592. def pbDeactivateWindows(sprites)
  1593.   if block_given?
  1594.     pbActivateWindow(sprites,nil) { yield }
  1595.   else
  1596.     pbActivateWindow(sprites,nil)
  1597.   end
  1598. end
  1599.  
  1600. # Activates a specific window of a sprite hash. _key_ is the key of the window
  1601. # in the sprite hash. If a code block is given, deactivates all windows except
  1602. # the specified window, runs the code in the block, and reactivates them.
  1603. def pbActivateWindow(sprites,key)
  1604.   return if !sprites
  1605.   activeStatuses={}
  1606.   for i in sprites
  1607.     if i[1] && i[1].is_a?(Window) && !pbDisposed?(i[1])
  1608.       activeStatuses[i[0]]=i[1].active
  1609.       i[1].active=(i[0]==key)
  1610.     end
  1611.   end
  1612.   if block_given?
  1613.     begin
  1614.       yield
  1615.     ensure
  1616.       pbRestoreActivations(sprites,activeStatuses)
  1617.     end
  1618.     return {}
  1619.   else
  1620.     return activeStatuses
  1621.   end
  1622. end
  1623.  
  1624. def pbAlphaBlend(dstColor,srcColor)
  1625.   r=(255*(srcColor.red-dstColor.red)/255)+dstColor.red
  1626.   g=(255*(srcColor.green-dstColor.green)/255)+dstColor.green
  1627.   b=(255*(srcColor.blue-dstColor.blue)/255)+dstColor.blue
  1628.   a=(255*(srcColor.alpha-dstColor.alpha)/255)+dstColor.alpha
  1629.   return Color.new(r,g,b,a)
  1630. end
  1631.  
  1632. def pbSrcOver(dstColor,srcColor)
  1633.   er=srcColor.red*srcColor.alpha/255
  1634.   eg=srcColor.green*srcColor.alpha/255
  1635.   eb=srcColor.blue*srcColor.alpha/255
  1636.   iea=255-srcColor.alpha
  1637.   cr=dstColor.red*dstColor.alpha/255
  1638.   cg=dstColor.green*dstColor.alpha/255
  1639.   cb=dstColor.blue*dstColor.alpha/255
  1640.   ica=255-dstColor.alpha
  1641.   a=255-(iea*ica)/255
  1642.   r=(iea*cr)/255+er
  1643.   g=(iea*cg)/255+eg
  1644.   b=(iea*cb)/255+eb
  1645.   r=(a==0) ? 0 : r*255/a
  1646.   g=(a==0) ? 0 : g*255/a
  1647.   b=(a==0) ? 0 : b*255/a
  1648.   return Color.new(r,g,b,a)
  1649. end
  1650.  
  1651. def pbSetSpritesToColor(sprites,color)
  1652.   return if !sprites||!color
  1653.   colors={}
  1654.   for i in sprites
  1655.     next if !i[1] || pbDisposed?(i[1])
  1656.     colors[i[0]]=i[1].color.clone
  1657.     i[1].color=pbSrcOver(i[1].color,color)
  1658.   end
  1659.   Graphics.update
  1660.   Input.update
  1661.   for i in colors
  1662.     next if !sprites[i[0]]
  1663.     sprites[i[0]].color=i[1]
  1664.   end
  1665. end
  1666.  
  1667. def pbTryString(x)
  1668.   ret=pbGetFileChar(x)
  1669.   return (ret!=nil && ret!="") ? x : nil
  1670. end
  1671.  
  1672. # Finds the real path for an image file.  This includes paths in encrypted
  1673. # archives.  Returns _x_ if the path can't be found.
  1674. def pbBitmapName(x)
  1675.   ret=pbResolveBitmap(x)
  1676.   return ret ? ret : x
  1677. end
  1678.  
  1679. # Finds the real path for an image file.  This includes paths in encrypted
  1680. # archives.  Returns nil if the path can't be found.
  1681. def pbResolveBitmap(x)
  1682.   return nil if !x
  1683.   noext=x.gsub(/\.(bmp|png|gif|jpg|jpeg)$/,"")
  1684.   filename=nil
  1685. #  RTP.eachPathFor(x) {|path|
  1686. #     filename=pbTryString(path) if !filename
  1687. #     filename=pbTryString(path+".gif") if !filename
  1688. #  }
  1689.   RTP.eachPathFor(noext) {|path|
  1690.      filename=pbTryString(path+".png") if !filename
  1691.      filename=pbTryString(path+".gif") if !filename
  1692. #     filename=pbTryString(path+".jpg") if !filename
  1693. #     filename=pbTryString(path+".jpeg") if !filename
  1694. #     filename=pbTryString(path+".bmp") if !filename
  1695.   }
  1696.   return filename
  1697. end
  1698.  
  1699. # Adds a background to the sprite hash.
  1700. # _planename_ is the hash key of the background.
  1701. # _background_ is a filename within the Graphics/Pictures/ folder and can be
  1702. #     an animated image.
  1703. # _viewport_ is a viewport to place the background in.
  1704. def addBackgroundPlane(sprites,planename,background,viewport=nil)
  1705.   sprites[planename]=AnimatedPlane.new(viewport)
  1706.   bitmapName=pbResolveBitmap("Graphics/Pictures/#{background}")
  1707.   if bitmapName==nil
  1708.     # Plane should exist in any case
  1709.     sprites[planename].bitmap=nil
  1710.     sprites[planename].visible=false
  1711.   else
  1712.     sprites[planename].setBitmap(bitmapName)
  1713.     for spr in sprites.values
  1714.       if spr.is_a?(Window)
  1715.         spr.windowskin=nil
  1716.       end
  1717.     end
  1718.   end
  1719. end
  1720.  
  1721. # Adds a background to the sprite hash.
  1722. # _planename_ is the hash key of the background.
  1723. # _background_ is a filename within the Graphics/Pictures/ folder and can be
  1724. #       an animated image.
  1725. # _color_ is the color to use if the background can't be found.
  1726. # _viewport_ is a viewport to place the background in.
  1727. def addBackgroundOrColoredPlane(sprites,planename,background,color,viewport=nil)
  1728.   bitmapName=pbResolveBitmap("Graphics/Pictures/#{background}")
  1729.   if bitmapName==nil
  1730.     # Plane should exist in any case
  1731.     sprites[planename]=ColoredPlane.new(color,@viewport)
  1732.   else
  1733.     sprites[planename]=AnimatedPlane.new(viewport)
  1734.     sprites[planename].setBitmap(bitmapName)
  1735.     for spr in sprites.values
  1736.       if spr.is_a?(Window)
  1737.         spr.windowskin=nil
  1738.       end
  1739.     end
  1740.   end
  1741. end
  1742.  
  1743. # Sets a bitmap's font to the system font.
  1744. def pbSetSystemFont(bitmap)
  1745.   fontname=MessageConfig.pbGetSystemFontName()
  1746.   bitmap.font.name=fontname
  1747.   if fontname=="Pokemon FireLeaf" || fontname=="Power Red and Green"
  1748.     bitmap.font.size=29
  1749.   elsif fontname=="Pokemon Emerald Small" || fontname=="Power Green Small"
  1750.     bitmap.font.size=25
  1751.   else
  1752.     bitmap.font.size=31
  1753.   end
  1754. end
  1755.  
  1756. # Gets the name of the system small font.
  1757. def pbSmallFontName()
  1758.   return MessageConfig.pbTryFonts("Power Green Small","Pokemon Emerald Small",
  1759.      "Arial Narrow","Arial")
  1760. end
  1761.  
  1762. # Gets the name of the system narrow font.
  1763. def pbNarrowFontName()
  1764.   return MessageConfig.pbTryFonts("Power Green Narrow","Pokemon Emerald Narrow",
  1765.      "Arial Narrow","Arial")
  1766. end
  1767.  
  1768. # Sets a bitmap's font to the system small font.
  1769. def pbSetSmallFont(bitmap)
  1770.   bitmap.font.name=pbSmallFontName()
  1771.   bitmap.font.size=25
  1772. end
  1773.  
  1774. # Sets a bitmap's font to the system narrow font.
  1775. def pbSetNarrowFont(bitmap)
  1776.   bitmap.font.name=pbNarrowFontName()
  1777.   bitmap.font.size=31
  1778. end
  1779.  
  1780.  
  1781.  
  1782. ################################################################################
  1783. # SpriteWrapper is a class based on Sprite which wraps Sprite's properties.
  1784. ################################################################################
  1785. class SpriteWrapper < Sprite
  1786.   def initialize(viewport=nil)
  1787.     @sprite=Sprite.new(viewport)
  1788.   end
  1789.  
  1790.   def dispose
  1791.     @sprite.dispose
  1792.   end
  1793.  
  1794.   def disposed?
  1795.     return @sprite.disposed?
  1796.   end
  1797.  
  1798.   def viewport
  1799.     return @sprite.viewport
  1800.   end
  1801.  
  1802.   def flash(color,duration)
  1803.     return @sprite.flash(color,duration)
  1804.   end
  1805.  
  1806.   def update
  1807.     return @sprite.update
  1808.   end
  1809.  
  1810.   def x
  1811.     @sprite.x
  1812.   end
  1813.  
  1814.   def x=(value)
  1815.     @sprite.x=value
  1816.   end
  1817.  
  1818.   def y
  1819.     @sprite.y
  1820.   end
  1821.  
  1822.   def y=(value)
  1823.     @sprite.y=value
  1824.   end
  1825.  
  1826.   def bitmap
  1827.     @sprite.bitmap
  1828.   end
  1829.  
  1830.   def bitmap=(value)
  1831.     @sprite.bitmap=value
  1832.   end
  1833.  
  1834.   def src_rect
  1835.     @sprite.src_rect
  1836.   end
  1837.  
  1838.   def src_rect=(value)
  1839.     @sprite.src_rect=value
  1840.   end
  1841.  
  1842.   def visible
  1843.     @sprite.visible
  1844.   end
  1845.  
  1846.   def visible=(value)
  1847.     @sprite.visible=value
  1848.   end
  1849.  
  1850.   def z
  1851.     @sprite.z
  1852.   end
  1853.  
  1854.   def z=(value)
  1855.     @sprite.z=value
  1856.   end
  1857.  
  1858.   def ox
  1859.     @sprite.ox
  1860.   end
  1861.  
  1862.   def ox=(value)
  1863.     @sprite.ox=value
  1864.   end
  1865.  
  1866.   def oy
  1867.     @sprite.oy
  1868.   end
  1869.  
  1870.   def oy=(value)
  1871.     @sprite.oy=value
  1872.   end
  1873.  
  1874.   def zoom_x
  1875.     @sprite.zoom_x
  1876.   end
  1877.  
  1878.   def zoom_x=(value)
  1879.     @sprite.zoom_x=value
  1880.   end
  1881.  
  1882.   def zoom_y
  1883.     @sprite.zoom_y
  1884.   end
  1885.  
  1886.   def zoom_y=(value)
  1887.     @sprite.zoom_y=value
  1888.   end
  1889.  
  1890.   def angle
  1891.     @sprite.angle
  1892.   end
  1893.  
  1894.   def angle=(value)
  1895.     @sprite.angle=value
  1896.   end
  1897.  
  1898.   def mirror
  1899.     @sprite.mirror
  1900.   end
  1901.  
  1902.   def mirror=(value)
  1903.     @sprite.mirror=value
  1904.   end
  1905.  
  1906.   def bush_depth
  1907.     @sprite.bush_depth
  1908.   end
  1909.  
  1910.   def bush_depth=(value)
  1911.     @sprite.bush_depth=value
  1912.   end
  1913.  
  1914.   def opacity
  1915.     @sprite.opacity
  1916.   end
  1917.  
  1918.   def opacity=(value)
  1919.     @sprite.opacity=value
  1920.   end
  1921.  
  1922.   def blend_type
  1923.     @sprite.blend_type
  1924.   end
  1925.  
  1926.   def blend_type=(value)
  1927.     @sprite.blend_type=value
  1928.   end
  1929.  
  1930.   def color
  1931.     @sprite.color
  1932.   end
  1933.  
  1934.   def color=(value)
  1935.     @sprite.color=value
  1936.   end
  1937.  
  1938.   def tone
  1939.     @sprite.tone
  1940.   end
  1941.  
  1942.   def tone=(value)
  1943.     @sprite.tone=value
  1944.   end
  1945.  
  1946.   def viewport=(value)
  1947.     return if self.viewport==value
  1948.     bitmap=@sprite.bitmap
  1949.     src_rect=@sprite.src_rect
  1950.     visible=@sprite.visible
  1951.     x=@sprite.x
  1952.     y=@sprite.y
  1953.     z=@sprite.z
  1954.     ox=@sprite.ox
  1955.     oy=@sprite.oy
  1956.     zoom_x=@sprite.zoom_x
  1957.     zoom_y=@sprite.zoom_y
  1958.     angle=@sprite.angle
  1959.     mirror=@sprite.mirror
  1960.     bush_depth=@sprite.bush_depth
  1961.     opacity=@sprite.opacity
  1962.     blend_type=@sprite.blend_type
  1963.     color=@sprite.color
  1964.     tone=@sprite.tone
  1965.     @sprite.dispose
  1966.     @sprite=Sprite.new(value)
  1967.     @sprite.bitmap=bitmap
  1968.     @sprite.src_rect=src_rect
  1969.     @sprite.visible=visible
  1970.     @sprite.x=x
  1971.     @sprite.y=y
  1972.     @sprite.z=z
  1973.     @sprite.ox=ox
  1974.     @sprite.oy=oy
  1975.     @sprite.zoom_x=zoom_x
  1976.     @sprite.zoom_y=zoom_y
  1977.     @sprite.angle=angle
  1978.     @sprite.mirror=mirror
  1979.     @sprite.bush_depth=bush_depth
  1980.     @sprite.opacity=opacity
  1981.     @sprite.blend_type=blend_type
  1982.     @sprite.color=color
  1983.     @sprite.tone=tone
  1984.   end
  1985. end
  1986.  
  1987.  
  1988. #########################################################################
  1989.  
  1990.  
  1991. class StringInput
  1992.   include Enumerable
  1993.  
  1994.   class << self
  1995.     def new( str )
  1996.       if block_given?
  1997.         begin
  1998.           f = super
  1999.           yield f
  2000.         ensure
  2001.           f.close if f
  2002.         end
  2003.       else
  2004.         super
  2005.       end
  2006.     end
  2007.     alias open new
  2008.   end
  2009.  
  2010.   def initialize( str )
  2011.     @string = str
  2012.     @pos = 0
  2013.     @closed = false
  2014.     @lineno = 0
  2015.   end
  2016.  
  2017.   attr_reader :lineno,:string
  2018.  
  2019.   def inspect
  2020.     return "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@string[0,30].inspect}>"
  2021.   end
  2022.  
  2023.   def close
  2024.     raise IOError, 'closed stream' if @closed
  2025.     @pos=nil; @closed=true
  2026.   end
  2027.  
  2028.   def closed?; @closed; end
  2029.  
  2030.   def pos
  2031.     raise IOError, 'closed stream' if @closed
  2032.     [@pos, @string.size].min
  2033.   end
  2034.  
  2035.   alias tell pos
  2036.  
  2037.   def rewind; seek(0); end
  2038.  
  2039.   def pos=(value); seek(value); end
  2040.  
  2041.   def seek( offset, whence=IO::SEEK_SET )
  2042.     raise IOError, 'closed stream' if @closed
  2043.     case whence
  2044.     when IO::SEEK_SET
  2045.       @pos=offset
  2046.     when IO::SEEK_CUR
  2047.       @pos+=offset
  2048.     when IO::SEEK_END
  2049.       @pos=@string.size - offset
  2050.     else
  2051.       raise ArgumentError, "unknown seek flag: #{whence}"
  2052.     end
  2053.     @pos = 0 if @pos < 0
  2054.     @pos = [@pos, @string.size + 1].min
  2055.     offset
  2056.   end
  2057.  
  2058.   def eof?
  2059.     raise IOError, 'closed stream' if @closed
  2060.     @pos > @string.size
  2061.   end
  2062.  
  2063.   def each( &block )
  2064.     raise IOError, 'closed stream' if @closed
  2065.     begin
  2066.       @string.each(&block)
  2067.     ensure
  2068.       @pos = 0
  2069.     end
  2070.   end
  2071.  
  2072.   def gets
  2073.     raise IOError, 'closed stream' if @closed
  2074.     if idx = @string.index(?\n, @pos)
  2075.       idx += 1  # "\n".size
  2076.       line = @string[ @pos ... idx ]
  2077.       @pos = idx
  2078.       @pos += 1 if @pos == @string.size
  2079.     else
  2080.       line = @string[ @pos .. -1 ]
  2081.       @pos = @string.size + 1
  2082.     end
  2083.     @lineno += 1
  2084.     line
  2085.   end
  2086.  
  2087.   def getc
  2088.     raise IOError, 'closed stream' if @closed
  2089.     ch = @string[@pos]
  2090.     @pos += 1
  2091.     @pos += 1 if @pos == @string.size
  2092.     ch
  2093.   end
  2094.  
  2095.   def read( len = nil )
  2096.     raise IOError, 'closed stream' if @closed
  2097.     if !len
  2098.       return nil if eof?
  2099.       rest = @string[@pos ... @string.size]
  2100.       @pos = @string.size + 1
  2101.       return rest
  2102.     end
  2103.     str = @string[@pos, len]
  2104.     @pos += len
  2105.     @pos += 1 if @pos == @string.size
  2106.     str
  2107.   end
  2108.  
  2109.   def read_all; read(); end
  2110.  
  2111.   alias sysread read
  2112. end
  2113.  
  2114.  
  2115.  
  2116. module ::Marshal
  2117.   class << self
  2118.     if !@oldloadAliased
  2119.       alias oldload load
  2120.       @oldloadAliased=true
  2121.     end
  2122.  
  2123.     def neverload
  2124.       return @@neverload
  2125.     end
  2126.  
  2127.     @@neverload=false
  2128.  
  2129.     def neverload=(value)
  2130.       @@neverload=value
  2131.     end
  2132.  
  2133.     def load(port,*arg)
  2134.       if @@neverload
  2135.         if port.is_a?(IO)
  2136.           return port.read
  2137.         else
  2138.           return port
  2139.         end
  2140.       end
  2141.       oldpos=port.pos if port.is_a?(IO)
  2142.       begin
  2143.         oldload(port,*arg)
  2144.       rescue
  2145.         p [$!.class,$!.message,$!.backtrace]
  2146.         if port.is_a?(IO)
  2147.           port.pos=oldpos
  2148.           return port.read
  2149.         else
  2150.           return port
  2151.         end
  2152.       end
  2153.     end
  2154.   end
  2155. end
  2156.  
  2157.  
  2158.  
  2159. # Used to determine whether a data file exists (rather than a graphics or
  2160. # audio file). Doesn't check RTP, but does check encrypted archives.
  2161. def pbRgssExists?(filename)
  2162.   filename=canonicalize(filename)
  2163.   if (safeExists?("./Game.rgssad") || safeExists?("./Game.rgss2a"))
  2164.     return pbGetFileChar(filename)!=nil
  2165.   else
  2166.     return safeExists?(filename)
  2167.   end
  2168. end
  2169.  
  2170. # Opens an IO, even if the file is in an encrypted archive.
  2171. # Doesn't check RTP for the file.
  2172. def pbRgssOpen(file,mode=nil)
  2173.   #File.open("debug.txt","ab"){|fw| fw.write([file,mode,Time.now.to_f].inspect+"\r\n") }
  2174.   if !safeExists?("./Game.rgssad") && !safeExists?("./Game.rgss2a")
  2175.     if block_given?
  2176.       File.open(file,mode){|f| yield f }
  2177.       return nil
  2178.     else
  2179.       return File.open(file,mode)
  2180.     end
  2181.   end
  2182.   file=canonicalize(file)
  2183.   Marshal.neverload=true
  2184.   begin
  2185.     str=load_data(file)
  2186.   ensure
  2187.     Marshal.neverload=false
  2188.   end
  2189.   if block_given?
  2190.     StringInput.open(str){|f| yield f }
  2191.     return nil
  2192.   else
  2193.     return StringInput.open(str)
  2194.   end
  2195. end
  2196.  
  2197. # Gets at least the first byte of a file. Doesn't check RTP, but does check
  2198. # encrypted archives.
  2199. def pbGetFileChar(file)
  2200.   file=canonicalize(file)
  2201.   if !(safeExists?("./Game.rgssad") || safeExists?("./Game.rgss2a"))
  2202.     return nil if !safeExists?(file)
  2203.     begin
  2204.       File.open(file,"rb"){|f|
  2205.          return f.read(1) # read one byte
  2206.       }
  2207.     rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
  2208.       return nil
  2209.     end
  2210.   end
  2211.   Marshal.neverload=true
  2212.   str=nil
  2213.   begin
  2214.     str=load_data(file)
  2215.   rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, RGSSError
  2216.     str=nil
  2217.   ensure
  2218.     Marshal.neverload=false
  2219.   end
  2220.   return str
  2221. end
  2222.  
  2223. # Gets the contents of a file. Doesn't check RTP, but does check
  2224. # encrypted archives.
  2225. def pbGetFileString(file)
  2226.   file=canonicalize(file)
  2227.   if !(safeExists?("./Game.rgssad") || safeExists?("./Game.rgss2a"))
  2228.     return nil if !safeExists?(file)
  2229.     begin
  2230.       File.open(file,"rb"){|f|
  2231.          return f.read # read all data
  2232.       }
  2233.     rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
  2234.       return nil
  2235.     end
  2236.   end
  2237.   Marshal.neverload=true
  2238.   str=nil
  2239.   begin
  2240.     str=load_data(file)
  2241.   rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, RGSSError
  2242.     str=nil
  2243.   ensure
  2244.     Marshal.neverload=false
  2245.   end
  2246.   return str
  2247. end
  2248.  
  2249.  
  2250.  
  2251. #===============================================================================
  2252. # SpriteWindow is a class based on Window which emulates Window's functionality.
  2253. # This class is necessary in order to change the viewport of windows (with
  2254. # viewport=) and to make windows fade in and out (with tone=).
  2255. #===============================================================================
  2256. class SpriteWindowCursorRect < Rect
  2257.   def initialize(window)
  2258.     @window=window
  2259.     @x=0
  2260.     @y=0
  2261.     @width=0
  2262.     @height=0
  2263.   end
  2264.  
  2265.   attr_reader :x,:y,:width,:height
  2266.  
  2267.   def empty
  2268.     needupdate=@x!=0 || @y!=0 || @width!=0 || @height!=0
  2269.     if needupdate
  2270.       @x=0
  2271.       @y=0
  2272.       @width=0
  2273.       @height=0
  2274.       @window.width=@window.width
  2275.     end
  2276.   end
  2277.  
  2278.   def isEmpty?
  2279.     return @x==0 && @y==0 && @width==0 && @height==0
  2280.   end
  2281.  
  2282.   def set(x,y,width,height)
  2283.     needupdate=@x!=x || @y!=y || @width!=width || @height!=height
  2284.     if needupdate
  2285.       @x=x
  2286.       @y=y
  2287.       @width=width
  2288.       @height=height
  2289.       @window.width=@window.width
  2290.     end
  2291.   end
  2292.  
  2293.   def height=(value)
  2294.     @height=value; @window.width=@window.width
  2295.   end
  2296.  
  2297.   def width=(value)
  2298.     @width=value; @window.width=@window.width
  2299.   end
  2300.  
  2301.   def x=(value)
  2302.     @x=value; @window.width=@window.width
  2303.   end
  2304.  
  2305.   def y=(value)
  2306.     @y=value; @window.width=@window.width
  2307.   end
  2308. end
  2309.  
  2310.  
  2311.  
  2312. class SpriteWindow < Window
  2313.   attr_reader :tone
  2314.   attr_reader :color
  2315.   attr_reader :viewport
  2316.   attr_reader :contents
  2317.   attr_reader :ox
  2318.   attr_reader :oy
  2319.   attr_reader :x
  2320.   attr_reader :y
  2321.   attr_reader :z
  2322.   attr_reader :zoom_x
  2323.   attr_reader :zoom_y
  2324.   attr_reader :offset_x
  2325.   attr_reader :offset_y
  2326.   attr_reader :width
  2327.   attr_reader :active
  2328.   attr_reader :pause
  2329.   attr_reader :height
  2330.   attr_reader :opacity
  2331.   attr_reader :back_opacity
  2332.   attr_reader :contents_opacity
  2333.   attr_reader :visible
  2334.   attr_reader :cursor_rect
  2335.   attr_reader :contents_blend_type
  2336.   attr_reader :blend_type
  2337.   attr_reader :openness
  2338.  
  2339.   def windowskin
  2340.     @_windowskin
  2341.   end
  2342.  
  2343.   # Flags used to preserve compatibility
  2344.   # with RGSS/RGSS2's version of Window
  2345.   module CompatBits
  2346.     CorrectZ=1
  2347.     ExpandBack=2
  2348.     ShowScrollArrows=4
  2349.     StretchSides=8
  2350.     ShowPause=16
  2351.     ShowCursor=32
  2352.   end
  2353.  
  2354.   attr_reader :compat
  2355.  
  2356.   def compat=(value)
  2357.     @compat=value
  2358.     privRefresh(true)
  2359.   end
  2360.  
  2361.   def initialize(viewport=nil)
  2362.     @sprites={}
  2363.     @spritekeys=[
  2364.        "back",
  2365.        "corner0","side0","scroll0",
  2366.        "corner1","side1","scroll1",
  2367.        "corner2","side2","scroll2",
  2368.        "corner3","side3","scroll3",
  2369.        "cursor","contents","pause"
  2370.     ]
  2371.     @viewport=viewport
  2372.     @sidebitmaps=[nil,nil,nil,nil]
  2373.     @cursorbitmap=nil
  2374.     @bgbitmap=nil
  2375.     for i in @spritekeys
  2376.       @sprites[i]=Sprite.new(@viewport)
  2377.     end
  2378.     @disposed=false
  2379.     @tone=Tone.new(0,0,0)
  2380.     @color=Color.new(0,0,0,0)
  2381.     @blankcontents=Bitmap.new(1,1) # RGSS2 requires this
  2382.     @contents=@blankcontents
  2383.     @_windowskin=nil
  2384.     @rpgvx=false
  2385.     @compat=CompatBits::ExpandBack|CompatBits::StretchSides
  2386.     @x=0
  2387.     @y=0
  2388.     @width=0
  2389.     @height=0
  2390.     @offset_x=0
  2391.     @offset_y=0
  2392.     @zoom_x=1.0
  2393.     @zoom_y=1.0
  2394.     @ox=0
  2395.     @oy=0
  2396.     @z=0
  2397.     @stretch=true
  2398.     @visible=true
  2399.     @active=true
  2400.     @openness=255
  2401.     @opacity=255
  2402.     @back_opacity=255
  2403.     @blend_type=0
  2404.     @contents_blend_type=0
  2405.     @contents_opacity=255
  2406.     @cursor_rect=SpriteWindowCursorRect.new(self)
  2407.     @cursorblink=0
  2408.     @cursoropacity=255
  2409.     @pause=false
  2410.     @pauseframe=0
  2411.     @flash=0
  2412.     @pauseopacity=0
  2413.     @skinformat=0
  2414.     @skinrect=Rect.new(0,0,0,0)
  2415.     @trim=[16,16,16,16]
  2416.     privRefresh(true)
  2417.   end
  2418.  
  2419.   def dispose
  2420.     if !self.disposed?
  2421.       for i in @sprites
  2422.         i[1].dispose if i[1]
  2423.         @sprites[i[0]]=nil
  2424.       end
  2425.       for i in 0...@sidebitmaps.length
  2426.         @sidebitmaps[i].dispose if @sidebitmaps[i]
  2427.         @sidebitmaps[i]=nil
  2428.       end
  2429.       @blankcontents.dispose
  2430.       @cursorbitmap.dispose if @cursorbitmap
  2431.       @backbitmap.dispose if @backbitmap
  2432.       @sprites.clear
  2433.       @sidebitmaps.clear
  2434.       @_windowskin=nil
  2435.       @disposed=true
  2436.     end
  2437.   end
  2438.  
  2439.   def stretch=(value)
  2440.     @stretch=value
  2441.     privRefresh(true)
  2442.   end
  2443.  
  2444.   def visible=(value)
  2445.     @visible=value
  2446.     privRefresh
  2447.   end
  2448.  
  2449.   def viewport=(value)
  2450.     @viewport=value
  2451.     for i in @spritekeys
  2452.       @sprites[i].dispose if @sprites[i]
  2453.     end
  2454.     for i in @spritekeys
  2455.       if @sprites[i].is_a?(Sprite)
  2456.         @sprites[i]=Sprite.new(@viewport)
  2457.       else
  2458.         @sprites[i]=nil
  2459.       end
  2460.     end
  2461.     privRefresh(true)
  2462.   end
  2463.  
  2464.   def z=(value)
  2465.     @z=value
  2466.     privRefresh
  2467.   end
  2468.  
  2469.   def disposed?
  2470.     return @disposed
  2471.   end
  2472.  
  2473.   def contents=(value)
  2474.     if @contents!=value
  2475.       @contents=value
  2476.       privRefresh if @visible
  2477.     end
  2478.   end
  2479.  
  2480.   def ox=(value)
  2481.     if @ox!=value
  2482.       @ox=value
  2483.       privRefresh if @visible
  2484.     end
  2485.   end
  2486.  
  2487.   def oy=(value)
  2488.     if @oy!=value
  2489.       @oy=value
  2490.       privRefresh if @visible
  2491.     end
  2492.   end
  2493.  
  2494.   def active=(value)
  2495.      @active=value
  2496.      privRefresh(true)
  2497.   end
  2498.  
  2499.   def cursor_rect=(value)
  2500.     if !value
  2501.       @cursor_rect.empty
  2502.     else
  2503.       @cursor_rect.set(value.x,value.y,value.width,value.height)
  2504.     end
  2505.   end
  2506.  
  2507.   def openness=(value)
  2508.     @openness=value
  2509.     @openness=0 if @openness<0
  2510.     @openness=255 if @openness>255
  2511.     privRefresh
  2512.   end
  2513.  
  2514.   def width=(value)
  2515.     @width=value
  2516.     privRefresh(true)
  2517.   end
  2518.  
  2519.   def height=(value)
  2520.     @height=value
  2521.     privRefresh(true)
  2522.   end
  2523.  
  2524.   def pause=(value)
  2525.     @pause=value
  2526.     @pauseopacity=0 if !value
  2527.     privRefresh if @visible
  2528.   end
  2529.  
  2530.   def x=(value)
  2531.     @x=value
  2532.     privRefresh if @visible
  2533.   end
  2534.  
  2535.   def y=(value)
  2536.     @y=value
  2537.     privRefresh if @visible
  2538.   end
  2539.  
  2540.   def zoom_x=(value)
  2541.     @zoom_x=value
  2542.     privRefresh if @visible
  2543.   end
  2544.  
  2545.   def zoom_y=(value)
  2546.     @zoom_y=value
  2547.     privRefresh if @visible
  2548.   end
  2549.  
  2550.   def offset_x=(value)
  2551.     @x=value
  2552.     privRefresh if @visible
  2553.   end
  2554.  
  2555.   def offset_y=(value)
  2556.     @y=value
  2557.     privRefresh if @visible
  2558.   end
  2559.  
  2560.   def opacity=(value)
  2561.     @opacity=value
  2562.     @opacity=0 if @opacity<0
  2563.     @opacity=255 if @opacity>255
  2564.     privRefresh if @visible
  2565.   end
  2566.  
  2567.   def back_opacity=(value)
  2568.     @back_opacity=value
  2569.     @back_opacity=0 if @back_opacity<0
  2570.     @back_opacity=255 if @back_opacity>255
  2571.     privRefresh if @visible
  2572.   end
  2573.  
  2574.   def contents_opacity=(value)
  2575.     @contents_opacity=value
  2576.     @contents_opacity=0 if @contents_opacity<0
  2577.     @contents_opacity=255 if @contents_opacity>255
  2578.     privRefresh if @visible
  2579.   end
  2580.  
  2581.   def tone=(value)
  2582.     @tone=value
  2583.     privRefresh if @visible
  2584.   end
  2585.  
  2586.   def color=(value)
  2587.     @color=value
  2588.     privRefresh if @visible
  2589.   end
  2590.  
  2591.   def blend_type=(value)
  2592.     @blend_type=value
  2593.     privRefresh if @visible
  2594.   end
  2595.  
  2596.   def flash(color,duration)
  2597.     return if disposed?
  2598.     @flash=duration+1
  2599.     for i in @sprites
  2600.       i[1].flash(color,duration)
  2601.     end
  2602.   end
  2603.  
  2604.   def update
  2605.     return if disposed?
  2606.     mustchange=false
  2607.     if @active
  2608.       if @cursorblink==0
  2609.         @cursoropacity-=8
  2610.         @cursorblink=1 if @cursoropacity<=128
  2611.       else
  2612.         @cursoropacity+=8
  2613.         @cursorblink=0 if @cursoropacity>=255
  2614.       end
  2615.       privRefreshCursor
  2616.     else
  2617.       @cursoropacity=128
  2618.       privRefreshCursor
  2619.     end
  2620.     if @pause
  2621.       oldpauseframe=@pauseframe
  2622.       oldpauseopacity=@pauseopacity
  2623.       @pauseframe=(Graphics.frame_count / 8) % 4
  2624.       @pauseopacity=[@pauseopacity+64,255].min
  2625.       mustchange=@pauseframe!=oldpauseframe || @pauseopacity!=oldpauseopacity
  2626.     end
  2627.     privRefresh if mustchange
  2628.     if @flash>0
  2629.       for i in @sprites.values
  2630.         i.update
  2631.       end
  2632.       @flash-=1
  2633.     end
  2634.   end
  2635.  
  2636.   #############
  2637.   attr_reader :skinformat
  2638.   attr_reader :skinrect
  2639.  
  2640.   def loadSkinFile(file)
  2641.     if (self.windowskin.width==80 || self.windowskin.width==96) &&
  2642.        self.windowskin.height==48
  2643.       # Body = X, Y, width, height of body rectangle within windowskin
  2644.       @skinrect.set(32,16,16,16)
  2645.       # Trim = X, Y, width, height of trim rectangle within windowskin
  2646.       @trim=[32,16,16,16]
  2647.     elsif self.windowskin.width==80 && self.windowskin.height==80
  2648.       @skinrect.set(32,32,16,16)
  2649.       @trim=[32,16,16,48]
  2650.     end
  2651.   end
  2652.  
  2653.   def windowskin=(value)
  2654.     oldSkinWidth=(@_windowskin && !@_windowskin.disposed?) ? @_windowskin.width : -1
  2655.     oldSkinHeight=(@_windowskin && !@_windowskin.disposed?) ? @_windowskin.height : -1
  2656.     @_windowskin=value
  2657.     if @skinformat==1
  2658.       @rpgvx=false
  2659.       if @_windowskin && !@_windowskin.disposed?
  2660.         if @_windowskin.width!=oldSkinWidth || @_windowskin.height!=oldSkinHeight
  2661.           # Update skinrect and trim if windowskin's dimensions have changed
  2662.           @skinrect.set((@_windowskin.width-16)/2,(@_windowskin.height-16)/2,16,16)
  2663.           @trim=[@skinrect.x,@skinrect.y,@skinrect.x,@skinrect.y]
  2664.         end
  2665.       else
  2666.         @skinrect.set(16,16,16,16)
  2667.         @trim=[16,16,16,16]
  2668.       end
  2669.     else
  2670.       if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128
  2671.         @rpgvx=true
  2672.       else
  2673.         @rpgvx=false
  2674.       end
  2675.       @trim=[16,16,16,16]
  2676.     end
  2677.     privRefresh(true)
  2678.   end
  2679.  
  2680.   def skinrect=(value)
  2681.     @skinrect=value
  2682.     privRefresh
  2683.   end
  2684.  
  2685.   def skinformat=(value)
  2686.     if @skinformat!=value
  2687.       @skinformat=value  
  2688.       privRefresh(true)
  2689.     end
  2690.   end
  2691.  
  2692.   def borderX
  2693.     return 32 if !@trim || skinformat==0
  2694.     if @_windowskin && !@_windowskin.disposed?
  2695.       return @trim[0]+(@_windowskin.width-@trim[2]-@trim[0])
  2696.     end
  2697.     return 32
  2698.   end
  2699.  
  2700.   def borderY
  2701.     return 32 if !@trim || skinformat==0
  2702.     if @_windowskin && !@_windowskin.disposed?
  2703.       return @trim[1]+(@_windowskin.height-@trim[3]-@trim[1])
  2704.     end
  2705.     return 32
  2706.   end
  2707.  
  2708.   def leftEdge; self.startX; end
  2709.   def topEdge; self.startY; end
  2710.   def rightEdge; self.borderX-self.leftEdge; end
  2711.   def bottomEdge; self.borderY-self.topEdge; end
  2712.  
  2713.   def startX
  2714.     return !@trim || skinformat==0  ? 16 : @trim[0]
  2715.   end
  2716.  
  2717.   def startY
  2718.     return !@trim || skinformat==0  ? 16 : @trim[1]
  2719.   end
  2720.  
  2721.   def endX
  2722.     return !@trim || skinformat==0  ? 16 : @trim[2]
  2723.   end
  2724.  
  2725.   def endY
  2726.     return !@trim || skinformat==0  ? 16 : @trim[3]
  2727.   end
  2728.  
  2729.   def startX=(value)
  2730.     @trim[0]=value
  2731.     privRefresh
  2732.   end
  2733.  
  2734.   def startY=(value)
  2735.     @trim[1]=value
  2736.     privRefresh
  2737.   end
  2738.  
  2739.   def endX=(value)
  2740.     @trim[2]=value
  2741.     privRefresh
  2742.   end
  2743.  
  2744.   def endY=(value)
  2745.     @trim[3]=value
  2746.     privRefresh
  2747.   end
  2748.  
  2749.   #############
  2750.   private
  2751.  
  2752.   def ensureBitmap(bitmap,dwidth,dheight)
  2753.     if !bitmap||bitmap.disposed?||bitmap.width<dwidth||bitmap.height<dheight
  2754.       bitmap.dispose if bitmap
  2755.       bitmap=Bitmap.new([1,dwidth].max,[1,dheight].max)
  2756.     end
  2757.     return bitmap
  2758.   end
  2759.  
  2760.   def tileBitmap(dstbitmap,dstrect,srcbitmap,srcrect)
  2761.     return if !srcbitmap || srcbitmap.disposed?
  2762.     left=dstrect.x
  2763.     top=dstrect.y
  2764.     y=0;loop do break unless y<dstrect.height
  2765.       x=0;loop do break unless x<dstrect.width
  2766.         dstbitmap.blt(x+left,y+top,srcbitmap,srcrect)
  2767.         x+=srcrect.width
  2768.       end
  2769.      y+=srcrect.height
  2770.    end
  2771.  end
  2772.  
  2773.   def privRefreshCursor
  2774.     contopac=self.contents_opacity
  2775.     cursoropac=@cursoropacity*contopac/255
  2776.     @sprites["cursor"].opacity=cursoropac
  2777.   end
  2778.  
  2779.   def privRefresh(changeBitmap=false)
  2780.     return if !self || self.disposed?
  2781.     backopac=self.back_opacity*self.opacity/255
  2782.     contopac=self.contents_opacity
  2783.     cursoropac=@cursoropacity*contopac/255
  2784.     haveskin=@_windowskin && !@_windowskin.disposed?
  2785.     for i in 0...4
  2786.       @sprites["corner#{i}"].bitmap=@_windowskin
  2787.       @sprites["scroll#{i}"].bitmap=@_windowskin
  2788.     end
  2789.     @sprites["pause"].bitmap=@_windowskin
  2790.     @sprites["contents"].bitmap=@contents
  2791.     if haveskin
  2792.       for i in 0...4
  2793.         @sprites["corner#{i}"].opacity=@opacity
  2794.         @sprites["corner#{i}"].tone=@tone
  2795.         @sprites["corner#{i}"].color=@color
  2796.         @sprites["corner#{i}"].visible=@visible
  2797.         @sprites["corner#{i}"].blend_type=@blend_type
  2798.         @sprites["side#{i}"].opacity=@opacity
  2799.         @sprites["side#{i}"].tone=@tone
  2800.         @sprites["side#{i}"].color=@color
  2801.         @sprites["side#{i}"].blend_type=@blend_type
  2802.         @sprites["side#{i}"].visible=@visible
  2803.         @sprites["scroll#{i}"].opacity=@opacity
  2804.         @sprites["scroll#{i}"].tone=@tone
  2805.         @sprites["scroll#{i}"].color=@color
  2806.         @sprites["scroll#{i}"].visible=@visible
  2807.         @sprites["scroll#{i}"].blend_type=@blend_type
  2808.       end
  2809.       for i in ["back","cursor","pause","contents"]
  2810.         @sprites[i].color=@color
  2811.         @sprites[i].tone=@tone
  2812.         @sprites[i].blend_type=@blend_type
  2813.       end
  2814.       @sprites["contents"].blend_type=@contents_blend_type
  2815.       @sprites["back"].opacity=backopac
  2816.       @sprites["contents"].opacity=contopac
  2817.       @sprites["cursor"].opacity=cursoropac
  2818.       @sprites["pause"].opacity=@pauseopacity
  2819.       supported=(@skinformat==0)
  2820.       hascontents=(@contents && !@contents.disposed?)
  2821.       @sprites["back"].visible=@visible
  2822.       @sprites["contents"].visible=@visible && @openness==255
  2823.       @sprites["pause"].visible=supported && @visible && @pause &&
  2824.          (@combat & CompatBits::ShowPause)
  2825.       @sprites["cursor"].visible=supported && @visible && @openness==255 &&
  2826.          (@combat & CompatBits::ShowCursor)
  2827.       @sprites["scroll0"].visible = false
  2828.       @sprites["scroll1"].visible = false
  2829.       @sprites["scroll2"].visible = false
  2830.       @sprites["scroll3"].visible = false
  2831.     else
  2832.       for i in 0...4
  2833.         @sprites["corner#{i}"].visible=false
  2834.         @sprites["side#{i}"].visible=false
  2835.         @sprites["scroll#{i}"].visible=false
  2836.       end
  2837.       @sprites["contents"].visible=@visible && @openness==255
  2838.       @sprites["contents"].color=@color
  2839.       @sprites["contents"].tone=@tone
  2840.       @sprites["contents"].blend_type=@contents_blend_type
  2841.       @sprites["contents"].opacity=contopac
  2842.       @sprites["back"].visible=false
  2843.       @sprites["pause"].visible=false
  2844.       @sprites["cursor"].visible=false
  2845.     end
  2846.     for i in @spritekeys
  2847.       @sprites[i].z=@z
  2848.     end
  2849.     if (@compat & CompatBits::CorrectZ)>0 && @skinformat==0 && !@rpgvx
  2850.       # Compatibility Mode: Cursor, pause, and contents have higher Z
  2851.       @sprites["cursor"].z=@z+1
  2852.       @sprites["contents"].z=@z+2
  2853.       @sprites["pause"].z=@z+2
  2854.     end
  2855.     if @skinformat==0
  2856.       startX=16
  2857.       startY=16
  2858.       endX=16
  2859.       endY=16
  2860.       trimStartX=16
  2861.       trimStartY=16
  2862.       trimWidth=32
  2863.       trimHeight=32
  2864.       if @rpgvx
  2865.         trimX=64
  2866.         trimY=0
  2867.         backRect=Rect.new(0,0,64,64)
  2868.         blindsRect=Rect.new(0,64,64,64)
  2869.       else
  2870.         trimX=128
  2871.         trimY=0
  2872.         backRect=Rect.new(0,0,128,128)
  2873.         blindsRect=nil
  2874.       end
  2875.       if @_windowskin && !@_windowskin.disposed?
  2876.         @sprites["corner0"].src_rect.set(trimX,trimY+0,16,16);
  2877.         @sprites["corner1"].src_rect.set(trimX+48,trimY+0,16,16);
  2878.         @sprites["corner2"].src_rect.set(trimX,trimY+48,16,16);
  2879.         @sprites["corner3"].src_rect.set(trimX+48,trimY+48,16,16);
  2880.         @sprites["scroll0"].src_rect.set(trimX+24, trimY+16, 16, 8) # up
  2881.         @sprites["scroll3"].src_rect.set(trimX+24, trimY+40, 16, 8) # down
  2882.         @sprites["scroll1"].src_rect.set(trimX+16, trimY+24, 8, 16) # left
  2883.         @sprites["scroll2"].src_rect.set(trimX+40, trimY+24, 8, 16) # right
  2884.         cursorX=trimX
  2885.         cursorY=trimY+64
  2886.         sideRects=[
  2887.            Rect.new(trimX+16,trimY+0,32,16),
  2888.            Rect.new(trimX,trimY+16,16,32),
  2889.            Rect.new(trimX+48,trimY+16,16,32),
  2890.            Rect.new(trimX+16,trimY+48,32,16)
  2891.         ]
  2892.         pauseRects=[
  2893.            trimX+32,trimY+64,
  2894.            trimX+48,trimY+64,
  2895.            trimX+32,trimY+80,
  2896.            trimX+48,trimY+80,
  2897.         ]
  2898.         pauseWidth=16
  2899.         pauseHeight=16
  2900.         @sprites["pause"].src_rect.set(
  2901.            pauseRects[@pauseframe*2],
  2902.            pauseRects[@pauseframe*2+1],
  2903.            pauseWidth,pauseHeight
  2904.         )
  2905.       end
  2906.     else
  2907.       trimStartX=@trim[0]
  2908.       trimStartY=@trim[1]
  2909.       trimWidth=@trim[0]+(@skinrect.width-@trim[2]+@trim[0])
  2910.       trimHeight=@trim[1]+(@skinrect.height-@trim[3]+@trim[1])
  2911.       if @_windowskin && !@_windowskin.disposed?
  2912.         # width of left end of window
  2913.         startX=@skinrect.x
  2914.         # width of top end of window
  2915.         startY=@skinrect.y
  2916.         backWidth=@skinrect.width
  2917.         backHeight=@skinrect.height
  2918.         cx=@skinrect.x+@skinrect.width # right side of BODY rect
  2919.         cy=@skinrect.y+@skinrect.height # bottom side of BODY rect
  2920.         # width of right end of window
  2921.         endX=(!@_windowskin || @_windowskin.disposed?) ? @skinrect.x : @_windowskin.width-cx
  2922.         # height of bottom end of window
  2923.         endY=(!@_windowskin || @_windowskin.disposed?) ? @skinrect.y : @_windowskin.height-cy
  2924.         @sprites["corner0"].src_rect.set(0,0,startX,startY);
  2925.         @sprites["corner1"].src_rect.set(cx,0,endX,startY);
  2926.         @sprites["corner2"].src_rect.set(0,cy,startX,endY);
  2927.         @sprites["corner3"].src_rect.set(cx,cy,endX,endY);
  2928.         backRect=Rect.new(@skinrect.x,@skinrect.y,
  2929.            @skinrect.width,@skinrect.height);
  2930.         blindsRect=nil
  2931.         sideRects=[
  2932.            Rect.new(startX,0,@skinrect.width,startY),  # side0 (top)
  2933.            Rect.new(0,startY,startX,@skinrect.height), # side1 (left)
  2934.            Rect.new(cx,startY,endX,@skinrect.height),  # side2 (right)
  2935.            Rect.new(startX,cy,@skinrect.width,endY)    # side3 (bottom)
  2936.         ]
  2937.       end
  2938.     end
  2939.     if @width>trimWidth && @height>trimHeight
  2940.       @sprites["contents"].src_rect.set(@ox,@oy,@width-trimWidth,@height-trimHeight)
  2941.     else
  2942.       @sprites["contents"].src_rect.set(0,0,0,0)
  2943.     end
  2944.     @sprites["contents"].x=@x+trimStartX
  2945.     @sprites["contents"].y=@y+trimStartY
  2946.     if (@compat & CompatBits::ShowScrollArrows)>0 && @skinformat==0
  2947.       # Compatibility mode: Make scroll arrows visible
  2948.       if @skinformat==0 && @_windowskin && !@_windowskin.disposed? &&
  2949.          @contents && !@contents.disposed?
  2950.         @sprites["scroll0"].visible = @visible && hascontents && @oy > 0
  2951.         @sprites["scroll1"].visible = @visible && hascontents && @ox > 0
  2952.         @sprites["scroll2"].visible = @visible && (@contents.width - @ox) > @width-trimWidth
  2953.         @sprites["scroll3"].visible = @visible && (@contents.height - @oy) > @height-trimHeight
  2954.       end
  2955.     end
  2956.     if @_windowskin && !@_windowskin.disposed?
  2957.       backTrimX=startX+endX
  2958.       backTrimY=startX+endX
  2959.       borderX=startX+endX
  2960.       borderY=startY+endY
  2961.       @sprites["corner0"].x=@x
  2962.       @sprites["corner0"].y=@y
  2963.       @sprites["corner1"].x=@x+@width-endX
  2964.       @sprites["corner1"].y=@y
  2965.       @sprites["corner2"].x=@x
  2966.       @sprites["corner2"].y=@y+@height-endY
  2967.       @sprites["corner3"].x=@x+@width-endX
  2968.       @sprites["corner3"].y=@y+@height-endY
  2969.       @sprites["side0"].x=@x+startX
  2970.       @sprites["side0"].y=@y
  2971.       @sprites["side1"].x=@x
  2972.       @sprites["side1"].y=@y+startY
  2973.       @sprites["side2"].x=@x+@width-endX
  2974.       @sprites["side2"].y=@y+startY
  2975.       @sprites["side3"].x=@x+startX
  2976.       @sprites["side3"].y=@y+@height-endY
  2977.       @sprites["scroll0"].x = @x+@width / 2 - 8
  2978.       @sprites["scroll0"].y = @y+8
  2979.       @sprites["scroll1"].x = @x+8
  2980.       @sprites["scroll1"].y = @y+@height / 2 - 8
  2981.       @sprites["scroll2"].x = @x+@width - 16
  2982.       @sprites["scroll2"].y = @y+@height / 2 - 8
  2983.       @sprites["scroll3"].x = @x+@width / 2 - 8
  2984.       @sprites["scroll3"].y = @y+@height - 16
  2985.       @sprites["cursor"].x=@x+startX+@cursor_rect.x
  2986.       @sprites["cursor"].y=@y+startY+@cursor_rect.y
  2987.       if (@compat & CompatBits::ExpandBack)>0 && @skinformat==0
  2988.         # Compatibility mode: Expand background
  2989.         @sprites["back"].x=@x+2
  2990.         @sprites["back"].y=@y+2
  2991.       else
  2992.         @sprites["back"].x=@x+startX
  2993.         @sprites["back"].y=@y+startY
  2994.       end
  2995.     end
  2996.     if changeBitmap && @_windowskin && !@_windowskin.disposed?
  2997.       if @skinformat==0
  2998.         @sprites["cursor"].x=@x+startX+@cursor_rect.x
  2999.         @sprites["cursor"].y=@y+startY+@cursor_rect.y
  3000.         width=@cursor_rect.width
  3001.         height=@cursor_rect.height
  3002.         if width > 0 && height > 0
  3003.           cursorrects=[
  3004.              # sides
  3005.              Rect.new(cursorX+2, cursorY+0, 28, 2),
  3006.              Rect.new(cursorX+0, cursorY+2, 2, 28),
  3007.              Rect.new(cursorX+30, cursorY+2, 2, 28),
  3008.              Rect.new(cursorX+2, cursorY+30, 28, 2),
  3009.              # corners
  3010.              Rect.new(cursorX+0, cursorY+0, 2, 2),
  3011.              Rect.new(cursorX+30, cursorY+0, 2, 2),
  3012.              Rect.new(cursorX+0, cursorY+30, 2, 2),
  3013.              Rect.new(cursorX+30, cursorY+30, 2, 2),
  3014.              # back
  3015.              Rect.new(cursorX+2, cursorY+2, 28, 28)
  3016.           ]
  3017.           margin=2
  3018.           fullmargin=4
  3019.           @cursorbitmap = ensureBitmap(@cursorbitmap, width, height)
  3020.           @cursorbitmap.clear
  3021.           @sprites["cursor"].bitmap=@cursorbitmap
  3022.           @sprites["cursor"].src_rect.set(0,0,width,height)
  3023.           rect = Rect.new(margin,margin,width - fullmargin, height - fullmargin)
  3024.           @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[8])
  3025.           @cursorbitmap.blt(0, 0, @_windowskin, cursorrects[4])# top left
  3026.           @cursorbitmap.blt(width-margin, 0, @_windowskin, cursorrects[5]) # top right
  3027.           @cursorbitmap.blt(0, height-margin, @_windowskin, cursorrects[6]) # bottom right
  3028.           @cursorbitmap.blt(width-margin, height-margin, @_windowskin, cursorrects[7]) # bottom left
  3029.           rect = Rect.new(margin, 0,width - fullmargin, margin)
  3030.           @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[0])
  3031.           rect = Rect.new(0, margin,margin, height - fullmargin)
  3032.           @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[1])
  3033.           rect = Rect.new(width - margin, margin, margin, height - fullmargin)
  3034.           @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[2])
  3035.           rect = Rect.new(margin, height-margin, width - fullmargin, margin)
  3036.           @cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[3])
  3037.         else
  3038.           @sprites["cursor"].visible=false
  3039.           @sprites["cursor"].src_rect.set(0,0,0,0)
  3040.         end
  3041.       end
  3042.       for i in 0..3
  3043.         case i
  3044.         when 0
  3045.           dwidth=@width-startX-endX
  3046.           dheight=startY
  3047.         when 1
  3048.           dwidth=startX
  3049.           dheight=@height-startY-endY
  3050.         when 2
  3051.           dwidth=endX
  3052.           dheight=@height-startY-endY
  3053.         when 3
  3054.           dwidth=@width-startX-endX
  3055.           dheight=endY
  3056.         end
  3057.         @sidebitmaps[i]=ensureBitmap(@sidebitmaps[i],dwidth,dheight)
  3058.         @sprites["side#{i}"].bitmap=@sidebitmaps[i]
  3059.         @sprites["side#{i}"].src_rect.set(0,0,dwidth,dheight)
  3060.         @sidebitmaps[i].clear
  3061.         if sideRects[i].width>0 && sideRects[i].height>0
  3062.           if (@compat & CompatBits::StretchSides)>0 && @skinformat==0
  3063.             # Compatibility mode: Stretch sides
  3064.             @sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect,
  3065.                @_windowskin,sideRects[i])
  3066.           else
  3067.             tileBitmap(@sidebitmaps[i],@sprites["side#{i}"].src_rect,
  3068.                @_windowskin,sideRects[i])
  3069.           end
  3070.         end
  3071.       end
  3072.       if (@compat & CompatBits::ExpandBack)>0 && @skinformat==0
  3073.         # Compatibility mode: Expand background
  3074.         backwidth=@width-4
  3075.         backheight=@height-4
  3076.       else
  3077.         backwidth=@width-borderX
  3078.         backheight=@height-borderY
  3079.       end
  3080.       if backwidth>0 && backheight>0
  3081.         @backbitmap=ensureBitmap(@backbitmap,backwidth,backheight)
  3082.         @sprites["back"].bitmap=@backbitmap
  3083.         @sprites["back"].src_rect.set(0,0,backwidth,backheight)
  3084.         @backbitmap.clear
  3085.         if @stretch
  3086.           @backbitmap.stretch_blt(@sprites["back"].src_rect,@_windowskin,backRect)
  3087.         else
  3088.           tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,backRect)
  3089.         end
  3090.         if blindsRect
  3091.           tileBitmap(@backbitmap,@sprites["back"].src_rect,@_windowskin,blindsRect)
  3092.         end
  3093.       else
  3094.         @sprites["back"].visible=false
  3095.         @sprites["back"].src_rect.set(0,0,0,0)
  3096.       end
  3097.     end
  3098.     if @openness!=255
  3099.       opn=@openness/255.0
  3100.       for k in @spritekeys
  3101.         sprite=@sprites[k]
  3102.         ratio=(@height<=0) ? 0 : (sprite.y-@y)*1.0/@height
  3103.         sprite.zoom_y=opn
  3104.         sprite.zoom_x=1.0
  3105.         sprite.oy=0
  3106.         sprite.y=(@y+(@height/2.0)+(@height*ratio*opn)-(@height/2*opn)).floor
  3107.         oldbitmap=sprite.bitmap
  3108.         oldsrcrect=sprite.src_rect.clone
  3109.       end
  3110.     else
  3111.       for k in @spritekeys
  3112.         sprite=@sprites[k]
  3113.         sprite.zoom_x=1.0
  3114.         sprite.zoom_y=1.0
  3115.       end
  3116.     end
  3117.     i=0
  3118.     # Ensure Z order
  3119.     for k in @spritekeys
  3120.       sprite=@sprites[k]
  3121.       y=sprite.y
  3122.       sprite.y=i
  3123.       sprite.oy=(sprite.zoom_y<=0) ? 0 : (i-y)/sprite.zoom_y
  3124.       sprite.zoom_x*=@zoom_x
  3125.       sprite.zoom_y*=@zoom_y
  3126.       sprite.x*=@zoom_x
  3127.       sprite.y*=@zoom_y
  3128.       sprite.x+=(@offset_x/sprite.zoom_x)
  3129.       sprite.y+=(@offset_y/sprite.zoom_y)
  3130.     end
  3131.   end
  3132. end
  3133.  
  3134.  
  3135.  
  3136. class SpriteWindow_Base < SpriteWindow
  3137.   TEXTPADDING=4 # In pixels
  3138.  
  3139.   def initialize(x, y, width, height)
  3140.     super()
  3141.     self.x = x
  3142.     self.y = y
  3143.     self.width = width
  3144.     self.height = height
  3145.     self.z = 100
  3146.     @curframe=MessageConfig.pbGetSystemFrame()
  3147.     @curfont=MessageConfig.pbGetSystemFontName()
  3148.     @sysframe=AnimatedBitmap.new(@curframe)
  3149.     @customskin=nil
  3150.     __setWindowskin(@sysframe.bitmap)
  3151.     __resolveSystemFrame()
  3152.     pbSetSystemFont(self.contents) if self.contents
  3153.   end
  3154.  
  3155.   def __setWindowskin(skin)
  3156.     if skin && (skin.width==192 && skin.height==128) ||  # RPGXP Windowskin
  3157.                (skin.width==128 && skin.height==128)     # RPGVX Windowskin
  3158.       self.skinformat=0
  3159.     else
  3160.       self.skinformat=1
  3161.     end
  3162.     self.windowskin=skin
  3163.   end
  3164.  
  3165.   def __resolveSystemFrame
  3166.     if self.skinformat==1
  3167.       if !@resolvedFrame
  3168.         @resolvedFrame=MessageConfig.pbGetSystemFrame()
  3169.         @resolvedFrame.sub!(/\.[^\.\/\\]+$/,"")
  3170.       end
  3171.       self.loadSkinFile("#{@resolvedFrame}.txt") if @resolvedFrame!=""
  3172.     end
  3173.   end
  3174.  
  3175.   def setSkin(skin) # Filename of windowskin to apply. Supports XP, VX, and animated skins.
  3176.     @customskin.dispose if @customskin
  3177.     @customskin=nil
  3178.     resolvedName=pbResolveBitmap(skin)
  3179.     return if !resolvedName || resolvedName==""
  3180.     @customskin=AnimatedBitmap.new(resolvedName)
  3181.     __setWindowskin(@customskin.bitmap)
  3182.     if self.skinformat==1
  3183.       skinbase=resolvedName.sub(/\.[^\.\/\\]+$/,"")
  3184.       self.loadSkinFile("#{skinbase}.txt")
  3185.     end
  3186.   end
  3187.  
  3188.   def setSystemFrame
  3189.     @customskin.dispose if @customskin
  3190.     @customskin=nil
  3191.     __setWindowskin(@sysframe.bitmap)
  3192.     __resolveSystemFrame()
  3193.   end
  3194.  
  3195.   def update
  3196.     super
  3197.     if self.windowskin
  3198.       if @customskin
  3199.         if @customskin.totalFrames>1
  3200.           @customskin.update
  3201.           __setWindowskin(@customskin.bitmap)
  3202.         end
  3203.       elsif @sysframe
  3204.         if @sysframe.totalFrames>1
  3205.           @sysframe.update
  3206.           __setWindowskin(@sysframe.bitmap)
  3207.         end
  3208.       end
  3209.     end
  3210.     if @curframe!=MessageConfig.pbGetSystemFrame()
  3211.       @curframe=MessageConfig.pbGetSystemFrame()
  3212.       if @sysframe && !@customskin
  3213.         @sysframe.dispose if @sysframe
  3214.         @sysframe=AnimatedBitmap.new(@curframe)
  3215.         @resolvedFrame=nil
  3216.         __setWindowskin(@sysframe.bitmap)
  3217.         __resolveSystemFrame()  
  3218.       end
  3219.       begin
  3220.         refresh
  3221.       rescue NoMethodError
  3222.       end
  3223.     end
  3224.     if @curfont!=MessageConfig.pbGetSystemFontName()
  3225.       @curfont=MessageConfig.pbGetSystemFontName()
  3226.       if self.contents && !self.contents.disposed?
  3227.         pbSetSystemFont(self.contents)
  3228.       end
  3229.       begin
  3230.         refresh
  3231.       rescue NoMethodError
  3232.       end
  3233.     end
  3234.   end
  3235.  
  3236.   def dispose
  3237.     self.contents.dispose if self.contents
  3238.     @sysframe.dispose
  3239.     @customskin.dispose if @customskin
  3240.     super
  3241.   end
  3242. end
  3243.  
  3244.  
  3245.  
  3246. class SpriteWindow_Selectable < SpriteWindow_Base
  3247.   attr_reader :index
  3248.  
  3249.   def initialize(x, y, width, height)
  3250.     super(x, y, width, height)
  3251.     @item_max = 1
  3252.     @column_max = 1
  3253.     @virtualOy=0
  3254.     @index = -1
  3255.     @row_height = 32
  3256.     @column_spacing = 32
  3257.     @ignore_input = false
  3258.   end
  3259.  
  3260.   def itemCount
  3261.     return @item_max || 0
  3262.   end
  3263.  
  3264.   def index=(index)
  3265.     if @index!=index
  3266.       @index = index
  3267.       priv_update_cursor_rect(true)
  3268.     end
  3269.   end
  3270.  
  3271.   def rowHeight
  3272.     return @row_height || 32
  3273.   end
  3274.  
  3275.   def rowHeight=(value)
  3276.     if @row_height!=value
  3277.       oldTopRow=self.top_row
  3278.       @row_height=[1,value].max
  3279.       self.top_row=oldTopRow
  3280.       update_cursor_rect
  3281.     end
  3282.   end
  3283.  
  3284.   def columns
  3285.     return @column_max || 1
  3286.   end
  3287.  
  3288.   def columns=(value)
  3289.     if @column_max!=value
  3290.       @column_max=[1,value].max
  3291.       update_cursor_rect
  3292.     end
  3293.   end
  3294.  
  3295.   def columnSpacing
  3296.     return @column_spacing || 32
  3297.   end
  3298.  
  3299.   def columnSpacing=(value)
  3300.     if @column_spacing!=value
  3301.       @column_spacing=[0,value].max
  3302.       update_cursor_rect
  3303.     end
  3304.   end
  3305.  
  3306.   def ignore_input=(value)
  3307.     @ignore_input=value
  3308.   end
  3309.  
  3310.   def count
  3311.     return @item_max
  3312.   end
  3313.  
  3314.   def row_max
  3315.     return ((@item_max + @column_max - 1) / @column_max).to_i
  3316.   end
  3317.  
  3318.   def top_row
  3319.     return (@virtualOy / (@row_height || 32)).to_i
  3320.   end
  3321.  
  3322.   def top_item
  3323.     return top_row * @column_max
  3324.   end
  3325.  
  3326.   def update_cursor_rect
  3327.     priv_update_cursor_rect
  3328.   end
  3329.  
  3330.   def top_row=(row)
  3331.     if row>row_max-1
  3332.       row=row_max-1
  3333.     end
  3334.     if row<0 # NOTE: The two comparison checks must be reversed since row_max can be 0
  3335.       row=0
  3336.     end
  3337.     @virtualOy=row*@row_height
  3338.   end
  3339.  
  3340.   def page_row_max
  3341.     return priv_page_row_max.to_i
  3342.   end
  3343.  
  3344.   def page_item_max
  3345.     return priv_page_item_max.to_i
  3346.   end
  3347.  
  3348.   def itemRect(item)
  3349.     if item<0 || item>=@item_max || item<self.top_item ||
  3350.        item>self.top_item+self.page_item_max
  3351.       return Rect.new(0,0,0,0)
  3352.     else
  3353.       cursor_width = (self.width-self.borderX-(@column_max-1)*@column_spacing) / @column_max
  3354.       x = item % @column_max * (cursor_width + @column_spacing)
  3355.       y = item / @column_max * @row_height - @virtualOy
  3356.       return Rect.new(x, y, cursor_width, @row_height)
  3357.     end
  3358.   end
  3359.  
  3360.   def update
  3361.     super
  3362.     if self.active and @item_max > 0 and @index >= 0 and !@ignore_input
  3363.       if Input.repeat?(Input::DOWN)
  3364.         if (Input.trigger?(Input::DOWN) && (@item_max%@column_max)==0) or
  3365.            @index < @item_max - @column_max
  3366.           oldindex=@index
  3367.           @index = (@index + @column_max) % @item_max
  3368.           if @index!=oldindex
  3369.             pbPlayCursorSE()
  3370.             update_cursor_rect
  3371.           end
  3372.         end
  3373.       end
  3374.       if Input.repeat?(Input::UP)
  3375.         if (Input.trigger?(Input::UP) && (@item_max%@column_max)==0) or
  3376.            @index >= @column_max
  3377.           oldindex=@index
  3378.           @index = (@index - @column_max + @item_max) % @item_max
  3379.           if @index!=oldindex
  3380.             pbPlayCursorSE()
  3381.             update_cursor_rect
  3382.           end
  3383.         end
  3384.       end
  3385.       if Input.repeat?(Input::RIGHT)
  3386.         if @column_max >= 2 and @index < @item_max - 1
  3387.           oldindex=@index
  3388.           @index += 1
  3389.           if @index!=oldindex
  3390.             pbPlayCursorSE()
  3391.             update_cursor_rect
  3392.           end
  3393.         end
  3394.       end
  3395.       if Input.repeat?(Input::LEFT)
  3396.         if @column_max >= 2 and @index > 0
  3397.           oldindex=@index
  3398.           @index -= 1
  3399.           if @index!=oldindex
  3400.             pbPlayCursorSE()
  3401.             update_cursor_rect
  3402.           end
  3403.         end
  3404.       end
  3405.       if Input.repeat?(Input::R)
  3406.         if self.index < @item_max-1
  3407.           oldindex=@index
  3408.           @index = [self.index+self.page_item_max, @item_max-1].min
  3409.           if @index!=oldindex
  3410.             pbPlayCursorSE()
  3411.             self.top_row += self.page_row_max
  3412.             update_cursor_rect
  3413.           end
  3414.         end
  3415.       end
  3416.       if Input.repeat?(Input::L)
  3417.         if self.index > 0
  3418.           oldindex=@index
  3419.           @index = [self.index-self.page_item_max, 0].max
  3420.           if @index!=oldindex
  3421.             pbPlayCursorSE()
  3422.             self.top_row -= self.page_row_max
  3423.             update_cursor_rect
  3424.           end
  3425.         end
  3426.       end
  3427.     end
  3428.   end
  3429.  
  3430.   def refresh; ;end
  3431.  
  3432.   private
  3433.  
  3434.   def priv_page_row_max
  3435.     return (self.height - self.borderY) / @row_height
  3436.   end
  3437.  
  3438.   def priv_page_item_max
  3439.     return (self.height - self.borderY) / @row_height * @column_max
  3440.   end
  3441.  
  3442.   def priv_update_cursor_rect(force=false)
  3443.     if @index < 0
  3444.       self.cursor_rect.empty
  3445.       self.refresh
  3446.       return
  3447.     end
  3448.     row = @index / @column_max
  3449.     if row < self.top_row
  3450.       self.top_row = row
  3451.       dorefresh=true
  3452.     end
  3453.     if row > self.top_row + (self.page_row_max - 1)
  3454.       self.top_row = row - (self.page_row_max - 1)
  3455.       dorefresh=true
  3456.     end
  3457.     self.top_row = [self.top_row, self.row_max - self.page_row_max].min  # ADDED
  3458.     cursor_width = (self.width-self.borderX) / @column_max
  3459.     x = self.index % @column_max * (cursor_width + @column_spacing)
  3460.     y = self.index / @column_max * @row_height - @virtualOy
  3461.     self.cursor_rect.set(x, y, cursor_width, @row_height)
  3462.     self.refresh if dorefresh || force
  3463.   end
  3464. end
  3465.  
  3466.  
  3467.  
  3468. module UpDownArrowMixin
  3469.   def initUpDownArrow
  3470.     @uparrow=AnimatedSprite.create("Graphics/Pictures/uparrow",8,2,self.viewport)
  3471.     @downarrow=AnimatedSprite.create("Graphics/Pictures/downarrow",8,2,self.viewport)
  3472.     @uparrow.z=99998
  3473.     @downarrow.z=99998
  3474.     @uparrow.visible=false
  3475.     @downarrow.visible=false
  3476.     @uparrow.play
  3477.     @downarrow.play
  3478.   end
  3479.  
  3480.   def dispose
  3481.     @uparrow.dispose
  3482.     @downarrow.dispose
  3483.     super
  3484.   end
  3485.  
  3486.   def viewport=(value)
  3487.     super
  3488.     @uparrow.viewport=self.viewport
  3489.     @downarrow.viewport=self.viewport
  3490.   end
  3491.  
  3492.   def color=(value)
  3493.     super
  3494.     @uparrow.color=value
  3495.     @downarrow.color=value
  3496.   end
  3497.  
  3498.   def adjustForZoom(sprite)
  3499.     sprite.zoom_x=self.zoom_x
  3500.     sprite.zoom_y=self.zoom_y
  3501.     sprite.x=(sprite.x*self.zoom_x+self.offset_x/self.zoom_x)
  3502.     sprite.y=(sprite.y*self.zoom_y+self.offset_y/self.zoom_y)
  3503.   end
  3504.  
  3505.   def update
  3506.     super
  3507.     @uparrow.x=self.x+(self.width/2)-(@uparrow.framewidth/2)
  3508.     @downarrow.x=self.x+(self.width/2)-(@downarrow.framewidth/2)
  3509.     @uparrow.y=self.y
  3510.     @downarrow.y=self.y+self.height-@downarrow.frameheight
  3511.     @uparrow.visible=self.visible && self.active && (self.top_item!=0 &&
  3512.        @item_max > self.page_item_max)
  3513.     @downarrow.visible=self.visible && self.active &&
  3514.        (self.top_item+self.page_item_max<@item_max && @item_max > self.page_item_max)
  3515.     @uparrow.z=self.z+1
  3516.     @downarrow.z=self.z+1
  3517.     adjustForZoom(@uparrow)
  3518.     adjustForZoom(@downarrow)
  3519.     @uparrow.viewport=self.viewport
  3520.     @downarrow.viewport=self.viewport
  3521.     @uparrow.update
  3522.     @downarrow.update
  3523.   end
  3524. end
  3525.  
  3526.  
  3527.  
  3528. class SpriteWindow_SelectableEx < SpriteWindow_Selectable
  3529.   include UpDownArrowMixin
  3530.  
  3531.   def initialize(*arg)
  3532.     super(*arg)
  3533.     initUpDownArrow
  3534.   end
  3535. end
  3536.  
  3537.  
  3538.  
  3539. class Window_DrawableCommand < SpriteWindow_SelectableEx
  3540.   attr_reader :baseColor
  3541.   attr_reader :shadowColor
  3542.  
  3543.   def textWidth(bitmap,text)
  3544.     return tmpbitmap.text_size(i).width
  3545.   end
  3546.  
  3547.   def getAutoDims(commands,dims,width=nil)
  3548.     rowMax=((commands.length + self.columns - 1) / self.columns).to_i
  3549.     windowheight=(rowMax*self.rowHeight)
  3550.     windowheight+=self.borderY
  3551.     if !width || width<0
  3552.       width=0
  3553.       tmpbitmap=BitmapWrapper.new(1,1)
  3554.       pbSetSystemFont(tmpbitmap)
  3555.       for i in commands
  3556.         width=[width,tmpbitmap.text_size(i).width].max
  3557.       end
  3558.       # one 16 to allow cursor
  3559.       width+=16+16+SpriteWindow_Base::TEXTPADDING
  3560.       tmpbitmap.dispose
  3561.     end
  3562.     # Store suggested width and height of window
  3563.     dims[0]=[self.borderX+1,(width*self.columns)+self.borderX+
  3564.        (self.columns-1)*self.columnSpacing].max
  3565.     dims[1]=[self.borderY+1,windowheight].max
  3566.     dims[1]=[dims[1],Graphics.height].min
  3567.   end
  3568.  
  3569.   def initialize(x,y,width,height,viewport=nil)
  3570.     super(x,y,width,height)
  3571.     self.viewport=viewport if viewport
  3572.     @selarrow=AnimatedBitmap.new("Graphics/Pictures/selarrow")
  3573.     @index=0
  3574.     colors=getDefaultTextColors(self.windowskin)
  3575.     @baseColor=colors[0]
  3576.     @shadowColor=colors[1]
  3577.     refresh
  3578.   end
  3579.  
  3580.   def drawCursor(index,rect)
  3581.     if self.index==index
  3582.       pbCopyBitmap(self.contents,@selarrow.bitmap,rect.x,rect.y)
  3583.     end
  3584.     return Rect.new(rect.x+16,rect.y,rect.width-16,rect.height)
  3585.   end
  3586.  
  3587.   def dispose
  3588.     @selarrow.dispose
  3589.     super
  3590.   end
  3591.  
  3592.   def baseColor=(value)
  3593.     @baseColor=value
  3594.     refresh
  3595.   end
  3596.  
  3597.   def shadowColor=(value)
  3598.     @shadowColor=value
  3599.     refresh
  3600.   end
  3601.  
  3602.   def itemCount # to be implemented by derived classes
  3603.     return 0
  3604.   end
  3605.  
  3606.   def drawItem(index,count,rect) # to be implemented by derived classes
  3607.   end
  3608.  
  3609.   def refresh
  3610.     @item_max=itemCount()
  3611.     dwidth=self.width-self.borderX
  3612.     dheight=self.height-self.borderY
  3613.     self.contents=pbDoEnsureBitmap(self.contents,dwidth,dheight)
  3614.     self.contents.clear
  3615.     for i in 0...@item_max
  3616.       if i<self.top_item || i>self.top_item+self.page_item_max
  3617.         next
  3618.       end
  3619.       drawItem(i,@item_max,itemRect(i))
  3620.     end
  3621.   end
  3622.  
  3623.   def update
  3624.     oldindex=self.index
  3625.     super
  3626.     refresh if self.index!=oldindex
  3627.   end
  3628. end
  3629.  
  3630.  
  3631.  
  3632. class Window_CommandPokemon < Window_DrawableCommand
  3633.   attr_reader :commands
  3634.  
  3635.   def initialize(commands,width=nil)
  3636.     @starting=true
  3637.     @commands=[]
  3638.     dims=[]
  3639.     super(0,0,32,32)
  3640.     getAutoDims(commands,dims,width)
  3641.     self.width=dims[0]
  3642.     self.height=dims[1]
  3643.     @commands=commands
  3644.     self.active=true
  3645.     colors=getDefaultTextColors(self.windowskin)
  3646.     self.baseColor=colors[0]
  3647.     self.shadowColor=colors[1]
  3648.     refresh
  3649.     @starting=false
  3650.   end
  3651.  
  3652.   def self.newWithSize(commands,x,y,width,height,viewport=nil)
  3653.     ret=self.new(commands,width)
  3654.     ret.x=x
  3655.     ret.y=y
  3656.     ret.width=width
  3657.     ret.height=height
  3658.     ret.viewport=viewport
  3659.     return ret
  3660.   end
  3661.  
  3662.   def self.newEmpty(x,y,width,height,viewport=nil)
  3663.     ret=self.new([],width)
  3664.     ret.x=x
  3665.     ret.y=y
  3666.     ret.width=width
  3667.     ret.height=height
  3668.     ret.viewport=viewport
  3669.     return ret
  3670.   end
  3671.  
  3672.   def index=(value)
  3673.     super
  3674.     refresh if !@starting
  3675.   end
  3676.  
  3677.   def commands=(value)
  3678.     @commands=value
  3679.     @item_max=commands.length  
  3680.     self.update_cursor_rect
  3681.     self.refresh
  3682.   end
  3683.  
  3684.   def width=(value)
  3685.     super
  3686.     if !@starting
  3687.       self.index=self.index
  3688.       self.update_cursor_rect
  3689.     end
  3690.   end
  3691.  
  3692.   def height=(value)
  3693.     super
  3694.     if !@starting
  3695.       self.index=self.index
  3696.       self.update_cursor_rect
  3697.     end
  3698.   end
  3699.  
  3700.   def resizeToFit(commands,width=nil)
  3701.     dims=[]
  3702.     getAutoDims(commands,dims,width)
  3703.     self.width=dims[0]
  3704.     self.height=dims[1]
  3705.   end
  3706.  
  3707.   def itemCount
  3708.     return @commands ? @commands.length : 0
  3709.   end
  3710.  
  3711.   def drawItem(index,count,rect)
  3712.     pbSetSystemFont(self.contents) if @starting
  3713.     rect=drawCursor(index,rect)
  3714.     pbDrawShadowText(self.contents,rect.x,rect.y,rect.width,rect.height,
  3715.        @commands[index],self.baseColor,self.shadowColor)
  3716.   end
  3717. end
  3718.  
  3719.  
  3720.  
  3721. class Window_AdvancedCommandPokemon < Window_DrawableCommand
  3722.   attr_reader :commands
  3723.  
  3724.   def textWidth(bitmap,text)
  3725.     dims=[nil,0]
  3726.     chars=getFormattedText(bitmap,0,0,
  3727.        Graphics.width-self.borderX-SpriteWindow_Base::TEXTPADDING-16,
  3728.        -1,text,self.rowHeight,true,true)
  3729.     for ch in chars
  3730.       dims[0]=dims[0] ? [dims[0],ch[1]].min : ch[1]
  3731.       dims[1]=[dims[1],ch[1]+ch[3]].max
  3732.     end
  3733.     dims[0]=0 if !dims[0]
  3734.     return dims[1]-dims[0]
  3735.   end
  3736.  
  3737.   def initialize(commands,width=nil)
  3738.     @starting=true
  3739.     @commands=[]
  3740.     dims=[]
  3741.     super(0,0,32,32)
  3742.     getAutoDims(commands,dims,width)
  3743.     self.width=dims[0]
  3744.     self.height=dims[1]
  3745.     @commands=commands
  3746.     self.active=true
  3747.     colors=getDefaultTextColors(self.windowskin)
  3748.     self.baseColor=colors[0]
  3749.     self.shadowColor=colors[1]
  3750.     refresh
  3751.     @starting=false
  3752.   end
  3753.  
  3754.   def self.newWithSize(commands,x,y,width,height,viewport=nil)
  3755.     ret=self.new(commands,width)
  3756.     ret.x=x
  3757.     ret.y=y
  3758.     ret.width=width
  3759.     ret.height=height
  3760.     ret.viewport=viewport
  3761.     return ret
  3762.   end
  3763.  
  3764.   def self.newEmpty(x,y,width,height,viewport=nil)
  3765.     ret=self.new([],width)
  3766.     ret.x=x
  3767.     ret.y=y
  3768.     ret.width=width
  3769.     ret.height=height
  3770.     ret.viewport=viewport
  3771.     return ret
  3772.   end
  3773.  
  3774.   def index=(value)
  3775.     super
  3776.     refresh if !@starting
  3777.   end
  3778.  
  3779.   def commands=(value)
  3780.     @commands=value
  3781.     @item_max=commands.length
  3782.     self.update_cursor_rect
  3783.     self.refresh
  3784.   end
  3785.  
  3786.   def width=(value)
  3787.     oldvalue=self.width
  3788.     super
  3789.     if !@starting && oldvalue!=value
  3790.       self.index=self.index
  3791.       self.update_cursor_rect
  3792.     end
  3793.   end
  3794.  
  3795.   def height=(value)
  3796.     oldvalue=self.height
  3797.     super
  3798.     if !@starting && oldvalue!=value
  3799.       self.index=self.index
  3800.       self.update_cursor_rect
  3801.     end
  3802.   end
  3803.  
  3804.   def resizeToFit(commands,width=nil)
  3805.     dims=[]
  3806.     getAutoDims(commands,dims,width)
  3807.     self.width=dims[0]
  3808.     self.height=dims[1]
  3809.   end
  3810.  
  3811.   def itemCount
  3812.     return @commands ? @commands.length : 0
  3813.   end
  3814.  
  3815.   def drawItem(index,count,rect)
  3816.     pbSetSystemFont(self.contents)
  3817.     rect=drawCursor(index,rect)
  3818.     if toUnformattedText(@commands[index]).gsub(/\n/,"")==@commands[index]
  3819.       # Use faster alternative for unformatted text without line breaks
  3820.       pbDrawShadowText(self.contents,rect.x,rect.y,rect.width,rect.height,
  3821.          @commands[index],self.baseColor,self.shadowColor)
  3822.     else
  3823.       chars=getFormattedText(
  3824.          self.contents,rect.x,rect.y,rect.width,rect.height,
  3825.          @commands[index],rect.height,true,true)
  3826.       drawFormattedChars(self.contents,chars)
  3827.     end
  3828.   end
  3829. end
  3830.  
  3831.  
  3832.  
  3833. # Represents a window with no formatting capabilities.  Its text color can be set,
  3834. # though, and line breaks are supported, but the text is generally unformatted.
  3835. class Window_UnformattedTextPokemon < SpriteWindow_Base
  3836.   attr_reader :text
  3837.   attr_reader :baseColor
  3838.   attr_reader :shadowColor
  3839.   # Letter-by-letter mode.  This mode is not supported in this class.
  3840.   attr_accessor :letterbyletter
  3841.  
  3842.   def text=(value)
  3843.     @text=value
  3844.     refresh
  3845.   end
  3846.  
  3847.   def baseColor=(value)
  3848.     @baseColor=value
  3849.     refresh
  3850.   end
  3851.  
  3852.   def shadowColor=(value)
  3853.     @shadowColor=value
  3854.     refresh
  3855.   end
  3856.  
  3857.   def initialize(text="")
  3858.     super(0,0,33,33)
  3859.     self.contents=Bitmap.new(1,1)
  3860.     pbSetSystemFont(self.contents)
  3861.     @text=text
  3862.     @letterbyletter=false # Not supported in this class
  3863.     colors=getDefaultTextColors(self.windowskin)
  3864.     @baseColor=colors[0]
  3865.     @shadowColor=colors[1]
  3866.     resizeToFit(text)
  3867.   end
  3868.  
  3869.   def self.newWithSize(text,x,y,width,height,viewport=nil)
  3870.     ret=self.new(text)
  3871.     ret.x=x
  3872.     ret.y=y
  3873.     ret.width=width
  3874.     ret.height=height
  3875.     ret.viewport=viewport
  3876.     ret.refresh
  3877.     return ret
  3878.   end
  3879.  
  3880.   def resizeToFitInternal(text,maxwidth) # maxwidth is maximum acceptable window width
  3881.     dims=[0,0]
  3882.     cwidth=maxwidth<0 ? Graphics.width : maxwidth
  3883.     getLineBrokenChunks(self.contents,text,
  3884.        cwidth-self.borderX-SpriteWindow_Base::TEXTPADDING,dims,true)
  3885.     return dims
  3886.   end
  3887.  
  3888.   def setTextToFit(text,maxwidth=-1)
  3889.     resizeToFit(text,maxwidth)
  3890.     self.text=text
  3891.   end
  3892.  
  3893.   def resizeToFit(text,maxwidth=-1) # maxwidth is maximum acceptable window width
  3894.     dims=resizeToFitInternal(text,maxwidth)
  3895.     self.width=dims[0]+self.borderX+SpriteWindow_Base::TEXTPADDING
  3896.     self.height=dims[1]+self.borderY
  3897.     refresh
  3898.   end
  3899.  
  3900.   def resizeHeightToFit(text,width=-1) # width is current window width
  3901.     dims=resizeToFitInternal(text,width)
  3902.     self.width=width<0 ? Graphics.width : width
  3903.     self.height=dims[1]+self.borderY
  3904.     refresh
  3905.   end
  3906.  
  3907.   def refresh
  3908.     self.contents=pbDoEnsureBitmap(self.contents,self.width-self.borderX,
  3909.        self.height-self.borderY)
  3910.     self.contents.clear
  3911.     drawTextEx(self.contents,0,0,self.contents.width,0,
  3912.        @text.gsub(/\r/,""),@baseColor,@shadowColor)
  3913.   end
  3914. end
  3915.  
  3916.  
  3917.  
  3918. class Window_AdvancedTextPokemon < SpriteWindow_Base
  3919.   attr_reader :text
  3920.   attr_reader :baseColor
  3921.   attr_reader :shadowColor
  3922.   attr_accessor :letterbyletter
  3923.   attr_reader :lineHeight
  3924.  
  3925.   def lineHeight(value)
  3926.     @lineHeight=value
  3927.     self.text=self.text
  3928.   end
  3929.  
  3930.   def text=(value)
  3931.     setText(value)
  3932.   end
  3933.  
  3934.   def textspeed
  3935.     @frameskip
  3936.   end
  3937.  
  3938.   def textspeed=(value)
  3939.     @frameskip=value
  3940.     @frameskipChanged=true
  3941.   end
  3942.  
  3943.   def waitcount
  3944.     @waitcount
  3945.   end
  3946.  
  3947.   def waitcount=(value)
  3948.     @waitcount=(value<=0) ? 0 : value
  3949.   end
  3950.  
  3951.   def setText(value)
  3952.     @waitcount=0
  3953.     @curchar=0
  3954.     @drawncurchar=-1
  3955.     @lastDrawnChar=-1
  3956.     oldtext=@text
  3957.     @text=value
  3958.     @textlength=unformattedTextLength(value)
  3959.     @scrollstate=0
  3960.     @scrollY=0
  3961.     @linesdrawn=0
  3962.     @realframes=0
  3963.     @textchars=[]
  3964.     width=1
  3965.     height=1
  3966.     numlines=0
  3967.     visiblelines=(self.height-self.borderY)/32
  3968.     if value.length==0
  3969.       @fmtchars=[]
  3970.       @bitmapwidth=width
  3971.       @bitmapheight=height
  3972.       @numtextchars=0
  3973.     else
  3974.       if !@letterbyletter
  3975.         @fmtchars=getFormattedText(self.contents,0,0,
  3976.            self.width-self.borderX-SpriteWindow_Base::TEXTPADDING,-1,
  3977.            shadowctag(@baseColor,@shadowColor)+value,32,true)
  3978.         @oldfont=self.contents.font.clone
  3979.         for ch in @fmtchars
  3980.           chx=ch[1]+ch[3]
  3981.           chy=ch[2]+ch[4]
  3982.           width=chx if width<chx
  3983.           height=chy if height<chy
  3984.           @textchars.push(ch[5] ? "" : ch[0])
  3985.         end
  3986.       else
  3987.         @fmtchars=[]
  3988.         fmt=getFormattedText(self.contents,0,0,
  3989.            self.width-self.borderX-SpriteWindow_Base::TEXTPADDING,-1,
  3990.            shadowctag(@baseColor,@shadowColor)+value,32,true)
  3991.         @oldfont=self.contents.font.clone
  3992.         for ch in fmt
  3993.           chx=ch[1]+ch[3]
  3994.           chy=ch[2]+ch[4]
  3995.           width=chx if width<chx
  3996.           height=chy if height<chy
  3997.           if !ch[5] && ch[0]=="\n" && @letterbyletter
  3998.             numlines+=1
  3999.             if numlines>=visiblelines
  4000.               fclone=ch.clone
  4001.               fclone[0]="\1"
  4002.               @fmtchars.push(fclone)
  4003.               @textchars.push("\1")
  4004.             end
  4005.           end
  4006.           # Don't add newline characters, since they
  4007.           # can slow down letter-by-letter display
  4008.           if ch[5] || (ch[0]!="\r")
  4009.             @fmtchars.push(ch)
  4010.             @textchars.push(ch[5] ? "" : ch[0])
  4011.           end
  4012.         end
  4013.         fmt.clear
  4014.       end
  4015.       @bitmapwidth=width
  4016.       @bitmapheight=height
  4017.       @numtextchars=@textchars.length
  4018.     end
  4019.     stopPause
  4020.     @displaying=@letterbyletter
  4021.     @needclear=true
  4022.     @nodraw=@letterbyletter
  4023.     refresh
  4024.   end
  4025.  
  4026.   def baseColor=(value)
  4027.     @baseColor=value
  4028.     refresh
  4029.   end
  4030.  
  4031.   def shadowColor=(value)
  4032.     @shadowColor=value
  4033.     refresh
  4034.   end
  4035.  
  4036.   def busy?
  4037.     return @displaying
  4038.   end
  4039.  
  4040.   def pausing?
  4041.     return @pausing && @displaying
  4042.   end
  4043.  
  4044.   def resume
  4045.     if !busy?
  4046.       self.stopPause
  4047.       return true
  4048.     end
  4049.     if @pausing
  4050.       @pausing=false
  4051.       self.stopPause
  4052.       return false
  4053.     else
  4054.       return true
  4055.     end
  4056.   end
  4057.  
  4058.   def dispose
  4059.     return if disposed?
  4060.     @pausesprite.dispose if @pausesprite
  4061.     @pausesprite=nil
  4062.     super
  4063.   end
  4064.  
  4065.   attr_reader :cursorMode
  4066.  
  4067.   def cursorMode=(value)
  4068.     @cursorMode=value
  4069.     moveCursor
  4070.   end
  4071.  
  4072.   def moveCursor
  4073.     if @pausesprite
  4074.       cursor=@cursorMode
  4075.       cursor=2 if cursor==0 && !@endOfText
  4076.       case cursor
  4077.       when 0 # End of text
  4078.         @pausesprite.x=self.x+self.startX+@endOfText.x+@endOfText.width-2
  4079.         @pausesprite.y=self.y+self.startY+@endOfText.y-@scrollY
  4080.       when 1 # Lower right
  4081.         pauseWidth=@pausesprite.bitmap ? @pausesprite.framewidth : 16
  4082.         pauseHeight=@pausesprite.bitmap ? @pausesprite.frameheight : 16
  4083.         @pausesprite.x=self.x+self.width-(20*2)+(pauseWidth/2)
  4084.         @pausesprite.y=self.y+self.height-(30*2)+(pauseHeight/2)
  4085.       when 2 # Lower middle
  4086.         pauseWidth=@pausesprite.bitmap ? @pausesprite.framewidth : 16
  4087.         pauseHeight=@pausesprite.bitmap ? @pausesprite.frameheight : 16
  4088.         @pausesprite.x=self.x+(self.width/2)-(pauseWidth/2)
  4089.         @pausesprite.y=self.y+self.height-(18*2)+(pauseHeight/2)
  4090.       end
  4091.     end
  4092.   end
  4093.  
  4094.   def initialize(text="")
  4095.     @cursorMode=MessageConfig::CURSORMODE
  4096.     @endOfText=nil
  4097.     @scrollstate=0
  4098.     @realframes=0
  4099.     @scrollY=0
  4100.     @nodraw=false
  4101.     @lineHeight=32
  4102.     @linesdrawn=0
  4103.     @bufferbitmap=nil
  4104.     @letterbyletter=false
  4105.     @starting=true
  4106.     @displaying=false
  4107.     @lastDrawnChar=-1
  4108.     @fmtchars=[]
  4109.     @frameskipChanged=false
  4110.     @frameskip=MessageConfig.pbGetTextSpeed()
  4111.     super(0,0,33,33)
  4112.     @pausesprite=nil
  4113.     @text=""
  4114.     self.contents=Bitmap.new(1,1)
  4115.     pbSetSystemFont(self.contents)
  4116.     self.resizeToFit(text,Graphics.width)
  4117.     colors=getDefaultTextColors(self.windowskin)
  4118.     @baseColor=colors[0]
  4119.     @shadowColor=colors[1]
  4120.     self.text=text
  4121.     @starting=false
  4122.   end
  4123.  
  4124.   def self.newWithSize(text,x,y,width,height,viewport=nil)
  4125.     ret=self.new(text)
  4126.     ret.x=x
  4127.     ret.y=y
  4128.     ret.width=width
  4129.     ret.height=height
  4130.     ret.viewport=viewport
  4131.     return ret
  4132.   end
  4133.  
  4134.   def width=(value)
  4135.     super
  4136.     if !@starting
  4137.       self.text=self.text
  4138.     end
  4139.   end
  4140.  
  4141.   def height=(value)
  4142.     super
  4143.     if !@starting
  4144.       self.text=self.text
  4145.     end
  4146.   end
  4147.  
  4148.   def resizeToFitInternal(text,maxwidth)
  4149.     dims=[0,0]
  4150.     cwidth=maxwidth<0 ? Graphics.width : maxwidth
  4151.     chars=getFormattedTextForDims(self.contents,0,0,
  4152.        cwidth-self.borderX-2-6,-1,text,@lineHeight,true)
  4153.     for ch in chars
  4154.       dims[0]=[dims[0],ch[1]+ch[3]].max
  4155.       dims[1]=[dims[1],ch[2]+ch[4]].max
  4156.     end
  4157.     return dims
  4158.   end
  4159.  
  4160.   def resizeToFit2(text,maxwidth,maxheight)
  4161.     dims=resizeToFitInternal(text,maxwidth)
  4162.     oldstarting=@starting
  4163.     @starting=true
  4164.     self.width=[dims[0]+self.borderX+SpriteWindow_Base::TEXTPADDING,maxwidth].min
  4165.     self.height=[dims[1]+self.borderY,maxheight].min
  4166.     @starting=oldstarting
  4167.     redrawText
  4168.   end
  4169.  
  4170.   def setTextToFit(text,maxwidth=-1)
  4171.     resizeToFit(text,maxwidth)
  4172.     self.text=text
  4173.   end
  4174.  
  4175.   def resizeToFit(text,maxwidth=-1)
  4176.     dims=resizeToFitInternal(text,maxwidth)
  4177.     oldstarting=@starting
  4178.     @starting=true
  4179.     self.width=dims[0]+self.borderX+SpriteWindow_Base::TEXTPADDING
  4180.     self.height=dims[1]+self.borderY
  4181.     @starting=oldstarting
  4182.     redrawText
  4183.   end
  4184.  
  4185.   def resizeHeightToFit(text,width=-1)
  4186.     dims=resizeToFitInternal(text,width)
  4187.     oldstarting=@starting
  4188.     @starting=true
  4189.     self.width=width<0 ? Graphics.width : width
  4190.     self.height=dims[1]+self.borderY
  4191.     @starting=oldstarting
  4192.     redrawText
  4193.   end
  4194.  
  4195.   def refresh
  4196.     oldcontents=self.contents
  4197.     self.contents=pbDoEnsureBitmap(oldcontents,@bitmapwidth,@bitmapheight)
  4198.     self.oy=@scrollY
  4199.     numchars=@numtextchars
  4200.     startchar=0
  4201.     numchars=[@curchar,@numtextchars].min if self.letterbyletter
  4202.     if busy? && @drawncurchar==@curchar && @scrollstate==0
  4203.       return
  4204.     end
  4205.     if !self.letterbyletter || !oldcontents.equal?(self.contents)
  4206.       @drawncurchar=-1
  4207.       @needclear=true
  4208.     end
  4209.     if @needclear
  4210.       self.contents.font=@oldfont if @oldfont
  4211.       self.contents.clear
  4212.       @needclear=false
  4213.     end
  4214.     if @nodraw
  4215.       @nodraw=false
  4216.       return
  4217.     end
  4218.     maxX=self.width-self.borderX
  4219.     maxY=self.height-self.borderY
  4220.     for i in @drawncurchar+1..numchars
  4221.       next if i>=@fmtchars.length
  4222.       if !self.letterbyletter
  4223.         next if @fmtchars[i][1]>=maxX
  4224.         next if @fmtchars[i][2]>=maxY
  4225.       end
  4226.       drawSingleFormattedChar(self.contents,@fmtchars[i])
  4227.       @lastDrawnChar=i
  4228.     end
  4229.     if !self.letterbyletter
  4230.       # all characters were drawn, reset old font
  4231.       self.contents.font=@oldfont if @oldfont
  4232.     end
  4233.     if numchars>0 && numchars!=@numtextchars
  4234.       fch=@fmtchars[numchars-1]
  4235.       if fch
  4236.         rcdst=Rect.new(fch[1],fch[2],fch[3],fch[4])
  4237.         if @textchars[numchars]=="\1"
  4238.           @endOfText=rcdst
  4239.           allocPause
  4240.           moveCursor()
  4241.         else
  4242.           @endOfText=Rect.new(rcdst.x+rcdst.width,rcdst.y,8,1)
  4243.         end
  4244.       end
  4245.     end
  4246.     @drawncurchar=@curchar
  4247.   end
  4248.  
  4249.   def maxPosition
  4250.     pos=0
  4251.     for ch in @fmtchars
  4252.       # index after the last character's index
  4253.       pos=ch[14]+1 if pos<ch[14]+1
  4254.     end
  4255.     return pos
  4256.   end
  4257.  
  4258.   def position
  4259.     if @lastDrawnChar<0
  4260.       return 0
  4261.     elsif @lastDrawnChar>=@fmtchars.length
  4262.       return @numtextchars
  4263.     else
  4264.       # index after the last character's index
  4265.       return @fmtchars[@lastDrawnChar][14]+1
  4266.     end
  4267.   end
  4268.  
  4269.   def redrawText
  4270.     if !@letterbyletter
  4271.       self.text=self.text
  4272.     else
  4273.       oldPosition=self.position
  4274.       self.text=self.text
  4275.       oldPosition=@numtextchars if oldPosition>@numtextchars
  4276.       while self.position!=oldPosition
  4277.         refresh
  4278.         updateInternal
  4279.       end
  4280.     end
  4281.   end
  4282.  
  4283.   def updateInternal
  4284.     curcharskip=@frameskip<0 ? @frameskip.abs : 1
  4285.     visiblelines=(self.height-self.borderY)/@lineHeight
  4286.     if @textchars[@curchar]=="\1"
  4287.       if !@pausing
  4288.         @realframes+=1
  4289.         if @realframes>=@frameskip || @frameskip<0
  4290.           curcharSkip(curcharskip)
  4291.           @realframes=0
  4292.         end
  4293.       end
  4294.     elsif @textchars[@curchar]=="\n"
  4295.       if @linesdrawn>=visiblelines-1
  4296.         if @scrollstate<@lineHeight
  4297.           @scrollstate+=[(@lineHeight/4),1].max
  4298.           @scrollY+=[(@lineHeight/4),1].max
  4299.         end
  4300.         if @scrollstate>=@lineHeight
  4301.           @realframes+=1
  4302.           if @realframes>=@frameskip || @frameskip<0
  4303.             curcharSkip(curcharskip)
  4304.             @linesdrawn+=1
  4305.             @scrollstate=0
  4306.             @realframes=0
  4307.           end
  4308.         end
  4309.       else
  4310.         @realframes+=1
  4311.         if @realframes>=@frameskip || @frameskip<0
  4312.           curcharSkip(curcharskip)
  4313.           @linesdrawn+=1
  4314.           @realframes=0
  4315.         end
  4316.       end
  4317.     elsif @curchar<=@numtextchars
  4318.       @realframes+=1
  4319.       if @realframes>=@frameskip || @frameskip<0
  4320.         curcharSkip(curcharskip)
  4321.         @realframes=0
  4322.       end
  4323.       if @textchars[@curchar]=="\1"
  4324.         @pausing=true if @curchar<@numtextchars-1
  4325.         self.startPause
  4326.         refresh
  4327.       end
  4328.     else
  4329.       @displaying=false
  4330.       @scrollstate=0
  4331.       @scrollY=0
  4332.       @linesdrawn=0
  4333.     end
  4334.   end
  4335.  
  4336.   def update
  4337.     super
  4338.     if @pausesprite && @pausesprite.visible
  4339.       @pausesprite.update
  4340.     end
  4341.     if @waitcount>0
  4342.       @waitcount-=1
  4343.       return
  4344.     end
  4345.     if busy?
  4346.       refresh if !@frameskipChanged
  4347.       updateInternal
  4348.       # following line needed to allow "textspeed=-999" to work seamlessly
  4349.       refresh if @frameskipChanged
  4350.     end
  4351.     @frameskipChanged=false
  4352.   end
  4353.  
  4354.   def allocPause
  4355.     if !@pausesprite
  4356.       @pausesprite=AnimatedSprite.create("Graphics/Pictures/pause",4,3)
  4357.       @pausesprite.z=100000
  4358.       @pausesprite.visible=false
  4359.     end
  4360.   end
  4361.  
  4362.   def startPause
  4363.     allocPause
  4364.     @pausesprite.visible=true
  4365.     @pausesprite.frame=0
  4366.     @pausesprite.start
  4367.     moveCursor
  4368.   end
  4369.  
  4370.   def stopPause
  4371.     if @pausesprite
  4372.       @pausesprite.stop
  4373.       @pausesprite.visible=false
  4374.     end
  4375.   end
  4376.  
  4377.   private
  4378.  
  4379.   def curcharSkip(skip)
  4380.     skip.times do
  4381.       @curchar+=1
  4382.       break if @textchars[@curchar]=="\n" || # newline
  4383.                @textchars[@curchar]=="\1" || # pause
  4384.                @textchars[@curchar]=="\2" || # letter-by-letter break
  4385.                @textchars[@curchar]==nil
  4386.     end
  4387.   end
  4388. end
  4389.  
  4390.  
  4391.  
  4392. class Window_InputNumberPokemon < SpriteWindow_Base
  4393.   attr_reader :number
  4394.   attr_reader :sign
  4395.  
  4396.   def initialize(digits_max)
  4397.     @digits_max=digits_max
  4398.     @number=0
  4399.     @frame=0
  4400.     @sign=false
  4401.     @negative=false
  4402.     super(0,0,32,32)
  4403.     self.width=digits_max*24+8+self.borderX
  4404.     self.height=32+self.borderY
  4405.     colors=getDefaultTextColors(self.windowskin)
  4406.     @baseColor=colors[0]
  4407.     @shadowColor=colors[1]
  4408.     @index=digits_max-1
  4409.     self.active=true
  4410.     refresh
  4411.   end
  4412.  
  4413.   def active=(value)
  4414.     super
  4415.     refresh
  4416.   end
  4417.  
  4418.   def number
  4419.     @number*(@sign && @negative ? -1 : 1)
  4420.   end
  4421.  
  4422.   def sign=(value)
  4423.     @sign=value
  4424.     self.width=@digits_max*24+8+self.borderX+(@sign ? 24 : 0)
  4425.     @index=(@digits_max-1)+(@sign ? 1 : 0)
  4426.     refresh
  4427.   end
  4428.  
  4429.   def number=(value)
  4430.     value=0 if !value.is_a?(Numeric)
  4431.     if @sign
  4432.       @negative=(value<0)
  4433.       @number = [value.abs, 10 ** @digits_max - 1].min
  4434.     else
  4435.       @number = [[value, 0].max, 10 ** @digits_max - 1].min
  4436.     end
  4437.     refresh
  4438.   end
  4439.  
  4440.   def refresh
  4441.     self.contents=pbDoEnsureBitmap(self.contents,
  4442.        self.width-self.borderX,self.height-self.borderY)
  4443.     pbSetSystemFont(self.contents)
  4444.     self.contents.clear
  4445.     s=sprintf("%0*d",@digits_max,@number.abs)
  4446.     x=0
  4447.     if @sign
  4448.       textHelper(0,0,@negative ? "-" : "+",0)
  4449.     end
  4450.     for i in 0...@digits_max
  4451.       index=i+(@sign ? 1 : 0)
  4452.       textHelper(index*24,0,s[i,1],index)
  4453.     end
  4454.   end
  4455.  
  4456.   def update
  4457.     super
  4458.     digits=@digits_max+(@sign ? 1 : 0)
  4459.     refresh if @frame%15==0
  4460.     if self.active
  4461.       if Input.repeat?(Input::UP) or Input.repeat?(Input::DOWN)
  4462.         pbPlayCursorSE()
  4463.         if @index==0 && @sign
  4464.           @negative=!@negative
  4465.         else
  4466.           place = 10 ** (digits - 1 - @index)
  4467.           n = @number / place % 10
  4468.           @number -= n*place
  4469.           if Input.repeat?(Input::UP)
  4470.             n = (n + 1) % 10
  4471.           elsif Input.repeat?(Input::DOWN)
  4472.             n = (n + 9) % 10
  4473.           end
  4474.           @number += n*place
  4475.         end
  4476.         refresh
  4477.       elsif Input.repeat?(Input::RIGHT)
  4478.         if digits >= 2
  4479.           pbPlayCursorSE()
  4480.           @index = (@index + 1) % digits
  4481.           @frame=0
  4482.           refresh
  4483.         end
  4484.       elsif Input.repeat?(Input::LEFT)
  4485.         if digits >= 2
  4486.           pbPlayCursorSE()
  4487.           @index = (@index + digits - 1) % digits
  4488.           @frame=0
  4489.           refresh
  4490.         end
  4491.       end
  4492.     end
  4493.     @frame=(@frame+1)%30
  4494.   end
  4495.  
  4496.   private
  4497.  
  4498.   def textHelper(x,y,text,i)
  4499.     textwidth=self.contents.text_size(text).width
  4500.     self.contents.font.color=@shadowColor
  4501.     pbDrawShadow(self.contents,x+(12-textwidth/2),y, textwidth+4, 32, text)
  4502.     self.contents.font.color=@baseColor
  4503.     self.contents.draw_text(x+(12-textwidth/2),y, textwidth+4, 32, text)    
  4504.     if @index==i && @active && @frame/15==0
  4505.       colors=getDefaultTextColors(self.windowskin)
  4506.       self.contents.fill_rect(x+(12-textwidth/2),y+30,textwidth,2,colors[0])
  4507.     end
  4508.   end
  4509. end
  4510.  
  4511.  
  4512.  
  4513. class AnimatedSprite < SpriteWrapper
  4514.   attr_reader :frame
  4515.   attr_reader :framewidth
  4516.   attr_reader :frameheight
  4517.   attr_reader :framecount
  4518.   attr_reader :animname
  4519.  
  4520.   def initializeLong(animname,framecount,framewidth,frameheight,frameskip)
  4521.     @animname=pbBitmapName(animname)
  4522.     @realframes=0
  4523.     @frameskip=[1,frameskip].max
  4524.     raise _INTL("Frame width is 0") if framewidth==0
  4525.     raise _INTL("Frame height is 0") if frameheight==0
  4526.     begin
  4527.       @animbitmap=AnimatedBitmap.new(animname).deanimate
  4528.     rescue
  4529.       @animbitmap=Bitmap.new(framewidth,frameheight)
  4530.     end
  4531.     if @animbitmap.width%framewidth!=0
  4532.       raise _INTL("Bitmap's width ({1}) is not a multiple of frame width ({2}) [Bitmap={3}]",
  4533.          @animbitmap.width,framewidth,animname)
  4534.     end
  4535.     if @animbitmap.height%frameheight!=0
  4536.       raise _INTL("Bitmap's height ({1}) is not a multiple of frame height ({2}) [Bitmap={3}]",
  4537.          @animbitmap.height,frameheight,animname)
  4538.     end
  4539.     @framecount=framecount
  4540.     @framewidth=framewidth
  4541.     @frameheight=frameheight
  4542.     @framesperrow=@animbitmap.width/@framewidth
  4543.     @playing=false
  4544.     self.bitmap=@animbitmap
  4545.     self.src_rect.width=@framewidth
  4546.     self.src_rect.height=@frameheight
  4547.     self.frame=0
  4548.   end
  4549.  
  4550.   # Shorter version of AnimationSprite.  All frames are placed on a single row
  4551.   # of the bitmap, so that the width and height need not be defined beforehand
  4552.   def initializeShort(animname,framecount,frameskip)
  4553.     @animname=pbBitmapName(animname)
  4554.     @realframes=0
  4555.     @frameskip=[1,frameskip].max
  4556.     begin
  4557.       @animbitmap=AnimatedBitmap.new(animname).deanimate
  4558.     rescue
  4559.       @animbitmap=Bitmap.new(framecount*4,32)
  4560.     end
  4561.     if @animbitmap.width%framecount!=0
  4562.       raise _INTL("Bitmap's width ({1}) is not a multiple of frame count ({2}) [Bitmap={3}]",
  4563.          @animbitmap.width,framewidth,animname)
  4564.     end
  4565.     @framecount=framecount
  4566.     @framewidth=@animbitmap.width/@framecount
  4567.     @frameheight=@animbitmap.height
  4568.     @framesperrow=framecount
  4569.     @playing=false
  4570.     self.bitmap=@animbitmap
  4571.     self.src_rect.width=@framewidth
  4572.     self.src_rect.height=@frameheight
  4573.     self.frame=0
  4574.   end
  4575.  
  4576.   def initialize(*args)
  4577.     if args.length==1
  4578.       super(args[0][3])
  4579.       initializeShort(args[0][0],args[0][1],args[0][2])
  4580.     else
  4581.       super(args[5])
  4582.       initializeLong(args[0],args[1],args[2],args[3],args[4])
  4583.     end
  4584.   end
  4585.  
  4586.   def self.create(animname,framecount,frameskip,viewport=nil)
  4587.     return self.new([animname,framecount,frameskip,viewport])
  4588.   end
  4589.  
  4590.   def dispose
  4591.     return if disposed?
  4592.     @animbitmap.dispose
  4593.     @animbitmap=nil
  4594.     super
  4595.   end
  4596.  
  4597.   def playing?
  4598.     return @playing
  4599.   end
  4600.  
  4601.   def frame=(value)
  4602.     @frame=value
  4603.     @realframes=0
  4604.     self.src_rect.x=@frame%@framesperrow*@framewidth
  4605.     self.src_rect.y=@frame/@framesperrow*@frameheight
  4606.   end
  4607.  
  4608.   def start
  4609.     @playing=true
  4610.     @realframes=0
  4611.   end
  4612.  
  4613.   alias play start
  4614.  
  4615.   def stop
  4616.     @playing=false
  4617.   end
  4618.  
  4619.   def update
  4620.     super
  4621.     if @playing
  4622.       @realframes+=1
  4623.       if @realframes==@frameskip
  4624.         @realframes=0
  4625.         self.frame+=1
  4626.         self.frame%=self.framecount
  4627.       end
  4628.     end
  4629.   end
  4630. end
  4631.  
  4632.  
  4633.  
  4634. # Displays an icon bitmap in a sprite. Supports animated images.
  4635. class IconSprite < SpriteWrapper
  4636.   attr_reader :name
  4637.  
  4638.   def initialize(*args)
  4639.     if args.length==0
  4640.       super(nil)
  4641.       self.bitmap=nil
  4642.     elsif args.length==1
  4643.       super(args[0])
  4644.       self.bitmap=nil
  4645.     elsif args.length==2
  4646.       super(nil)
  4647.       self.x=args[0]
  4648.       self.y=args[1]
  4649.     else
  4650.       super(args[2])
  4651.       self.x=args[0]
  4652.       self.y=args[1]
  4653.     end
  4654.     @name=""
  4655.     @_iconbitmap=nil
  4656.   end
  4657.  
  4658.   def dispose
  4659.     clearBitmaps()
  4660.     super
  4661.   end
  4662.  
  4663.   def update
  4664.     super
  4665.     if @_iconbitmap
  4666.       @_iconbitmap.update
  4667.       if self.bitmap!=@_iconbitmap.bitmap
  4668.         oldrc=self.src_rect
  4669.         self.bitmap=@_iconbitmap.bitmap
  4670.         self.src_rect=oldrc
  4671.       end
  4672.     end
  4673.   end
  4674.  
  4675.   def clearBitmaps
  4676.     @_iconbitmap.dispose if @_iconbitmap
  4677.     @_iconbitmap=nil
  4678.     self.bitmap=nil if !self.disposed?
  4679.   end
  4680.  
  4681.   # Sets the icon's filename.  Alias for setBitmap.
  4682.   def name=(value)
  4683.     setBitmap(value)
  4684.   end
  4685.  
  4686.   # Sets the icon's filename.
  4687.   def setBitmap(file,hue=0)
  4688.     oldrc=self.src_rect
  4689.     clearBitmaps()
  4690.     @name=file
  4691.     return if file==nil
  4692.     if file!=""
  4693.       @_iconbitmap=AnimatedBitmap.new(file,hue)
  4694.       # for compatibility
  4695.       self.bitmap=@_iconbitmap ? @_iconbitmap.bitmap : nil
  4696.       self.src_rect=oldrc
  4697.     else
  4698.       @_iconbitmap=nil
  4699.     end
  4700.   end
  4701. end
  4702.  
  4703.  
  4704.  
  4705. # Old GifSprite class, retained for compatibility
  4706. class GifSprite < IconSprite
  4707.   def initialize(path)
  4708.     super(0,0)
  4709.     setBitmap(path)
  4710.   end
  4711. end
  4712.  
  4713.  
  4714.  
  4715. # Sprite class that maintains a bitmap of its own.
  4716. # This bitmap can't be changed to a different one.
  4717. class BitmapSprite < SpriteWrapper
  4718.   def initialize(width,height,viewport=nil)
  4719.     super(viewport)
  4720.     self.bitmap=Bitmap.new(width,height)
  4721.     @initialized=true
  4722.   end
  4723.  
  4724.   def bitmap=(value)
  4725.     super(value) if !@initialized
  4726.   end
  4727.  
  4728.   def dispose
  4729.     self.bitmap.dispose if !self.disposed?
  4730.     super
  4731.   end
  4732. end
  4733.  
  4734.  
  4735.  
  4736. class Plane
  4737.   def update; end
  4738.   def refresh; end
  4739. end
  4740.  
  4741.  
  4742.  
  4743. # This class works around a limitation that planes are always
  4744. # 640 by 480 pixels in size regardless of the window's size.
  4745. class LargePlane < Plane
  4746.   attr_accessor :borderX
  4747.   attr_accessor :borderY
  4748.  
  4749.   def initialize(viewport=nil)
  4750.     @__sprite=Sprite.new(viewport)
  4751.     @__disposed=false
  4752.     @__ox=0
  4753.     @__oy=0
  4754.     @__bitmap=nil
  4755.     @__visible=true
  4756.     @__sprite.visible=false
  4757.     @borderX=0
  4758.     @borderY=0
  4759.   end
  4760.  
  4761.   def disposed?
  4762.     return @__disposed
  4763.   end
  4764.  
  4765.   def dispose
  4766.     if !@__disposed
  4767.       @__sprite.bitmap.dispose if @__sprite.bitmap
  4768.       @__sprite.dispose
  4769.       @__sprite=nil
  4770.       @__bitmap=nil
  4771.       @__disposed=true
  4772.     end
  4773.     super
  4774.   end
  4775.  
  4776.   def ox; @__ox; end
  4777.   def oy; @__oy; end
  4778.  
  4779.   def ox=(value);
  4780.     if @__ox!=value
  4781.       @__ox=value; refresh
  4782.     end
  4783.   end
  4784.  
  4785.   def oy=(value);
  4786.     if @__oy!=value
  4787.       @__oy=value; refresh
  4788.     end
  4789.   end
  4790.  
  4791.   def bitmap
  4792.     return @__bitmap
  4793.   end
  4794.  
  4795.   def bitmap=(value)
  4796.     if value==nil
  4797.       if @__bitmap!=nil
  4798.         @__bitmap=nil
  4799.         @__sprite.visible=(@__visible && !@__bitmap.nil?)
  4800.       end
  4801.     elsif @__bitmap!=value && !value.disposed?
  4802.       @__bitmap=value
  4803.       refresh
  4804.     elsif value.disposed?
  4805.       if @__bitmap!=nil
  4806.         @__bitmap=nil
  4807.         @__sprite.visible=(@__visible && !@__bitmap.nil?)
  4808.       end
  4809.     end
  4810.   end
  4811.  
  4812.   def viewport; @__sprite.viewport; end
  4813.   def zoom_x; @__sprite.zoom_x; end
  4814.   def zoom_y; @__sprite.zoom_y; end
  4815.   def opacity; @__sprite.opacity; end
  4816.   def blend_type; @__sprite.blend_type; end
  4817.   def visible; @__visible; end
  4818.   def z; @__sprite.z; end
  4819.   def color; @__sprite.color; end
  4820.   def tone; @__sprite.tone; end
  4821.  
  4822.   def zoom_x=(v);
  4823.     if @__sprite.zoom_x!=v
  4824.       @__sprite.zoom_x=v; refresh
  4825.     end
  4826.   end
  4827.  
  4828.   def zoom_y=(v);
  4829.     if @__sprite.zoom_y!=v
  4830.       @__sprite.zoom_y=v; refresh
  4831.     end
  4832.   end
  4833.  
  4834.   def opacity=(v); @__sprite.opacity=(v); end
  4835.   def blend_type=(v); @__sprite.blend_type=(v); end
  4836.   def visible=(v); @__visible=v; @__sprite.visible=(@__visible && !@__bitmap.nil?); end
  4837.   def z=(v); @__sprite.z=(v); end
  4838.   def color=(v); @__sprite.color=(v); end
  4839.   def tone=(v); @__sprite.tone=(v); end
  4840.   def update; ;end
  4841.  
  4842.   def refresh
  4843.     @__sprite.visible=(@__visible && !@__bitmap.nil?)
  4844.     if @__bitmap
  4845.       if !@__bitmap.disposed?
  4846.         @__ox+=@__bitmap.width*@__sprite.zoom_x if @__ox<0
  4847.         @__oy+=@__bitmap.height*@__sprite.zoom_y if @__oy<0
  4848.         @__ox-=@__bitmap.width*@__sprite.zoom_x if @__ox>@__bitmap.width
  4849.         @__oy-=@__bitmap.height*@__sprite.zoom_y if @__oy>@__bitmap.height
  4850.         dwidth=(Graphics.width/@__sprite.zoom_x+@borderX).to_i # +2
  4851.         dheight=(Graphics.height/@__sprite.zoom_y+@borderY).to_i # +2
  4852.         @__sprite.bitmap=ensureBitmap(@__sprite.bitmap,dwidth,dheight)
  4853.         @__sprite.bitmap.clear
  4854.         tileBitmap(@__sprite.bitmap,@__bitmap,@__bitmap.rect)
  4855.       else
  4856.         @__sprite.visible=false
  4857.       end
  4858.     end
  4859.   end
  4860.  
  4861.   private
  4862.  
  4863.   def ensureBitmap(bitmap,dwidth,dheight)
  4864.     if !bitmap||bitmap.disposed?||bitmap.width<dwidth||bitmap.height<dheight
  4865.       bitmap.dispose if bitmap
  4866.       bitmap=Bitmap.new([1,dwidth].max,[1,dheight].max)
  4867.     end
  4868.     return bitmap
  4869.   end
  4870.  
  4871.   def tileBitmap(dstbitmap,srcbitmap,srcrect)
  4872.     return if !srcbitmap || srcbitmap.disposed?
  4873.     dstrect=dstbitmap.rect
  4874.     left=dstrect.x-@__ox/@__sprite.zoom_x
  4875.     top=dstrect.y-@__oy/@__sprite.zoom_y
  4876.     left=left.to_i; top=top.to_i
  4877.     while left>0; left-=srcbitmap.width; end
  4878.     while top>0; top-=srcbitmap.height; end
  4879.     y=top; while y<dstrect.height
  4880.       x=left; while x<dstrect.width
  4881.         dstbitmap.blt(x+@borderX,y+@borderY,srcbitmap,srcrect)
  4882.         x+=srcrect.width
  4883.       end
  4884.       y+=srcrect.height
  4885.     end
  4886.   end
  4887. end
  4888.  
  4889.  
  4890.  
  4891. # A plane class that displays a single color.
  4892. class ColoredPlane < LargePlane
  4893.   def initialize(color,viewport=nil)
  4894.     super(viewport)
  4895.     self.bitmap=Bitmap.new(32,32)
  4896.     setPlaneColor(color)
  4897.   end
  4898.  
  4899.   def dispose
  4900.     self.bitmap.dispose if self.bitmap
  4901.     super
  4902.   end
  4903.  
  4904.   def update; super; end
  4905.  
  4906.   def setPlaneColor(value)
  4907.     self.bitmap.fill_rect(0,0,self.bitmap.width,self.bitmap.height,value)
  4908.     self.refresh
  4909.   end
  4910. end
  4911.  
  4912.  
  4913.  
  4914. # A plane class that supports animated images.
  4915. class AnimatedPlane < LargePlane
  4916.   def initialize(viewport)
  4917.     super(viewport)
  4918.     @bitmap=nil
  4919.   end
  4920.  
  4921.   def dispose
  4922.     clearBitmaps()
  4923.     super
  4924.   end
  4925.  
  4926.   def update
  4927.     super
  4928.     if @bitmap
  4929.       @bitmap.update
  4930.       self.bitmap=@bitmap.bitmap
  4931.     end
  4932.   end
  4933.  
  4934.   def clearBitmaps
  4935.     @bitmap.dispose if @bitmap
  4936.     @bitmap=nil
  4937.     self.bitmap=nil if !self.disposed?
  4938.   end
  4939.  
  4940.   def setPanorama(file, hue=0)
  4941.     clearBitmaps()
  4942.     return if file==nil
  4943.     @bitmap=AnimatedBitmap.new("Graphics/Panoramas/"+file,hue)
  4944.   end
  4945.  
  4946.   def setFog(file, hue=0)
  4947.     clearBitmaps()
  4948.     return if file==nil
  4949.     @bitmap=AnimatedBitmap.new("Graphics/Fogs/"+file,hue)
  4950.   end
  4951.  
  4952.   def setBitmap(file, hue=0)
  4953.     clearBitmaps()
  4954.     return if file==nil
  4955.     @bitmap=AnimatedBitmap.new(file,hue)
  4956.   end
  4957. end
  4958.  
  4959.  
  4960.  
  4961. # Displays an icon bitmap in a window. Supports animated images.
  4962. class IconWindow < SpriteWindow_Base
  4963.   attr_reader :name
  4964.  
  4965.   def initialize(x,y,width,height,viewport=nil)
  4966.     super(x,y,width,height)
  4967.     self.viewport=viewport
  4968.     self.contents=nil
  4969.     @name=""
  4970.     @_iconbitmap=nil
  4971.   end
  4972.  
  4973.   def dispose
  4974.     clearBitmaps()
  4975.     super
  4976.   end
  4977.  
  4978.   def update
  4979.     super
  4980.     if @_iconbitmap
  4981.       @_iconbitmap.update
  4982.       self.contents=@_iconbitmap.bitmap
  4983.     end
  4984.   end
  4985.  
  4986.   def clearBitmaps
  4987.     @_iconbitmap.dispose if @_iconbitmap
  4988.     @_iconbitmap=nil
  4989.     self.contents=nil if !self.disposed?
  4990.   end
  4991.  
  4992.   # Sets the icon's filename.  Alias for setBitmap.
  4993.   def name=(value)
  4994.     setBitmap(value)
  4995.   end
  4996.  
  4997.   # Sets the icon's filename.
  4998.   def setBitmap(file,hue=0)
  4999.     clearBitmaps()
  5000.     @name=file
  5001.     return if file==nil
  5002.     if file!=""
  5003.       @_iconbitmap=AnimatedBitmap.new(file,hue)
  5004.       # for compatibility
  5005.       self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil
  5006.     else
  5007.       @_iconbitmap=nil
  5008.     end
  5009.   end
  5010. end
  5011.  
  5012.  
  5013.  
  5014. # Displays an icon bitmap in a window. Supports animated images.
  5015. # Accepts bitmaps and paths to bitmap files in its constructor
  5016. class PictureWindow < SpriteWindow_Base
  5017.   def initialize(pathOrBitmap)
  5018.     super(0,0,32,32)
  5019.     self.viewport=viewport
  5020.     self.contents=nil
  5021.     @_iconbitmap=nil
  5022.     setBitmap(pathOrBitmap)
  5023.   end
  5024.  
  5025.   def dispose
  5026.     clearBitmaps()
  5027.     super
  5028.   end
  5029.  
  5030.   def update
  5031.     super
  5032.     if @_iconbitmap
  5033.       if @_iconbitmap.is_a?(Bitmap)
  5034.         self.contents=@_iconbitmap
  5035.       else
  5036.         @_iconbitmap.update
  5037.         self.contents=@_iconbitmap.bitmap
  5038.       end
  5039.     end
  5040.   end
  5041.  
  5042.   def clearBitmaps
  5043.     @_iconbitmap.dispose if @_iconbitmap
  5044.     @_iconbitmap=nil
  5045.     self.contents=nil if !self.disposed?
  5046.   end
  5047.  
  5048.   # Sets the icon's bitmap or filename. (hue parameter
  5049.   # is ignored unless pathOrBitmap is a filename)
  5050.   def setBitmap(pathOrBitmap,hue=0)
  5051.     clearBitmaps()
  5052.     if pathOrBitmap!=nil && pathOrBitmap!=""
  5053.       if pathOrBitmap.is_a?(Bitmap)
  5054.         @_iconbitmap=pathOrBitmap
  5055.         self.contents=@_iconbitmap
  5056.         self.width=@_iconbitmap.width+self.borderX
  5057.         self.height=@_iconbitmap.height+self.borderY
  5058.       elsif pathOrBitmap.is_a?(AnimatedBitmap)
  5059.         @_iconbitmap=pathOrBitmap
  5060.         self.contents=@_iconbitmap.bitmap
  5061.         self.width=@_iconbitmap.bitmap.width+self.borderX
  5062.         self.height=@_iconbitmap.bitmap.height+self.borderY
  5063.       else
  5064.         @_iconbitmap=AnimatedBitmap.new(pathOrBitmap,hue)
  5065.         self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil
  5066.         self.width=@_iconbitmap ? @_iconbitmap.bitmap.width+self.borderX :
  5067.            32+self.borderX
  5068.         self.height=@_iconbitmap ? @_iconbitmap.bitmap.height+self.borderY :
  5069.            32+self.borderY
  5070.       end
  5071.     else
  5072.       @_iconbitmap=nil
  5073.       self.width=32+self.borderX
  5074.       self.height=32+self.borderY
  5075.     end
  5076.   end
  5077. end
  5078.  
  5079.  
  5080.  
  5081. class Window_CommandPokemonEx < Window_CommandPokemon
  5082. end
  5083.  
  5084.  
  5085.  
  5086. class Window_AdvancedCommandPokemonEx < Window_AdvancedCommandPokemon
  5087. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement