• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Pokemon Contests Script 1.5

mewlover22

Pokemon Creator
455
Posts
15
Years
  • Tired your fix in a clean version and i got this error did i forget something because i did everything in the post you told me to do.

    ---------------------------
    Pokemon Essentials
    ---------------------------
    Exception: RuntimeError

    Message: Script error within event 21, map 22 (Contest Hall):

    Exception: NoMethodError

    Message: Section177:154:in `pbTurn'undefined method `pbCustomMessage' for Kernel:Module

    ***Full script:

    Kernel.pbMessage(_INTL("First up is Gary's Butterscortch!"))
    showSpeciesIntro(PBSpecies::CHARIZARD,"","Butterscortch")
    pbAddContestMove(2,1,2,3,7)
    pbChangeContestName(2,"Butterscortch")
    pbContest(50,PBSpecies::CHARIZARD,20,PBSpecies::SQUIRTLE,20,PBSpecies::HITMONTOP,20,1)


    Interpreter:243:in `pbExecuteScript'

    Contest:115:in `pbStartContest'

    Contest:2460:in `pbStartContest'

    Contest:2470:in `pbContest'

    (eval):5:in `pbExecuteScript'

    Interpreter:1606:in `eval'

    Interpreter:243:in `pbExecuteScript'

    Interpreter:1606:in `command_355'

    Interpreter:494:in `execute_command'

    Interpreter:193:in `update'



    Interpreter:276:in `pbExecuteScript'

    Interpreter:1606:in `command_355'

    Interpreter:494:in `execute_command'

    Interpreter:193:in `update'

    Interpreter:106:in `loop'

    Interpreter:198:in `update'

    Scene_Map:103:in `update'

    Scene_Map:101:in `loop'

    Scene_Map:114:in `update'

    Scene_Map:68:in `main'



    This exception was logged in

    C:\Users\Chris\Saved Games/Pokemon Essentials/errorlog.txt.

    Press Ctrl+C to copy this message to the clipboard.
    ---------------------------
    OK
    ---------------------------
     
    31
    Posts
    8
    Years
  • Well from what I can see the problem is in pbCustomMessage and that should be where the trouble is...
    All I needed to do in v16.1 was just add in Messages
    Above def Kernel.pbMessage around line 996

    Code:
    def Kernel.pbCustomMessage(message,skin=nil,newx=nil,newwidth=nil,&block) ret=0 msgwindow=Kernel.pbCreateMessageWindow(nil,skin) msgwindow.x=newx if newx!=nil if newwidth!=nil msgwindow.width=newwidth else msgwindow.width=Graphics.width-msgwindow.x end Kernel.pbMessageDisplay(msgwindow,message,&block) Kernel.pbDisposeMessageWindow(msgwindow) Input.update return ret end

    And I skipped the second part of that because it really isn't needed.

    Because in the Main Contest script under
    def pbTurn(turnnumber)
    it uses the pbCustomMessage
    and I know changing that part of the script isn't what is needed.
     
    Last edited:

    mewlover22

    Pokemon Creator
    455
    Posts
    15
    Years
  • Well from what I can see the problem is in pbCustomMessage and that should be where the trouble is...
    All I needed to do in v16.1 was just add in Messages
    Code:
    def Kernel.pbCustomMessage(message,skin=nil,newx=nil,newwidth=nil,&block) ret=0 msgwindow=Kernel.pbCreateMessageWindow(nil,skin) msgwindow.x=newx if newx!=nil if newwidth!=nil msgwindow.width=newwidth else msgwindow.width=Graphics.width-msgwindow.x end Kernel.pbMessageDisplay(msgwindow,message,&block) Kernel.pbDisposeMessageWindow(msgwindow) Input.update return ret end



    And I skipped the second part of that because it really isn't needed.

    Where do these go in the main script?
     
    31
    Posts
    8
    Years
  • Ok Here is my Messages Script
    Code:
    class Game_Temp
      attr_writer :message_window_showing
      attr_writer :player_transferring
      attr_writer :transition_processing
    
      def message_window_showing
        @message_window_showing=false if !@message_window_showing
        return @message_window_showing
      end
    
      def player_transferring
        @player_transferring=false if !@player_transferring
        return @player_transferring
      end
    
      def transition_processing
        @transition_processing=false if !@transition_processing
        return @transition_processing
      end
    end
    
    
    
    class Game_Message
      attr_writer :background, :visible
      def visible; return @visible ? @visible : false; end
      def background; return @background ? @background : 0; end
    end
    
    
    
    class Game_System
      attr_writer :message_position
    
      def message_position
        @message_position=2 if !@message_position
        return @message_position
      end
    end
    
    
    
    #########
    
    class Scene_Map
      def updatemini
        oldmws=$game_temp.message_window_showing
        oldvis=$game_message ? $game_message.visible : false
        $game_temp.message_window_showing=true
        $game_message.visible=true if $game_message
        loop do
          $game_map.update
          $game_player.update
          $game_system.update
          if $game_screen
            $game_screen.update
          else
            $game_map.screen.update
          end
          unless $game_temp.player_transferring
            break
          end
          transfer_player
          if $game_temp.transition_processing
            break
          end
        end
        $game_temp.message_window_showing=oldmws
        $game_message.visible=oldvis if $game_message
        @spriteset.update if @spriteset
        @message_window.update if @message_window
      end
    end
    
    
    
    class Scene_Battle
      def updatemini
        if self.respond_to?("update_basic")
          update_basic(true)
          update_info_viewport                  # Update information viewport
          if $game_message && $game_message.visible
            @info_viewport.visible = false
            @message_window.visible = true
          end
        else
          oldmws=$game_temp.message_window_showing
          $game_temp.message_window_showing=true
          # Update system (timer) and screen
          $game_system.update
          if $game_screen
            $game_screen.update
          else
            $game_map.screen.update
          end    
          # If timer has reached 0
          if $game_system.timer_working and $game_system.timer == 0
            # Abort battle
            $game_temp.battle_abort = true
          end
          # Update windows
          @help_window.update if @help_window
          @party_command_window.update if @party_command_window
          @actor_command_window.update if @actor_command_window
          @status_window.update if @status_window
          $game_temp.message_window_showing=oldmws
          @message_window.update if @message_window
          # Update sprite set
          @spriteset.update if @spriteset
        end
      end
    end
    
    
    
    def pbMapInterpreterRunning?
      interp=pbMapInterpreter
      return interp && interp.running?
    end
    
    def pbMapInterpreter
      if $game_map && $game_map.respond_to?("interpreter")
        return $game_map.interpreter
      elsif $game_system
        return $game_system.map_interpreter
      end
      return nil
    end
    
    def pbRefreshSceneMap
      if $scene && $scene.is_a?(Scene_Map)
        if $scene.respond_to?("miniupdate")
          $scene.miniupdate
        else
          $scene.updatemini
        end
      elsif $scene && $scene.is_a?(Scene_Battle)
        $scene.updatemini
      end
    end
    
    def pbUpdateSceneMap
      if $scene && $scene.is_a?(Scene_Map) && !pbIsFaded?
        if $scene.respond_to?("miniupdate")
          $scene.miniupdate
        else
          $scene.updatemini
        end
      elsif $scene && $scene.is_a?(Scene_Battle)
        $scene.updatemini
      end
    end
    #########
    
    def pbCsvField!(str)
      ret=""
      str.sub!(/\A\s*/,"")
      if str[0,1]=="\""
        str[0,1]=""
        escaped=false
        fieldbytes=0
        str.scan(/./) do |s|
          fieldbytes+=s.length
          break if s=="\"" && !escaped
          if s=="\\" && !escaped
            escaped=true
          else
            ret+=s
            escaped=false
          end
        end
        str[0,fieldbytes]=""
        if !str[/\A\s*,/] && !str[/\A\s*$/] 
          raise _INTL("Invalid quoted field (in: {1})",ret)
        end
        str[0,str.length]=$~.post_match
      else
        if str[/,/]
          str[0,str.length]=$~.post_match
          ret=$~.pre_match
        else
          ret=str.clone
          str[0,str.length]=""
        end
        ret.gsub!(/\s+$/,"")
      end
      return ret
    end
    
    def pbCsvPosInt!(str)
      ret=pbCsvField!(str)
      if !ret[/\A\d+$/]
        raise _INTL("Field {1} is not a positive integer",ret)
      end
      return ret.to_i
    end
    
    def pbEventCommentInput(*args)
      parameters = []
      list = *args[0].list # Event or event page
      elements = *args[1] # Number of elements
      trigger = *args[2] # Trigger
      return nil if list == nil
      return nil unless list.is_a?(Array)
      for item in list
        next unless item.code == 108 || item.code == 408
        if item.parameters[0] == trigger
          start = list.index(item) + 1
          finish = start + elements
          for id in start...finish
            next if !list[id]
            parameters.push(list[id].parameters[0])
          end
          return parameters
        end
      end
      return nil
    end
    
    def pbCurrentEventCommentInput(elements,trigger)
      return nil if !pbMapInterpreterRunning?
      event=pbMapInterpreter.get_character(0)
      return nil if !event
      return pbEventCommentInput(event,elements,trigger)
    end
    
    
    
    module InterpreterMixin
      def pbGlobalLock # Freezes all events on the map (for use at the beginning of common events)
        for event in $game_map.events.values
          event.minilock
        end
      end
    
      def pbGlobalUnlock # Unfreezes all events on the map (for use at the end of common events)
        for event in $game_map.events.values
          event.unlock
        end
      end
    
      def pbRepeatAbove(index)
        index=@list[index].indent
        loop do
          index-=1
          if @list[index].indent==indent
            return index+1
          end
        end
      end
    
      def pbBreakLoop(index)
        indent = @list[index].indent
        temp_index=index
        # Copy index to temporary variables
        loop do
          # Advance index
          temp_index += 1
          # If a fitting loop was not found
          if temp_index >= @list.size-1
            return index+1
          end
          if @list[temp_index].code == 413 and @list[temp_index].indent < indent
            return temp_index+1
          end
        end
      end
    
      def pbJumpToLabel(index,label_name)
        temp_index = 0
        loop do
          if temp_index >= @list.size-1
            return index+1
          end
          if @list[temp_index].code == 118 and
             @list[temp_index].parameters[0] == label_name
            return temp_index+1
          end
          temp_index += 1
        end
      end
    
    # Gets the next index in the interpreter, ignoring
    # certain events between messages
      def pbNextIndex(index)
        return -1 if !@list || @list.length==0
        i=index+1
        loop do
          if i>[email protected]
            return i
          end
          code=@list[i].code
          case code
          when 118, 108, 408 # Label, Comment
            i+=1
          when 413 # Repeat Above
            i=pbRepeatAbove(i)
          when 113 # Break Loop
            i=pbBreakLoop(i)
          when 119 # Jump to Label
            newI=pbJumpToLabel(i,@list[i].parameters[0])
            if newI>i
              i=newI
            else
              i+=1
            end
          else
            return i
          end     
        end
      end
    
    # Helper function that shows a picture in a script.  To be used in
    # a script event command.
      def pbShowPicture(number,name,origin,x,y,zoomX=100,zoomY=100,opacity=255,blendType=0)
        number = number + ($game_temp.in_battle ? 50 : 0)
        $game_screen.pictures[number].show(name,origin,
           x, y, zoomX,zoomY,opacity,blendType)
      end
    
    # Erases an event and adds it to the list of erased events so that
    # it can stay erased when the game is saved then loaded again.  To be used in
    # a script event command.
      def pbEraseThisEvent
        if $game_map.events[@event_id]
          $game_map.events[@event_id].erase
          $PokemonMap.addErasedEvent(@event_id) if $PokemonMap
        end
        @index+=1
        return true
      end
    
    # Runs a common event.  To be used in a script event command.
      def pbCommonEvent(id)
        if $game_temp.in_battle
          $game_temp.common_event_id = id
        else
          commonEvent = $data_common_events[id]
          $game_system.battle_interpreter.setup(commonEvent.list, 0)
        end
      end
    
    # Sets another event's self switch (eg. pbSetSelfSwitch(20,"A",true) ).
    # To be used in a script event command.
      def pbSetSelfSwitch(event,swtch,value)
        $game_self_switches[[@map_id,event,swtch]]=value
        $game_map.need_refresh = true
      end
    
    # Must use this approach to share the methods because the methods already
    # defined in a class override those defined in an included module
      CustomEventCommands=<<_END_
    
      def command_242
        pbBGMFade(pbParams[0])
        return true
      end
    
      def command_246
        pbBGSFade(pbParams[0])
        return true
      end
    
      def command_251
        pbSEStop()
        return true
      end
    
      def command_241
        pbBGMPlay(pbParams[0])
        return true
      end
    
      def command_245
        pbBGSPlay(pbParams[0])
        return true
      end
    
      def command_249
        pbMEPlay(pbParams[0])
        return true
      end
    
      def command_250
        pbSEPlay(pbParams[0])
        return true
      end
    _END_
    end
    
    
    
    def pbButtonInputProcessing(variableNumber=0,timeoutFrames=0)
      ret=0
      loop do
        Graphics.update
        Input.update
        pbUpdateSceneMap
        for i in 1..18
          if Input.trigger?(i)
            ret=i
          end
        end
        break if ret!=0
        if timeoutFrames && timeoutFrames>0
          i+=1
          break if i>=timeoutFrames
        end
      end
      Input.update
      if variableNumber && variableNumber>0
        $game_variables[variableNumber]=ret
        $game_map.need_refresh = true if $game_map
      end
      return ret
    end
    
    
    
    class Game_Temp
      attr_accessor :background
    end
    
    
    
    class Game_Interpreter   # Used by RMVX
      include InterpreterMixin
      eval(InterpreterMixin::CustomEventCommands)
      @@immediateDisplayAfterWait=false
      @buttonInput=false
    
      def pbParams
        return @params
      end
    
      def command_105
        return false if @buttonInput
        @buttonInput=true
        pbButtonInputProcessing(@list[@index].parameters[0])
        @buttonInput=false
        @index+=1
        return true
      end
    
      def command_101
        if $game_temp.message_window_showing
          return false
        end
        $game_message=Game_Message.new if !$game_message
        message=""
        commands=nil
        numInputVar=nil
        numInputDigitsMax=nil
        text=""
        facename=@list[@index].parameters[0]
        faceindex=@list[@index].parameters[1]
        if facename && facename!=""
          text+="\\ff[#{facename},#{faceindex}]"
        end
        if $game_message
          $game_message.background=@list[@index].parameters[2]
        end
        $game_system.message_position=@list[@index].parameters[3]
        message+=text
        messageend=""
        loop do
          nextIndex=pbNextIndex(@index)
          code=@list[nextIndex].code
          if code == 401
            text=@list[nextIndex].parameters[0]
            text+=" " if text!="" && text[text.length-1,1]!=" "
            message+=text
            @index=nextIndex
          else
            if code == 102
              commands=@list[nextIndex].parameters
              @index=nextIndex
            elsif code == 106 && @@immediateDisplayAfterWait
              params=@list[nextIndex].parameters
              if params[0]<=10
                nextcode=@list[nextIndex+1].code
                if nextcode==101||nextcode==102||nextcode==103
                  @index=nextIndex
                else
                  break
                end
              else
                break
              end
            elsif code == 103
              numInputVar=@list[nextIndex].parameters[0]
              numInputDigitsMax=@list[nextIndex].parameters[1]
              @index=nextIndex
            elsif code == 101
              messageend="\1"
            end
            break
          end
        end
        message=_MAPINTL($game_map.map_id,message)
        @message_waiting=true
        if commands
          cmdlist=[]
          for cmd in commands[0]
            cmdlist.push(_MAPINTL($game_map.map_id,cmd))
          end
          command=Kernel.pbMessage(message+messageend,cmdlist,commands[1])
          @branch[@list[@index].indent] = command
        elsif numInputVar
          params=ChooseNumberParams.new
          params.setMaxDigits(numInputDigitsMax)
          params.setDefaultValue($game_variables[numInputVar])
          $game_variables[numInputVar]=Kernel.pbMessageChooseNumber(message+messageend,params)
          $game_map.need_refresh = true if $game_map
        else
          Kernel.pbMessage(message+messageend)
        end
        @message_waiting=false
        return true
      end
    
      def command_102
        @message_waiting=true
        command=Kernel.pbShowCommands(nil,@list[@index].parameters[0],@list[@index].parameters[1])
        @message_waiting=false
        @branch[@list[@index].indent] = command
        Input.update # Must call Input.update again to avoid extra triggers
        return true
      end
    
      def command_103
        varnumber=@list[@index].parameters[0]
        @message_waiting=true
        params=ChooseNumberParams.new
        params.setMaxDigits(@list[@index].parameters[1])
        params.setDefaultValue($game_variables[varnumber])
        $game_variables[varnumber]=Kernel.pbChooseNumber(nil,params)
        $game_map.need_refresh = true if $game_map
        @message_waiting=false
        return true
      end
    end
    
    
    
    class Interpreter   # Used by RMXP
      include InterpreterMixin
      eval(InterpreterMixin::CustomEventCommands)
      @@immediateDisplayAfterWait=false
      @buttonInput=false
    
      def pbParams
        return @parameters
      end
    
      def command_105
        return false if @buttonInput
        @buttonInput=true
        pbButtonInputProcessing(@list[@index].parameters[0])
        @buttonInput=false
        @index+=1
        return true
      end
    
      def command_101
        if $game_temp.message_window_showing
          return false
        end
        message=""
        commands=nil
        numInputVar=nil
        numInputDigitsMax=nil
        text=""
        firstText=nil
        if @list[@index].parameters.length==1
          text+=@list[@index].parameters[0]
          firstText=@list[@index].parameters[0]
          text+=" " if text[text.length-1,1]!=" "
          message+=text
        else
          facename=@list[@index].parameters[0]
          faceindex=@list[@index].parameters[1]
          if facename && facename!=""
            text+="\\ff[#{facename},#{faceindex}]"
            message+=text
          end
        end
        messageend=""
        loop do
          nextIndex=pbNextIndex(@index)
          code=@list[nextIndex].code
          if code == 401
            text=@list[nextIndex].parameters[0]
            text+=" " if text[text.length-1,1]!=" "
            message+=text
            @index=nextIndex
          else
            if code == 102
              commands=@list[nextIndex].parameters
              @index=nextIndex
            elsif code == 106 && @@immediateDisplayAfterWait
              params=@list[nextIndex].parameters
              if params[0]<=10
                nextcode=@list[nextIndex+1].code
                if nextcode==101||nextcode==102||nextcode==103
                  @index=nextIndex
                else
                  break
                end
              else
                break
              end
            elsif code == 103
              numInputVar=@list[nextIndex].parameters[0]
              numInputDigitsMax=@list[nextIndex].parameters[1]
              @index=nextIndex
            elsif code == 101
              if @list[@index].parameters.length==1
                text=@list[@index].parameters[0]
                if text[/\A\\ignr/] && text==firstText
                  text+=" " if text[text.length-1,1]!=" "
                  message+=text
                  @index=nextIndex
                  continue
                end
              end
              messageend="\1"
            end
            break
          end
        end
        @message_waiting=true # needed to allow parallel process events to work while
                              # a message is displayed
        message=_MAPINTL($game_map.map_id,message)
        if commands
          cmdlist=[]
          for cmd in commands[0]
            cmdlist.push(_MAPINTL($game_map.map_id,cmd))
          end
          command=Kernel.pbMessage(message+messageend,cmdlist,commands[1])
          @branch[@list[@index].indent] = command
        elsif numInputVar
          params=ChooseNumberParams.new
          params.setMaxDigits(numInputDigitsMax)
          params.setDefaultValue($game_variables[numInputVar])
          $game_variables[numInputVar]=Kernel.pbMessageChooseNumber(message+messageend,params)
          $game_map.need_refresh = true if $game_map
        else
          Kernel.pbMessage(message+messageend,nil)
        end
        @message_waiting=false
        return true
      end
    
      def command_102
        @message_waiting=true
        command=Kernel.pbShowCommands(nil,@list[@index].parameters[0],@list[@index].parameters[1])
        @message_waiting=false
        @branch[@list[@index].indent] = command
        Input.update # Must call Input.update again to avoid extra triggers
        return true
      end
    
      def command_103
        varnumber=@list[@index].parameters[0]
        @message_waiting=true
        params=ChooseNumberParams.new
        params.setMaxDigits(@list[@index].parameters[1])
        params.setDefaultValue($game_variables[varnumber])
        $game_variables[varnumber]=Kernel.pbChooseNumber(nil,params)
        $game_map.need_refresh = true if $game_map
        @message_waiting=false
        return true
      end
    end
    
    
    
    class ChooseNumberParams
      def initialize
        @maxDigits=0
        @minNumber=0
        @maxNumber=0
        @skin=nil
        @messageSkin=nil
        @negativesAllowed=false
        @initialNumber=0
        @cancelNumber=nil
      end
    
      def setMessageSkin(value)
        @messageSkin=value
      end
    
      def messageSkin # Set the full path for the message's window skin
        @messageSkin
      end
    
      def setSkin(value)
        @skin=value
      end
    
      def skin
        @skin
      end
    
      def setNegativesAllowed(value)
        @negativeAllowed=value
      end
    
      def negativesAllowed
        @negativeAllowed ? true : false
      end
    
      def setRange(minNumber,maxNumber)
        maxNumber=minNumber if minNumber>maxNumber
        @maxDigits=0
        @minNumber=minNumber
        @maxNumber=maxNumber
      end
    
      def setDefaultValue(number)
        @initialNumber=number
        @cancelNumber=nil
      end
    
      def setInitialValue(number)
        @initialNumber=number
      end
    
      def setCancelValue(number)
        @cancelNumber=number
      end
    
      def initialNumber
        return clamp(@initialNumber,self.minNumber,self.maxNumber)
      end
    
      def cancelNumber
        return @cancelNumber ? @cancelNumber : self.initialNumber
      end
    
      def minNumber
        ret=0
        if @maxDigits>0
          ret=-((10**@maxDigits)-1)
        elsif
          ret=@minNumber
        end
        ret=0 if !@negativeAllowed && ret<0
        return ret
      end
    
      def maxNumber
        ret=0
        if @maxDigits>0
          ret=((10**@maxDigits)-1)
        elsif
          ret=@maxNumber
        end
        ret=0 if !@negativeAllowed && ret<0
        return ret
      end
    
      def setMaxDigits(value)
        @maxDigits=[1,value].max
      end
    
      def maxDigits
        if @maxDigits>0
          return @maxDigits
        else
          return [numDigits(self.minNumber),numDigits(self.maxNumber)].max
        end
      end
    
      private
    
      def clamp(v,mn,mx)
        return v<mn ? mn : (v>mx ? mx : v)
      end
    
      def numDigits(number)
        ans = 1
        number=number.abs
        while number >= 10
          ans+=1
          number/=10
        end
        return ans
      end
    end
    
    
    
    def pbChooseNumber(msgwindow,params)
      return 0 if !params
      ret=0
      maximum=params.maxNumber
      minimum=params.minNumber
      defaultNumber=params.initialNumber
      cancelNumber=params.cancelNumber
      cmdwindow=Window_InputNumberPokemon.new(params.maxDigits)
      cmdwindow.z=99999
      cmdwindow.visible=true
      cmdwindow.setSkin(params.skin) if params.skin
      cmdwindow.sign=params.negativesAllowed # must be set before number
      cmdwindow.number=defaultNumber
      curnumber=defaultNumber
      pbPositionNearMsgWindow(cmdwindow,msgwindow,:right)
      command=0
      loop do
        Graphics.update
        Input.update
        pbUpdateSceneMap
        cmdwindow.update
        msgwindow.update if msgwindow
        yield if block_given?
        if Input.trigger?(Input::C)
          ret=cmdwindow.number
          if ret>maximum
            pbPlayBuzzerSE()
          elsif ret<minimum
            pbPlayBuzzerSE()
          else
            pbPlayDecisionSE()
            break
          end
        elsif Input.trigger?(Input::B)
          pbPlayCancelSE()
          ret=cancelNumber
          break
        end
      end
      cmdwindow.dispose
      Input.update
      return ret 
    end
    
    def Kernel.pbShowCommandsWithHelp(msgwindow,commands,help,cmdIfCancel=0,defaultCmd=0)
      msgwin=msgwindow
      if !msgwindow
        msgwin=Kernel.pbCreateMessageWindow(nil)
      end
      oldlbl=msgwin.letterbyletter
      msgwin.letterbyletter=false
      if commands
        cmdwindow=Window_CommandPokemonEx.new(commands)
        cmdwindow.z=99999
        cmdwindow.visible=true
        cmdwindow.resizeToFit(cmdwindow.commands)
        cmdwindow.height=msgwin.y if cmdwindow.height>msgwin.y
        cmdwindow.index=defaultCmd
        command=0
        msgwin.text=help[cmdwindow.index]
        msgwin.width=msgwin.width # Necessary evil to make it use the proper margins.
        loop do
          Graphics.update
          Input.update
          oldindex=cmdwindow.index
          cmdwindow.update
          if oldindex!=cmdwindow.index
            msgwin.text=help[cmdwindow.index]
          end
          msgwin.update
          yield if block_given?
          if Input.trigger?(Input::B)
            if cmdIfCancel>0
              command=cmdIfCancel-1
              break
            elsif cmdIfCancel<0
              command=cmdIfCancel
              break
            end
          end
          if Input.trigger?(Input::C)
            command=cmdwindow.index
            break
          end
          pbUpdateSceneMap
        end
        ret=command
        cmdwindow.dispose
        Input.update
      end
      msgwin.letterbyletter=oldlbl
      if !msgwindow
        msgwin.dispose
      end
      return ret
    end
    
    def Kernel.pbShowCommands(msgwindow,commands=nil,cmdIfCancel=0,defaultCmd=0)
      ret=0
      if commands
        cmdwindow=Window_CommandPokemonEx.new(commands)
        cmdwindow.z=99999
        cmdwindow.visible=true
        cmdwindow.resizeToFit(cmdwindow.commands)
        pbPositionNearMsgWindow(cmdwindow,msgwindow,:right)
        cmdwindow.index=defaultCmd
        command=0
        loop do
          Graphics.update
          Input.update
          cmdwindow.update
          msgwindow.update if msgwindow
          yield if block_given?
          if Input.trigger?(Input::B)
            if cmdIfCancel>0
              command=cmdIfCancel-1
              break
            elsif cmdIfCancel<0
              command=cmdIfCancel
              break
            end
          end
          if Input.trigger?(Input::C)
            command=cmdwindow.index
            break
          end
          pbUpdateSceneMap
        end
        ret=command
        cmdwindow.dispose
        Input.update
      end
      return ret
    end
    
    def pbPositionFaceWindow(facewindow,msgwindow)
      return if !facewindow
      if msgwindow
        if facewindow.height<=msgwindow.height
          facewindow.y=msgwindow.y
        else
          facewindow.y=msgwindow.y+msgwindow.height-facewindow.height
        end
        facewindow.x=Graphics.width-facewindow.width
        msgwindow.x=0
        msgwindow.width=Graphics.width-facewindow.width
      else
        facewindow.height=Graphics.height if facewindow.height>Graphics.height
        facewindow.x=0
        facewindow.y=0
      end
    end
    
    def pbPositionNearMsgWindow(cmdwindow,msgwindow,side)
      return if !cmdwindow
      if msgwindow
        height=[cmdwindow.height,Graphics.height-msgwindow.height].min
        if cmdwindow.height!=height
          cmdwindow.height=height
        end
        cmdwindow.y=msgwindow.y-cmdwindow.height
        if cmdwindow.y<0
          cmdwindow.y=msgwindow.y+msgwindow.height
          if cmdwindow.y+cmdwindow.height>Graphics.height
            cmdwindow.y=msgwindow.y-cmdwindow.height
          end
        end
        case side
        when :left
          cmdwindow.x=msgwindow.x
        when :right
          cmdwindow.x=msgwindow.x+msgwindow.width-cmdwindow.width
        else
          cmdwindow.x=msgwindow.x+msgwindow.width-cmdwindow.width
        end
      else
        cmdwindow.height=Graphics.height if cmdwindow.height>Graphics.height
        cmdwindow.x=0
        cmdwindow.y=0
      end
    end
    
    def pbGetBasicMapNameFromId(id)
      begin
        map = pbLoadRxData("Data/MapInfos")
        return "" if !map
        return map[id].name
      rescue
        return ""
      end
    end
    
    def pbGetMapNameFromId(id)
      map=pbGetBasicMapNameFromId(id)
      if $Trainer
        map.gsub!(/\\PN/,$Trainer.name)
      end
      return map
    end
    
    #~~ Pokémon Contests ~~ Required
    def Kernel.pbCustomMessage(message,skin=nil,newx=nil,newwidth=nil,&block)
      ret=0
      msgwindow=Kernel.pbCreateMessageWindow(nil,skin)
      msgwindow.x=newx if newx!=nil
      if newwidth!=nil
        msgwindow.width=newwidth
      else
      msgwindow.width=Graphics.width-msgwindow.x
    end
      Kernel.pbMessageDisplay(msgwindow,message,&block)
      Kernel.pbDisposeMessageWindow(msgwindow)
      Input.update
      return ret
    end
    #~~
    
    def Kernel.pbMessage(message,commands=nil,cmdIfCancel=0,skin=nil,defaultCmd=0,&block)
      ret=0
      msgwindow=Kernel.pbCreateMessageWindow(nil,skin)
      if commands
        ret=Kernel.pbMessageDisplay(msgwindow,message,true,
           proc {|msgwindow|
              next Kernel.pbShowCommands(msgwindow,commands,cmdIfCancel,defaultCmd,&block)
        },&block)
      else
        Kernel.pbMessageDisplay(msgwindow,message,&block)
      end
      Kernel.pbDisposeMessageWindow(msgwindow)
      Input.update
      return ret
    end
    
    def Kernel.pbMessageChooseNumber(message,params,&block)
      msgwindow=Kernel.pbCreateMessageWindow(nil,params.messageSkin)
      ret=Kernel.pbMessageDisplay(msgwindow,message,true,
         proc {|msgwindow|
            next Kernel.pbChooseNumber(msgwindow,params,&block)
      },&block)
      Kernel.pbDisposeMessageWindow(msgwindow)
      return ret
    end
    
    def Kernel.pbConfirmMessage(message,&block)
      return (Kernel.pbMessage(message,[_INTL("Yes"),_INTL("No")],2,&block)==0)
    end
    
    def Kernel.pbConfirmMessageSerious(message,&block)
      return (Kernel.pbMessage(message,[_INTL("No"),_INTL("Yes")],1,&block)==1)
    end
    
    def Kernel.pbCreateStatusWindow(viewport=nil)
      msgwindow=Window_AdvancedTextPokemon.new("")
      if !viewport
        msgwindow.z=99999
      else
        msgwindow.viewport=viewport
      end
      msgwindow.visible=false
      msgwindow.letterbyletter=false
      pbBottomLeftLines(msgwindow,2)
      skinfile=MessageConfig.pbGetSpeechFrame()
      msgwindow.setSkin(skinfile)
      return msgwindow
    end
    
    def Kernel.pbCreateMessageWindow(viewport=nil,skin=nil)
      msgwindow=Window_AdvancedTextPokemon.new("")
      if !viewport
        msgwindow.z=99999
      else
        msgwindow.viewport=viewport
      end
      msgwindow.visible=true
      msgwindow.letterbyletter=true
      msgwindow.back_opacity=MessageConfig::WindowOpacity
      pbBottomLeftLines(msgwindow,2)
      $game_temp.message_window_showing=true if $game_temp
      $game_message.visible=true if $game_message
      skin=MessageConfig.pbGetSpeechFrame() if !skin
      msgwindow.setSkin(skin)
      return msgwindow
    end
    
    def Kernel.pbDisposeMessageWindow(msgwindow)
      $game_temp.message_window_showing=false if $game_temp
      $game_message.visible=false if $game_message
      msgwindow.dispose
    end
    
    
    
    class FaceWindowVX < SpriteWindow_Base 
      def initialize(face)
        super(0,0,128,128)
        faceinfo=face.split(",")
        facefile=pbResolveBitmap("Graphics/Faces/"+faceinfo[0])
        facefile=pbResolveBitmap("Graphics/Pictures/"+faceinfo[0]) if !facefile
        self.contents.dispose if self.contents
        @faceIndex=faceinfo[1].to_i
        @facebitmaptmp=AnimatedBitmap.new(facefile)
        @facebitmap=BitmapWrapper.new(96,96)
        @facebitmap.blt(0,0,@facebitmaptmp.bitmap,Rect.new(
           (@faceIndex % 4) * 96,
           (@faceIndex / 4) * 96, 96, 96
        ))
        self.contents=@facebitmap
      end
    
      def update
        super
        if @facebitmaptmp.totalFrames>1
          @facebitmaptmp.update
          @facebitmap.blt(0,0,@facebitmaptmp.bitmap,Rect.new(
             (@faceIndex % 4) * 96,
             (@faceIndex / 4) * 96, 96, 96
          ))
        end
      end
    
      def dispose
        @facebitmaptmp.dispose
        @facebitmap.dispose if @facebitmap
        super
      end
    end
    
    
    
    def itemIconTag(item)
      return "" if !item
      if item.respond_to?("icon_name")
        return sprintf("<icon=%s>",item.icon_name)
      else
        ix=item.icon_index % 16 * 24
        iy=item.icon_index / 16 * 24
        return sprintf("<img=Graphics/System/Iconset|%d|%d|24|24>",ix,iy)
      end
    end
    
    def getSkinColor(windowskin,color,isDarkSkin)
      if !windowskin || windowskin.disposed? || 
         windowskin.width!=128 || windowskin.height!=128
        textcolors=[
           isDarkSkin ? shadowc3tag(MessageConfig::LIGHTTEXTBASE, MessageConfig::LIGHTTEXTSHADOW) :
                        shadowc3tag(MessageConfig::DARKTEXTBASE, MessageConfig::DARKTEXTSHADOW),
           "<c2=7E105D08>",   # Red
           "<c2=421F2117>",   # Blue
           "<c2=43F022E8>",   # Green
           "<c2=7FF05EE8>",   # Yellow
           "<c2=7E1F5D17>",   # Magenta
           "<c2=43FF22F7>",   # Cyan
           "<c2=63184210>",   # Grey
           "<c2=7FFF5EF7>"    # White
        ]
        color=0 if color>textcolors.length
        return textcolors[color]
      else # VX windowskin
        color=0 if color>=32
        x = 64 + (color % 8) * 8
        y = 96 + (color / 8) * 8
        pixel=windowskin.get_pixel(x, y)
        return shadowctagFromColor(pixel)
      end
    end
    
    # internal function
    def pbRepositionMessageWindow(msgwindow, linecount=2)
      msgwindow.height=32*linecount+msgwindow.borderY
      msgwindow.y=(Graphics.height)-(msgwindow.height)
      if $game_temp && $game_temp.in_battle && !$scene.respond_to?("update_basic")
        msgwindow.y=0
      elsif $game_system && $game_system.respond_to?("message_position")
        case $game_system.message_position
        when 0  # up
          msgwindow.y=0
        when 1  # middle
          msgwindow.y=(Graphics.height/2)-(msgwindow.height/2)
        when 2
         msgwindow.y=(Graphics.height)-(msgwindow.height)
        end
      end
      if $game_system && $game_system.respond_to?("message_frame")
        if $game_system.message_frame != 0
          msgwindow.opacity = 0
        end
      end
      if $game_message
        case $game_message.background
        when 1  # dim
          msgwindow.opacity=0
        when 2  # transparent
          msgwindow.opacity=0
        end 
      end
    end
    
    # internal function
    def pbUpdateMsgWindowPos(msgwindow,event,eventChanged=false)
      if event
        if eventChanged
          msgwindow.resizeToFit2(msgwindow.text,Graphics.width*2/3,msgwindow.height)
        end
        msgwindow.y=event.screen_y-48-msgwindow.height  
        if msgwindow.y<0
          msgwindow.y=event.screen_y+24
        end
        msgwindow.x=event.screen_x-(msgwindow.width/2)
        msgwindow.x=0 if msgwindow.x<0
        if msgwindow.x>Graphics.width-msgwindow.width
          msgwindow.x=Graphics.width-msgwindow.width
        end
      else
        curwidth=msgwindow.width
        if curwidth!=Graphics.width
          msgwindow.width=Graphics.width
          msgwindow.width=Graphics.width     
        end
      end
    end
    
    # internal function
    
    def pbGetGoldString
      moneyString=""
      if $Trainer
        moneyString=_INTL("${1}",$Trainer.money)
      else
        if $data_system.respond_to?("words")
          moneyString=_INTL("{1} {2}",$game_party.gold,$data_system.words.gold)
        else
          moneyString=_INTL("{1} {2}",$game_party.gold,Vocab.gold)         
        end
      end
      return moneyString
    end
    
    def pbDisplayGoldWindow(msgwindow)
      moneyString=pbGetGoldString()
      goldwindow=Window_AdvancedTextPokemon.new(_INTL("Money:\n<ar>{1}</ar>",moneyString))
      goldwindow.setSkin("Graphics/Windowskins/goldskin")
      goldwindow.resizeToFit(goldwindow.text,Graphics.width)
      goldwindow.width=160 if goldwindow.width<=160
      if msgwindow.y==0
        goldwindow.y=Graphics.height-goldwindow.height
      else
        goldwindow.y=0
      end
      goldwindow.viewport=msgwindow.viewport
      goldwindow.z=msgwindow.z
      return goldwindow
    end
    
    def pbDisplayCoinsWindow(msgwindow,goldwindow)
      coinString=($PokemonGlobal) ? $PokemonGlobal.coins : "0"
      coinwindow=Window_AdvancedTextPokemon.new(_INTL("Coins:\n<ar>{1}</ar>",coinString))
      coinwindow.setSkin("Graphics/Windowskins/goldskin")
      coinwindow.resizeToFit(coinwindow.text,Graphics.width)
      coinwindow.width=160 if coinwindow.width<=160
      if msgwindow.y==0
        coinwindow.y=(goldwindow) ? goldwindow.y-coinwindow.height : Graphics.height-coinwindow.height
      else
        coinwindow.y=(goldwindow) ? goldwindow.height : 0
      end
      coinwindow.viewport=msgwindow.viewport
      coinwindow.z=msgwindow.z
      return coinwindow
    end
    
    def pbMessageWaitForInput(msgwindow,frames,showPause=false)
      return if !frames || frames<=0
      if msgwindow && showPause
        msgwindow.startPause
      end
      frames.times do
        Graphics.update
        Input.update
        msgwindow.update if msgwindow
        pbUpdateSceneMap
        if Input.trigger?(Input::C) || Input.trigger?(Input::B)
          break
        end
        yield if block_given?
      end
      if msgwindow && showPause
        msgwindow.stopPause
      end
    end
    
    def Kernel.pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
      return if !msgwindow
      oldletterbyletter=msgwindow.letterbyletter
      msgwindow.letterbyletter=(letterbyletter ? true : false)
      ret=nil
      count=0
      commands=nil
      facewindow=nil
      goldwindow=nil
      coinwindow=nil
      cmdvariable=0
      cmdIfCancel=0
      msgwindow.waitcount=0
      autoresume=false
      text=message.clone
      msgback=nil
      linecount=(Graphics.height>400) ? 3 : 2
      ### Text replacement
      text.gsub!(/\\\\/,"\5")
      if $game_actors
        text.gsub!(/\\[Nn]\[([1-8])\]/){ 
           m=$1.to_i
           next $game_actors[m].name
        }
      end
      text.gsub!(/\\[Ss][Ii][Gg][Nn]\[([^\]]*)\]/){ 
         next "\\op\\cl\\ts[]\\w["+$1+"]"
      }
      text.gsub!(/\\[Pp][Nn]/,$Trainer.name) if $Trainer
      text.gsub!(/\\[Pp][Mm]/,_INTL("${1}",$Trainer.money)) if $Trainer
      text.gsub!(/\\[Nn]/,"\n")
      text.gsub!(/\\\[([0-9A-Fa-f]{8,8})\]/){ "<c2="+$1+">" }
      text.gsub!(/\\[Pp][Gg]/,"\\b") if $Trainer && $Trainer.isMale?
      text.gsub!(/\\[Pp][Gg]/,"\\r") if $Trainer && $Trainer.isFemale?
      text.gsub!(/\\[Pp][Oo][Gg]/,"\\r") if $Trainer && $Trainer.isMale?
      text.gsub!(/\\[Pp][Oo][Gg]/,"\\b") if $Trainer && $Trainer.isFemale?
      text.gsub!(/\\[Pp][Gg]/,"")
      text.gsub!(/\\[Pp][Oo][Gg]/,"")
      text.gsub!(/\\[Bb]/,"<c2=6546675A>")
      text.gsub!(/\\[Rr]/,"<c2=043C675A>")
      text.gsub!(/\\1/,"\1")
      colortag=""
      isDarkSkin=isDarkWindowskin(msgwindow.windowskin)
      if ($game_message && $game_message.background>0) ||
         ($game_system && $game_system.respond_to?("message_frame") &&
          $game_system.message_frame != 0)
        colortag=getSkinColor(msgwindow.windowskin,0,true)
      else
        colortag=getSkinColor(msgwindow.windowskin,0,isDarkSkin)
      end
      text.gsub!(/\\[Cc]\[([0-9]+)\]/){ 
         m=$1.to_i
         next getSkinColor(msgwindow.windowskin,m,isDarkSkin)
      }
      begin
        last_text = text.clone
        text.gsub!(/\\[Vv]\[([0-9]+)\]/) { $game_variables[$1.to_i] }
      end until text == last_text
      begin
        last_text = text.clone
        text.gsub!(/\\[Ll]\[([0-9]+)\]/) { 
           linecount=[1,$1.to_i].max;
           next "" 
        }
      end until text == last_text
      text=colortag+text
      ### Controls
      textchunks=[]
      controls=[]
      while text[/(?:\\([WwFf]|[Ff][Ff]|[Tt][Ss]|[Cc][Ll]|[Mm][Ee]|[Ss][Ee]|[Ww][Tt]|[Ww][Tt][Nn][Pp]|[Cc][Hh])\[([^\]]*)\]|\\([Gg]|[Cc][Nn]|[Ww][Dd]|[Ww][Mm]|[Oo][Pp]|[Cc][Ll]|[Ww][Uu]|[\.]|[\|]|[\!]|[\x5E])())/i]
        textchunks.push($~.pre_match)
        if $~[1]
          controls.push([$~[1].downcase,$~[2],-1])
        else
          controls.push([$~[3].downcase,"",-1])
        end
        text=$~.post_match
      end
      textchunks.push(text)
      for chunk in textchunks
        chunk.gsub!(/\005/,"\\")
      end
      textlen=0
      for i in 0...controls.length
        control=controls[i][0]
        if control=="wt" || control=="wtnp" || control=="." || control=="|"
          textchunks[i]+="\2"
        elsif control=="!"
          textchunks[i]+="\1"
        end
        textlen+=toUnformattedText(textchunks[i]).scan(/./m).length
        controls[i][2]=textlen
      end
      text=textchunks.join("")
      unformattedText=toUnformattedText(text)
      signWaitCount=0
      haveSpecialClose=false
      specialCloseSE=""
      for i in 0...controls.length
        control=controls[i][0]
        param=controls[i][1]
        if control=="f"
          facewindow.dispose if facewindow
          facewindow=PictureWindow.new("Graphics/Pictures/#{param}")
        elsif control=="op"
          signWaitCount=21
        elsif control=="cl"
          text=text.sub(/\001\z/,"") # fix: '$' can match end of line as well
          haveSpecialClose=true
          specialCloseSE=param
        elsif control=="se" && controls[i][2]==0
          startSE=param
          controls[i]=nil
        elsif control=="ff"
          facewindow.dispose if facewindow
          facewindow=FaceWindowVX.new(param)
        elsif control=="ch"
          cmds=param.clone
          cmdvariable=pbCsvPosInt!(cmds)
          cmdIfCancel=pbCsvField!(cmds).to_i
          commands=[]
          while cmds.length>0
            commands.push(pbCsvField!(cmds))
          end
        elsif control=="wtnp" || control=="^"
          text=text.sub(/\001\z/,"") # fix: '$' can match end of line as well
        end
      end
      if startSE!=nil
        pbSEPlay(pbStringToAudioFile(startSE))
      elsif signWaitCount==0 && letterbyletter
        pbPlayDecisionSE()
      end
      ########## Position message window  ##############
      pbRepositionMessageWindow(msgwindow,linecount)
      if $game_message && $game_message.background==1
        msgback=IconSprite.new(0,msgwindow.y,msgwindow.viewport)
        msgback.z=msgwindow.z-1
        msgback.setBitmap("Graphics/System/MessageBack")
      end
      if facewindow
        pbPositionNearMsgWindow(facewindow,msgwindow,:left)
        facewindow.viewport=msgwindow.viewport
        facewindow.z=msgwindow.z
      end
      atTop=(msgwindow.y==0)
      ########## Show text #############################
      msgwindow.text=text
      Graphics.frame_reset if Graphics.frame_rate>40
      begin
        if signWaitCount>0
          signWaitCount-=1
          if atTop
            msgwindow.y=-(msgwindow.height*(signWaitCount)/20)
          else
            msgwindow.y=Graphics.height-(msgwindow.height*(20-signWaitCount)/20)
          end
        end
        for i in 0...controls.length
          if controls[i] && controls[i][2]<=msgwindow.position && msgwindow.waitcount==0
            control=controls[i][0]
            param=controls[i][1]
            case control
            when "f"
              facewindow.dispose if facewindow
              facewindow=PictureWindow.new("Graphics/Pictures/#{param}")
              pbPositionNearMsgWindow(facewindow,msgwindow,:left)
              facewindow.viewport=msgwindow.viewport
              facewindow.z=msgwindow.z
            when "ts"
              if param==""
                msgwindow.textspeed=-999
              else
                msgwindow.textspeed=param.to_i
              end
            when "ff"
              facewindow.dispose if facewindow
              facewindow=FaceWindowVX.new(param)
              pbPositionNearMsgWindow(facewindow,msgwindow,:left)
              facewindow.viewport=msgwindow.viewport
              facewindow.z=msgwindow.z
            when "g" # Display gold window
              goldwindow.dispose if goldwindow
              goldwindow=pbDisplayGoldWindow(msgwindow)
            when "cn" # Display coins window
              coinwindow.dispose if coinwindow
              coinwindow=pbDisplayCoinsWindow(msgwindow,goldwindow)
            when "wu"
              msgwindow.y=0
              atTop=true
              msgback.y=msgwindow.y if msgback
              pbPositionNearMsgWindow(facewindow,msgwindow,:left)
              msgwindow.y=-(msgwindow.height*(signWaitCount)/20)
            when "wm"
              atTop=false
              msgwindow.y=(Graphics.height/2)-(msgwindow.height/2)
              msgback.y=msgwindow.y if msgback
              pbPositionNearMsgWindow(facewindow,msgwindow,:left)
            when "wd"
              atTop=false
              msgwindow.y=(Graphics.height)-(msgwindow.height)
              msgback.y=msgwindow.y if msgback
              pbPositionNearMsgWindow(facewindow,msgwindow,:left)
              msgwindow.y=Graphics.height-(msgwindow.height*(20-signWaitCount)/20)
            when "."
              msgwindow.waitcount+=Graphics.frame_rate/4
            when "|"
              msgwindow.waitcount+=Graphics.frame_rate
            when "wt" # Wait
              param=param.sub(/\A\s+/,"").sub(/\s+\z/,"")
              msgwindow.waitcount+=param.to_i*2
            when "w" # Windowskin
              if param==""
                msgwindow.windowskin=nil
              else
                msgwindow.setSkin("Graphics/Windowskins/#{param}")
              end
              msgwindow.width=msgwindow.width  # Necessary evil
            when "^" # Wait, no pause
              autoresume=true
            when "wtnp" # Wait, no pause
              param=param.sub(/\A\s+/,"").sub(/\s+\z/,"")
              msgwindow.waitcount=param.to_i*2
              autoresume=true
            when "se" # Play SE
              pbSEPlay(pbStringToAudioFile(param))
            when "me" # Play ME
              pbMEPlay(pbStringToAudioFile(param))
            end
            controls[i]=nil
          end
        end
        break if !letterbyletter
        Graphics.update
        Input.update
        facewindow.update if facewindow
        if $DEBUG && Input.trigger?(Input::F6)
          pbRecord(unformattedText)
        end
        if autoresume && msgwindow.waitcount==0
          msgwindow.resume if msgwindow.busy?
          break if !msgwindow.busy?
        end
        if (Input.trigger?(Input::C) || Input.trigger?(Input::B))
          if msgwindow.busy?
            pbPlayDecisionSE() if msgwindow.pausing?
            msgwindow.resume
          else
            break if signWaitCount==0
          end
        end
        pbUpdateSceneMap
        msgwindow.update
        yield if block_given?
      end until (!letterbyletter || commandProc || commands) && !msgwindow.busy?
      Input.update # Must call Input.update again to avoid extra triggers
      msgwindow.letterbyletter=oldletterbyletter
      if commands
        $game_variables[cmdvariable]=Kernel.pbShowCommands(
           msgwindow,commands,cmdIfCancel)
        $game_map.need_refresh = true if $game_map
      end
      if commandProc
        ret=commandProc.call(msgwindow)
      end
      msgback.dispose if msgback
      goldwindow.dispose if goldwindow
      coinwindow.dispose if coinwindow
      facewindow.dispose if facewindow
      if haveSpecialClose
        pbSEPlay(pbStringToAudioFile(specialCloseSE))
        atTop=(msgwindow.y==0)
        for i in 0..20
          if atTop
            msgwindow.y=-(msgwindow.height*(i)/20)
          else
            msgwindow.y=Graphics.height-(msgwindow.height*(20-i)/20)
          end
          Graphics.update
          Input.update
          pbUpdateSceneMap
          msgwindow.update
        end
      end
      return ret
    end

    And don't forget to use Thread Tools Show Printable Version.
     

    mewlover22

    Pokemon Creator
    455
    Posts
    15
    Years
  • You did it i think we should make a version 16 script so people can use this so far i have found no issues im just testing a contest right now.

    Edit right as round one began this happened.

    ---------------------------
    Pokemon Essentials
    ---------------------------
    Exception: RuntimeError

    Message: Script error within event 21, map 22 (Contest Hall):

    Exception: NameError

    Message: Section177:1704:in `pbMoveButtons'uninitialized constant PokeContestScene::PBContestMoves

    ***Full script:

    Kernel.pbMessage(_INTL("First up is Gary's Butterscortch!"))
    showSpeciesIntro(PBSpecies::CHARIZARD,"","Butterscortch")
    pbAddContestMove(2,1,2,3,7)
    pbChangeContestName(2,"Butterscortch")
    pbContest(50,PBSpecies::CHARIZARD,20,PBSpecies::SQUIRTLE,20,PBSpecies::HITMONTOP,20,1)


    Interpreter:243:in `pbExecuteScript'

    Contest:185:in `pbTurn'

    Contest:115:in `pbStartContest'

    Contest:2460:in `pbStartContest'

    Contest:2470:in `pbContest'

    (eval):5:in `pbExecuteScript'

    Interpreter:1606:in `eval'

    Interpreter:243:in `pbExecuteScript'

    Interpreter:1606:in `command_355'

    Interpreter:494:in `execute_command'



    Interpreter:276:in `pbExecuteScript'

    Interpreter:1606:in `command_355'

    Interpreter:494:in `execute_command'

    Interpreter:193:in `update'

    Interpreter:106:in `loop'

    Interpreter:198:in `update'

    Scene_Map:103:in `update'

    Scene_Map:101:in `loop'

    Scene_Map:114:in `update'

    Scene_Map:68:in `main'



    This exception was logged in

    C:\Users\Chris\Saved Games/Pokemon Essentials/errorlog.txt.

    Press Ctrl+C to copy this message to the clipboard.
    ---------------------------
    OK
    ---------------------------
     
    31
    Posts
    8
    Years
  • Well I know you should have PBContestMove above PBMove script and in
    PBMove it should look like this:
    Code:
    class PokemonTemp
      attr_accessor :pokemonMoveData
    
      def pbOpenMoveData
        if !self.pokemonMoveData
          pbRgssOpen("Data/moves.dat","rb"){|f|
             self.pokemonMoveData=f.read
          }
        end
        if block_given?
          StringInput.open(self.pokemonMoveData) {|f| yield f }
        else
          return StringInput.open(self.pokemonMoveData)
        end
      end
    end
    
    
    
    class PBMoveData
      attr_reader :function,:basedamage,:type,:accuracy
      attr_reader :totalpp,:addlEffect,:target,:priority
      attr_reader :flags
      attr_reader :category,:contestType
    
      def initializeOld(moveid)
        movedata=pbRgssOpen("Data/rsattacks.dat")
        movedata.pos=moveid*9
        @function   = movedata.fgetb
        @basedamage = movedata.fgetb
        @type       = movedata.fgetb
        @accuracy   = movedata.fgetb
        @totalpp    = movedata.fgetb
        @addlEffect = movedata.fgetb
        @target     = movedata.fgetb
        @priority   = movedata.fgetsb
        @flags      = movedata.fgetb
        movedata.close
      end
    
      def initialize(moveid)
        movedata=nil
        if $PokemonTemp
          movedata=$PokemonTemp.pbOpenMoveData
        else
          movedata=pbRgssOpen("Data/moves.dat")
        end
        movedata.pos=moveid*14
        @function    = movedata.fgetw
        @basedamage  = movedata.fgetb
        @type        = movedata.fgetb
        @category    = movedata.fgetb
        @accuracy    = movedata.fgetb
        @totalpp     = movedata.fgetb
        @addlEffect  = movedata.fgetb
        @target      = movedata.fgetw
        @priority    = movedata.fgetsb
        @flags       = movedata.fgetw
        @contestType = movedata.fgetb
        movedata.close
      end
    end
    
    
    
    class PBMove
      attr_reader(:id)       # This move's ID
      attr_accessor(:pp)     # The amount of PP remaining for this move
      attr_accessor(:ppup)   # The number of PP Ups used for this move
    
    # Gets this move's type.
      def type
        movedata=PBMoveData.new(@id)
        return movedata.type
      end
    
    # Gets the maximum PP for this move.
      def totalpp
        movedata=PBMoveData.new(@id)
        tpp=movedata.totalpp
        return tpp+(tpp*@ppup/5).floor
      end
    
    # Initializes this object to the specified move ID.
      def initialize(moveid)
        movedata=PBMoveData.new(moveid)
        @pp=movedata.totalpp
        @id=moveid
        @ppup=0
      end
    end

    And the Compiler Script should look like this:
    Code:
    #===============================================================================
    # Exceptions and critical code
    #===============================================================================
    class Reset < Exception
    end
    
    
    
    def pbGetExceptionMessage(e,script="")
      emessage=e.message
      if e.is_a?(Hangup)
        emessage="The script is taking too long. The game will restart."
      elsif e.is_a?(Errno::ENOENT)
        filename=emessage.sub("No such file or directory - ", "")
        emessage="File #{filename} not found."
      end
      if emessage && !safeExists?("Game.rgssad") && !safeExists?("Game.rgss2a")
        emessage=emessage.gsub(/uninitialized constant PBItems\:\:(\S+)/){
           "The item '#{$1}' is not valid. Please add the item\r\nto the list of items in the editor. See the wiki for more information." }
        emessage=emessage.gsub(/undefined method `(\S+?)' for PBItems\:Module/){
           "The item '#{$1}' is not valid. Please add the item\r\nto the list of items in the editor. See the wiki for more information." }
        emessage=emessage.gsub(/uninitialized constant PBTypes\:\:(\S+)/){
           "The type '#{$1}' is not valid. Please add the type\r\nto the PBS/types.txt file." }
        emessage=emessage.gsub(/undefined method `(\S+?)' for PBTypes\:Module/){
           "The type '#{$1}' is not valid. Please add the type\r\nto the PBS/types.txt file." }
        emessage=emessage.gsub(/uninitialized constant PBTrainers\:\:(\S+)$/){
           "The trainer type '#{$1}' is not valid. Please add the trainer\r\nto the list of trainer types in the Editor. See the wiki for\r\nmore information." }
        emessage=emessage.gsub(/undefined method `(\S+?)' for PBTrainers\:Module/){
           "The trainer type '#{$1}' is not valid. Please add the trainer\r\nto the list of trainer types in the Editor. See the wiki for\r\nmore information." }
        emessage=emessage.gsub(/uninitialized constant PBSpecies\:\:(\S+)$/){
           "The Pokemon species '#{$1}' is not valid. Please\r\nadd the species to the PBS/pokemon.txt file.\r\nSee the wiki for more information." }
        emessage=emessage.gsub(/undefined method `(\S+?)' for PBSpecies\:Module/){
           "The Pokemon species '#{$1}' is not valid. Please\r\nadd the species to the PBS/pokemon.txt file.\r\nSee the wiki for more information." }
      end
      return emessage
    end
    
    def pbPrintException(e)
      emessage=pbGetExceptionMessage(e)
      btrace=""
      if e.backtrace
        maxlength=$INTERNAL ? 25 : 10
        e.backtrace[0,maxlength].each do |i|
          btrace=btrace+"#{i}\r\n"
        end
      end
      btrace.gsub!(/Section(\d+)/){$RGSS_SCRIPTS[$1.to_i][1]}
      message="Exception: #{e.class}\r\nMessage: #{emessage}\r\n#{btrace}"
      errorlog="errorlog.txt"
      if (Object.const_defined?(:RTP) rescue false)
        errorlog=RTP.getSaveFileName("errorlog.txt")
      end
      errorlogline=errorlog.sub(Dir.pwd+"\\","")
      errorlogline=errorlogline.sub(Dir.pwd+"/","")
      if errorlogline.length>20
        errorlogline="\r\n"+errorlogline
      end
      File.open(errorlog,"ab"){|f| f.write(message) }
      if !e.is_a?(Hangup)
        print("#{message}\r\nThis exception was logged in #{errorlogline}.\r\nPress Ctrl+C to copy this message to the clipboard.")
      end
    end
    
    def pbCriticalCode
      ret=0
      begin
        yield
        ret=1
      rescue Exception
        e=$!
        if e.is_a?(Reset) || e.is_a?(SystemExit)
          raise
        else
          pbPrintException(e)
          if e.is_a?(Hangup)
            ret=2
            raise Reset.new
          end
        end
      end
      return ret
    end
    
    
    
    #===============================================================================
    # File reading
    #===============================================================================
    module FileLineData
      @file=""
      @linedata=""
      @lineno=0
      @section=nil
      @key=nil
      @value=nil
    
      def self.file
        @file
      end
    
      def self.file=(value)
        @file=value
      end
    
      def self.clear
        @file=""
        @linedata=""
        @lineno=""
        @section=nil
        @key=nil
        @value=nil
      end
    
      def self.linereport
        if @section
          return _INTL("File {1}, section {2}, key {3}\r\n{4}\r\n",@file,@section,@key,@value)
        else
          return _INTL("File {1}, line {2}\r\n{3}\r\n",@file,@lineno,@linedata)
        end
      end
    
      def self.setSection(section,key,value)
        @section=section
        @key=key
        if value && value.length>200
          @value=_INTL("{1}...",value[0,200])
        else
          @value=!value ? "" : value.clone
        end
      end
    
      def self.setLine(line,lineno)
        @section=nil
        if line && line.length>200
          @linedata=_INTL("{1}...",line[0,200])
        else
          @linedata=line
        end
        @lineno=lineno
      end
    end
    
    
    
    def findIndex(a)
      index=-1
      count=0
      a.each {|i|
         if yield i
           index=count
           break
         end
         count+=1
      }
      return index
    end
    
    def prepline(line)
      line.sub!(/\s*\#.*$/,"")
      line.sub!(/\s+$/,"")
      return line
    end
    
    def pbEachFileSectionEx(f)
      lineno=1
      havesection=false
      sectionname=nil
      lastsection={}
      f.each_line {|line|
         if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
           line=line[3,line.length-3]
         end
         if !line[/^\#/] && !line[/^\s*$/]
           if line[/^\s*\[\s*(.*)\s*\]\s*$/]
             if havesection
               yield lastsection,sectionname 
             end
             sectionname=$~[1]
             havesection=true
             lastsection={}
           else
            if sectionname==nil
              raise _INTL("Expected a section at the beginning of the file. This error may also occur if the file was not saved in UTF-8.\r\n{1}",FileLineData.linereport)
            end
            if !line[/^\s*(\w+)\s*=\s*(.*)$/]
              raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}",FileLineData.linereport)
            end
            r1=$~[1]
            r2=$~[2]
            lastsection[r1]=r2.gsub(/\s+$/,"")
          end
        end
        lineno+=1
        if lineno%500==0
          Graphics.update
        end
        if lineno%50==0
          Win32API.SetWindowText(_INTL("Processing line {1}",lineno))
        end
      }
      if havesection
        yield lastsection,sectionname 
      end
    end
    
    def pbEachFileSection(f)
      pbEachFileSectionEx(f) {|section,name|
         if block_given? && name[/^\d+$/]
           yield section,name.to_i
         end
      }
    end
    
    def pbEachSection(f)
      lineno=1
      havesection=false
      sectionname=nil
      lastsection=[]
      f.each_line {|line|
         if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
           line=line[3,line.length-3]
         end
         if !line[/^\#/] && !line[/^\s*$/]
           if line[/^\s*\[\s*(.+?)\s*\]\s*$/]
             if havesection
               yield lastsection,sectionname 
             end
             sectionname=$~[1]
             lastsection=[]
             havesection=true
           else
             if sectionname==nil
               raise _INTL("Expected a section at the beginning of the file (line {1}). Sections begin with '[name of section]'",lineno)
             end
             lastsection.push(line.gsub(/^\s+/,"").gsub(/\s+$/,""))
           end
         end
         lineno+=1
         if lineno%500==0
           Graphics.update
         end
      }
      if havesection
        yield lastsection,sectionname 
      end
    end
    
    def pbEachCommentedLine(f)
      lineno=1
      f.each_line {|line|
         if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
           line=line[3,line.length-3]
         end
         if !line[/^\#/] && !line[/^\s*$/]
           yield line, lineno
         end
         lineno+=1
      }
    end
    
    def pbCompilerEachCommentedLine(filename)
      File.open(filename,"rb"){|f|
         FileLineData.file=filename
         lineno=1
         f.each_line {|line|
            if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
              line=line[3,line.length-3]
            end
            if !line[/^\#/] && !line[/^\s*$/]
              FileLineData.setLine(line,lineno)
              yield line, lineno
            end
            lineno+=1
         }
      }
    end
    
    def pbEachPreppedLine(f)
      lineno=1
      f.each_line {|line|
         if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
           line=line[3,line.length-3]
         end
         line=prepline(line)
         if !line[/^\#/] && !line[/^\s*$/]
           yield line, lineno
         end
         lineno+=1
      }
    end
    
    def pbCompilerEachPreppedLine(filename)
      File.open(filename,"rb"){|f|
         FileLineData.file=filename
         lineno=1
         f.each_line {|line|
            if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
              line=line[3,line.length-3]
            end
            line=prepline(line)
            if !line[/^\#/] && !line[/^\s*$/]
              FileLineData.setLine(line,lineno)
              yield line, lineno
            end
            lineno+=1
         }
      }
    end
    
    #===============================================================================
    # Valid value checks
    #===============================================================================
    def pbCheckByte(x,valuename)
      if x<0 || x>255
        raise _INTL("The value \"{1}\" must be from 0 through 255 (0x00-0xFF in hex), got a value of {2}\r\n{3}",
           valuename,x,FileLineData.linereport)
      end
    end
    
    def pbCheckSignedByte(x,valuename)
      if x<-128 || x>127
        raise _INTL("The value \"{1}\" must be from -128 through 127, got a value of {2}\r\n{3}",
           valuename,x,FileLineData.linereport)
      end
    end
    
    def pbCheckWord(x,valuename)
      if x<0 || x>65535
        raise _INTL("The value \"{1}\" must be from 0 through 65535 (0x0000-0xFFFF in hex), got a value of {2}\r\n{3}",
           valuename,x,FileLineData.linereport)
      end
    end
    
    def pbCheckSignedWord(x,valuename)
      if x<-32768 || x>32767
        raise _INTL("The value \"{1}\" must be from -32768 through 32767, got a value of {2}\r\n{3}",
           valuename,x,FileLineData.linereport)
      end
    end
    
    #===============================================================================
    # Csv parsing
    #===============================================================================
    def csvfield!(str)
      ret=""
      str.sub!(/^\s*/,"")
      if str[0,1]=="\""
        str[0,1]=""
        escaped=false
        fieldbytes=0
        str.scan(/./) do |s|
          fieldbytes+=s.length
          break if s=="\"" && !escaped
          if s=="\\" && !escaped
            escaped=true
          else
            ret+=s
            escaped=false
          end
        end
        str[0,fieldbytes]=""
        if !str[/^\s*,/] && !str[/^\s*$/] 
          raise _INTL("Invalid quoted field (in: {1})\r\n{2}",str,FileLineData.linereport)
        end
        str[0,str.length]=$~.post_match
      else
        if str[/,/]
          str[0,str.length]=$~.post_match
          ret=$~.pre_match
        else
          ret=str.clone
          str[0,str.length]=""
        end
        ret.gsub!(/\s+$/,"")
      end
      return ret
    end
    
    def csvquote(str)
      return "" if !str || str==""
      if str[/[,\"]/] #|| str[/^\s/] || str[/\s$/] || str[/^#/]
        str=str.gsub(/[\"]/,"\\\"")
        str="\"#{str}\""
      end
      return str
    end
    
    def csvBoolean!(str,line=-1)
      field=csvfield!(str)
      if field[/^1|[Tt][Rr][Uu][Ee]|[Yy][Ee][Ss]$/]
        return true
      elsif field[/^0|[Ff][Aa][Ll][Ss][Ee]|[Nn][Oo]$/]
        return false
      else
        raise _INTL("Field {1} is not a Boolean value (true, false, 1, 0)\r\n{2}",field,FileLineData.linereport)
        return false
      end
    end
    
    def csvInt!(str,line=-1)
      ret=csvfield!(str)
      if !ret[/^\-?\d+$/]
        raise _INTL("Field {1} is not an integer\r\n{2}",ret,FileLineData.linereport)
      end
      return ret.to_i
    end
    
    def csvPosInt!(str,line=-1)
      ret=csvfield!(str)
      if !ret[/^\d+$/]
        raise _INTL("Field {1} is not a positive integer\r\n{2}",ret,FileLineData.linereport)
      end
      return ret.to_i
    end
    
    def csvFloat!(str,key,section)
      ret=csvfield!(str)
      return Float(ret) rescue raise _INTL("Field {1} is not a number\r\n{2}",ret,FileLineData.linereport)
    end
    
    def csvEnumField!(value,enumer,key,section)
      ret=csvfield!(value)
      return checkEnumField(ret,enumer)
    end
    
    def csvEnumFieldOrInt!(value,enumer,key,section)
      ret=csvfield!(value)
      if ret[/\-?\d+/]
        return ret.to_i
      end
      return checkEnumField(ret,enumer)
    end
    
    def checkEnumField(ret,enumer)
      if enumer.is_a?(Module)
        begin
          if ret=="" || !enumer.const_defined?(ret)
            raise _INTL("Undefined value {1} in {2}\r\n{3}",ret,enumer.name,FileLineData.linereport)
          end
        rescue NameError
          raise _INTL("Incorrect value {1} in {2}\r\n{3}",ret,enumer.name,FileLineData.linereport)
        end
        return enumer.const_get(ret.to_sym)
      elsif enumer.is_a?(Symbol) || enumer.is_a?(String)
        enumer=Object.const_get(enumer.to_sym)
        begin
          if ret=="" || !enumer.const_defined?(ret)
            raise _INTL("Undefined value {1} in {2}\r\n{3}",ret,enumer.name,FileLineData.linereport)
          end
        rescue NameError
          raise _INTL("Incorrect value {1} in {2}\r\n{3}",ret,enumer.name,FileLineData.linereport)
        end
        return enumer.const_get(ret.to_sym)
      elsif enumer.is_a?(Array)
        idx=findIndex(enumer){|item| ret==item}
        if idx<0
          raise _INTL("Undefined value {1} (expected one of: {2})\r\n{3}",ret,enumer.inspect,FileLineData.linereport)
        end
        return idx
      elsif enumer.is_a?(Hash)
        value=enumer[ret]
        if value==nil
          raise _INTL("Undefined value {1} (expected one of: {2})\r\n{3}",ret,enumer.keys.inspect,FileLineData.linereport)
        end
        return value
      end
      raise _INTL("Enumeration not defined\r\n{1}",FileLineData.linereport)
    end
    
    #===============================================================================
    # Csv record reading/writing
    #===============================================================================
    def pbGetCsvRecord(rec,lineno,schema)
      record=[]
      repeat=false
      if schema[1][0,1]=="*"
        repeat=true
        start=1
      else
        repeat=false
        start=0
      end
      begin
        for i in start...schema[1].length
          chr=schema[1][i,1]
          case chr
          when "u"
            record.push(csvPosInt!(rec,lineno))
          when "v"
            field=csvPosInt!(rec,lineno)
            raise _INTL("Field '{1}' must be greater than 0\r\n{2}",field,FileLineData.linereport) if field==0
            record.push(field)
          when "i"
            record.push(csvInt!(rec,lineno))
          when "U", "I"
            field=csvfield!(rec)
            if field==""
              record.push(nil)
            elsif !field[/^\d+$/]
              raise _INTL("Field '{1}' must be 0 or greater\r\n{2}",field,FileLineData.linereport)
            else
              record.push(field.to_i)
            end
          when "x"
            field=csvfield!(rec)     
            if !field[/^[A-Fa-f0-9]+$/]
              raise _INTL("Field '{1}' is not a hexadecimal number\r\n{2}",field,FileLineData.linereport)
            end
            record.push(field.hex)
          when "s"
            record.push(csvfield!(rec))
          when "S"
            field=csvfield!(rec)
            if field==""
              record.push(nil)
            else
              record.push(field)
            end
          when "n" # Name
            field=csvfield!(rec)
            if !field[/^(?![0-9])\w+$/]
              raise _INTL("Field '{1}' must contain only letters, digits, and\r\nunderscores and can't begin with a number.\r\n{2}",field,FileLineData.linereport)
            end
            record.push(field)
          when "N" # Optional name
            field=csvfield!(rec)
            if field==""
              record.push(nil)
            else
              if !field[/^(?![0-9])\w+$/]
                raise _INTL("Field '{1}' must contain only letters, digits, and\r\nunderscores and can't begin with a number.\r\n{2}",field,FileLineData.linereport)
              end
              record.push(field)
            end
          when "b"
            record.push(csvBoolean!(rec,lineno))
          when "e"
            record.push(csvEnumField!(rec,schema[2+i-start],"",FileLineData.linereport))
          end
        end
        break if repeat && rec==""
      end while repeat
      return (schema[1].length==1) ? record[0] : record
    end
    
    def pbWriteCsvRecord(record,file,schema)
      if !record.is_a?(Array)
        rec=[record]
      else
        rec=record.clone
      end
      for i in 0...schema[1].length
        chr=schema[1][i,1]
        file.write(",") if i>0 
        if rec[i].nil?
          # do nothing
        elsif rec[i].is_a?(String)
          file.write(csvquote(rec[i]))
        elsif rec[i]==true
          file.write("true")
        elsif rec[i]==false
          file.write("false")
        elsif rec[i].is_a?(Numeric)
          case chr
          when "e"
            enumer=schema[2+i]
            if enumer.is_a?(Array)
              file.write(enumer[rec[i]])
            elsif enumer.is_a?(Symbol) || enumer.is_a?(String)
              mod=Object.const_get(enumer.to_sym)
              if enumer.to_s=="PBTrainers" && !mod.respond_to?("getCount")
                file.write((getConstantName(mod,rec[i]) rescue pbGetTrainerConst(rec[i])))
              else
                file.write(getConstantName(mod,rec[i]))
              end
            elsif enumer.is_a?(Module)
              file.write(getConstantName(enumer,rec[i]))
            elsif enumer.is_a?(Hash)
              for key in enumer.keys
                if enumer[key]==rec[i]
                  file.write(key)
                  break
                end
              end
            end
          else
            file.write(rec[i].inspect)
          end
        else
          file.write(rec[i].inspect)
        end
      end
      return record
    end
    
    #===============================================================================
    # Encoding and decoding
    #===============================================================================
    def intSize(value)
      return 1 if value<0x80
      return 2 if value<0x4000
      return 3 if value<0x200000
      return 4 if value<0x10000000
      return 5
    end
    
    def encodeInt(strm,value)
      num=0
      loop do
        if value<0x80
          strm.fputb(value)
          return num+1
        end
        strm.fputb(0x80|(value&0x7F))
        value>>=7
        num+=1
      end
    end
    
    def decodeInt(strm)
      bits=0
      curbyte=0
      ret=0
      begin
        curbyte=strm.fgetb
        ret+=(curbyte&0x7F)<<bits
        bits+=7
      end while(((curbyte&0x80)>0)&&bits<0x1d)
      return ret
    end
    
    def strSize(str)
      return str.length+intSize(str.length)
    end
    
    def encodeString(strm,str)
      encodeInt(strm,str.length)
      strm.write(str)
    end
    
    def decodeString(strm)
      len=decodeInt(strm)
      return strm.read(len)
    end
    
    def strsplit(str,re)
      ret=[]
      tstr=str
      while re=~tstr
        ret[ret.length]=$~.pre_match
        tstr=$~.post_match
      end
      ret[ret.length]=tstr if ret.length
      return ret
    end
    
    def canonicalize(c)
      csplit=strsplit(c,/[\/\\]/)
      pos=-1
      ret=[]
      retstr=""
      for x in csplit
        if x=="."
        elsif x==".."
          ret.delete_at(pos) if pos>=0
          pos-=1
        else
          ret.push(x)
          pos+=1
        end
      end
      for i in 0...ret.length
        retstr+="/" if i>0
        retstr+=ret[i]
      end
      return retstr
    end
    
    def frozenArrayValue(arr)
      typestring=""
      for i in 0...arr.length
        if i>0
          typestring+=((i%20)==0) ? ",\r\n" : ","
        end
        typestring+=arr[i].to_s
      end
      return "["+typestring+"].freeze"
    end
    
    #===============================================================================
    # Enum const manipulators and parsers
    #===============================================================================
    def pbGetConst(mod,item,err)
      isdef=false
      begin
        isdef=mod.const_defined?(item.to_sym)
      rescue
        raise sprintf(err,item)
      end
      raise sprintf(err,item) if !isdef
      return mod.const_get(item.to_sym)
    end
    
    def removeConstantValue(mod,value)
      for c in mod.constants
        if mod.const_get(c.to_sym)==value
          mod.send(:remove_const,c.to_sym)
        end
      end
    end
    
    def setConstantName(mod,value,name)
      for c in mod.constants
        if mod.const_get(c.to_sym)==value
          mod.send(:remove_const,c.to_sym)
        end
      end
      mod.const_set(name,value)
    end
    
    def getConstantName(mod,value)
      for c in mod.constants
        return c if mod.const_get(c.to_sym)==value
      end
      raise _INTL("Value {1} not defined by a constant in {2}",value,mod.name)
    end
    
    def parseItem(item)
      clonitem=item.upcase
      clonitem.sub!(/^\s*/){}
      clonitem.sub!(/\s*$/){}
      return pbGetConst(PBItems,clonitem,
         _INTL("Undefined item constant name: %s\r\nName must consist only of letters, numbers, and\r\nunderscores and can't begin with a number.\r\nMake sure the item is defined in\r\nPBS/items.txt.\r\n{1}",
         FileLineData.linereport))
    end
    
    def parseSpecies(item)
      clonitem=item.upcase
      clonitem.gsub!(/^[\s\n]*/){}
      clonitem.gsub!(/[\s\n]*$/){}
      clonitem="NIDORANmA" if clonitem=="NIDORANMA"
      clonitem="NIDORANfE" if clonitem=="NIDORANFE"
      return pbGetConst(PBSpecies,clonitem,_INTL("Undefined species constant name: [%s]\r\nName must consist only of letters, numbers, and\r\nunderscores and can't begin with a number.\r\nMake sure the name is defined in\r\nPBS/pokemon.txt.\r\n{1}",FileLineData.linereport))
    end
    
    def parseMove(item)
      clonitem=item.upcase
      clonitem.sub!(/^\s*/){}
      clonitem.sub!(/\s*$/){}
      return pbGetConst(PBMoves,clonitem,_INTL("Undefined move constant name: %s\r\nName must consist only of letters, numbers, and\r\nunderscores and can't begin with a number.\r\nMake sure the name is defined in\r\nPBS/moves.txt.\r\n{1}",FileLineData.linereport))
    end
    
    def parseNature(item)
      clonitem=item.upcase
      clonitem.sub!(/^\s*/){}
      clonitem.sub!(/\s*$/){}
      return pbGetConst(PBNatures,clonitem,_INTL("Undefined nature constant name: %s\r\nName must consist only of letters, numbers, and\r\nunderscores and can't begin with a number.\r\nMake sure the name is defined in\r\nthe script section PBNatures.\r\n{1}",FileLineData.linereport))
    end
    
    def parseTrainer(item)
      clonitem=item.clone
      clonitem.sub!(/^\s*/){}
      clonitem.sub!(/\s*$/){}
      return pbGetConst(PBTrainers,clonitem,_INTL("Undefined Trainer constant name: %s\r\nName must consist only of letters, numbers, and\r\nunderscores and can't begin with a number.\r\nIn addition, the name must be defined\r\nin trainertypes.txt.\r\n{1}",FileLineData.linereport))
    end
    
    #===============================================================================
    # Scripted constants
    #===============================================================================
    def pbFindScript(a,name)
      a.each{|i| 
         next if !i
         return i if i[1]==name
      }
      return nil
    end
    
    def pbAddScript(script,sectionname)
      begin
        scripts=load_data("Data/Constants.rxdata")
        scripts=[] if !scripts
      rescue
        scripts=[]
      end
      s=pbFindScript(scripts,sectionname)
      if s
        s[2]=Zlib::Deflate.deflate("#{script}\r\n")
      else
        scripts.push([rand(100000000),sectionname,Zlib::Deflate.deflate("#{script}\r\n")])
      end
      save_data(scripts,"Data/Constants.rxdata")
    end
    
    
    
    #===============================================================================
    # Serial record
    #===============================================================================
    class SerialRecord < Array
      def bytesize
        return SerialRecord.bytesize(self)
      end
    
      def encode(strm)
        return SerialRecord.encode(self,strm)
      end
    
      def self.bytesize(arr)
        ret=0
        return 0 if !arr
        for field in arr
          if field==nil || field==true || field==false
            ret+=1
          elsif field.is_a?(String)
            ret+=strSize(field)+1
          elsif field.is_a?(Numeric)
            ret+=intSize(field)+1
          end
        end
        return ret
      end
    
      def self.encode(arr,strm)
        return if !arr
        for field in arr
          if field==nil
            strm.write("0")
          elsif field==true
            strm.write("T")
          elsif field==false
            strm.write("F")
          elsif field.is_a?(String)
            strm.write("\"")
            encodeString(strm,field)
          elsif field.is_a?(Numeric)
            strm.write("i")
            encodeInt(strm,field)
          end
        end
      end
    
      def self.decode(strm,offset,length)
        ret=SerialRecord.new
        strm.pos=offset
        while strm.pos<offset+length
          datatype=strm.read(1)
          case datatype
          when "0"
            ret.push(nil)
          when "T"
            ret.push(true)
          when "F"
            ret.push(false)
          when "\""
            ret.push(decodeString(strm))
          when "i"
            ret.push(decodeInt(strm))
          end
        end
        return ret
      end
    end
    
    
    
    def readSerialRecords(filename)
      ret=[]
      if !pbRgssExists?(filename)
        return ret
      end
      pbRgssOpen(filename,"rb"){|file|
         numrec=file.fgetdw>>3
         curpos=0
         for i in 0...numrec
           file.pos=curpos
           offset=file.fgetdw
           length=file.fgetdw
           record=SerialRecord.decode(file,offset,length)
           ret.push(record)
           curpos+=8
         end
      }
      return ret
    end
    
    def writeSerialRecords(filename,records)
      File.open(filename,"wb"){|file|
         totalsize=records.length*8
         for record in records
           file.fputdw(totalsize)
           bytesize=record.bytesize
           file.fputdw(bytesize)
           totalsize+=bytesize
         end
         for record in records
           record.encode(file)
         end
      }
    end
    
    
    
    #===============================================================================
    # Data structures
    #===============================================================================
    class ByteArray
      include Enumerable
    
      def initialize(data=nil)
        @a=(data) ? data.unpack("C*") : []
      end
    
      def []=(i,value)
        @a[i]=value
      end
    
      def [](i)
        return @a[i]
      end
    
      def length; @a.length; end
      def size; @a.size; end
    
      def fillNils(length,value)
        for i in 0...length
          @a[i]=value if !@a[i]
        end
      end
    
      def each
        @a.each {|i| yield i}
      end
    
      def self._load(str)
        return self.new(str)
      end
    
      def _dump(depth=100)
        return @a.pack("C*")
      end
    end
    
    
    
    class WordArray
      include Enumerable
    
      def initialize(data=nil)
        @a=(data) ? data.unpack("v*") : []
      end
    
      def []=(i,value)
        @a[i]=value
      end
    
      def [](i)
        return @a[i]
      end
    
      def length; @a.length; end
      def size; @a.size; end
    
      def fillNils(length,value)
        for i in 0...length
          @a[i]=value if !@a[i]
        end
      end
    
      def each
        @a.each {|i| yield i}
      end
    
      def self._load(str)
        return self.new(str)
      end
    
      def _dump(depth=100)
        return @a.pack("v*")
      end
    end
    
    
    
    class SignedWordArray
      include Enumerable
    
      def initialize(data=nil)
        @a=(data) ? data.unpack("v*") : []
      end
    
      def []=(i,value)
        @a[i]=value
      end
    
      def [](i)
        v=@a[i]
        return v<0x8000 ? v : -((~v)&0xFFFF)-1
      end
    
      def length; @a.length; end
      def size; @a.size; end
    
      def fillNils(length,value)
        for i in 0...length
          @a[i]=value if !@a[i]
        end
      end
    
      def each
        @a.each {|i| yield i}
      end
    
      def self._load(str)
        return self.new(str)
      end
    
      def _dump(depth=100)
        return @a.pack("v*")
      end
    end
    
    
    
    #===============================================================================
    # Compile types
    #===============================================================================
    def pbWriteDefaultTypes
      if !safeExists?("PBS/types.txt")
        File.open("PBS/types.txt","w"){|f|
           f.write(0xEF.chr)
           f.write(0xBB.chr)
           f.write(0xBF.chr)
    fx=<<END
    [0]
    Name=Normal
    InternalName=NORMAL
    Weaknesses=FIGHTING
    Immunities=GHOST
    
    [1]
    Name=Fighting
    InternalName=FIGHTING
    Weaknesses=FLYING,PSYCHIC
    Resistances=ROCK,BUG,DARK
    
    [2]
    Name=Flying
    InternalName=FLYING
    Weaknesses=ROCK,ELECTRIC,ICE
    Resistances=FIGHTING,BUG,GRASS
    Immunities=GROUND
    
    [3]
    Name=Poison
    InternalName=POISON
    Weaknesses=GROUND,PSYCHIC
    Resistances=FIGHTING,POISON,BUG,GRASS
    
    [4]
    Name=Ground
    InternalName=GROUND
    Weaknesses=WATER,GRASS,ICE
    Resistances=POISON,ROCK
    Immunities=ELECTRIC
    
    [5]
    Name=Rock
    InternalName=ROCK
    Weaknesses=FIGHTING,GROUND,STEEL,WATER,GRASS
    Resistances=NORMAL,FLYING,POISON,FIRE
    
    [6]
    Name=Bug
    InternalName=BUG
    Weaknesses=FLYING,ROCK,FIRE
    Resistances=FIGHTING,GROUND,GRASS
    
    [7]
    Name=Ghost
    InternalName=GHOST
    Weaknesses=GHOST,DARK
    Resistances=POISON,BUG
    Immunities=NORMAL,FIGHTING
    
    [8]
    Name=Steel
    InternalName=STEEL
    Weaknesses=FIGHTING,GROUND,FIRE
    Resistances=NORMAL,FLYING,ROCK,BUG,GHOST,STEEL,GRASS,PSYCHIC,ICE,DRAGON,DARK
    Immunities=POISON
    
    [9]
    Name=???
    InternalName=QMARKS
    IsPseudoType=true
    
    [10]
    Name=Fire
    InternalName=FIRE
    IsSpecialType=true
    Weaknesses=GROUND,ROCK,WATER
    Resistances=BUG,STEEL,FIRE,GRASS,ICE
    
    [11]
    Name=Water
    InternalName=WATER
    IsSpecialType=true
    Weaknesses=GRASS,ELECTRIC
    Resistances=STEEL,FIRE,WATER,ICE
    
    [12]
    Name=Grass
    InternalName=GRASS
    IsSpecialType=true
    Weaknesses=FLYING,POISON,BUG,FIRE,ICE
    Resistances=GROUND,WATER,GRASS,ELECTRIC
    
    [13]
    Name=Electric
    InternalName=ELECTRIC
    IsSpecialType=true
    Weaknesses=GROUND
    Resistances=FLYING,STEEL,ELECTRIC
    
    [14]
    Name=Psychic
    InternalName=PSYCHIC
    IsSpecialType=true
    Weaknesses=BUG,GHOST,DARK
    Resistances=FIGHTING,PSYCHIC
    
    [15]
    Name=Ice
    InternalName=ICE
    IsSpecialType=true
    Weaknesses=FIGHTING,ROCK,STEEL,FIRE
    Resistances=ICE
    
    [16]
    Name=Dragon
    InternalName=DRAGON
    IsSpecialType=true
    Weaknesses=ICE,DRAGON
    Resistances=FIRE,WATER,GRASS,ELECTRIC
    
    [17]
    Name=Dark
    InternalName=DARK
    IsSpecialType=true
    Weaknesses=FIGHTING,BUG
    Resistances=GHOST,DARK
    Immunities=PSYCHIC
    
    END
           f.write(fx)
        }
      end
    end
    
    def pbCompileTypes
      pbWriteDefaultTypes
      sections=[]
      typechart=[]
      types=[]
      nameToType={}
      requiredtypes={
         "Name"=>[1,"s"],
         "InternalName"=>[2,"s"],
      }
      optionaltypes={
         "IsPseudoType"=>[3,"b"],
         "IsSpecialType"=>[4,"b"],
         "Weaknesses"=>[5,"*s"],
         "Resistances"=>[6,"*s"],
         "Immunities"=>[7,"*s"]
      }
      currentmap=-1
      foundtypes=[]
      pbCompilerEachCommentedLine("PBS/types.txt") {|line,lineno|
         if line[/^\s*\[\s*(\d+)\s*\]\s*$/]
           sectionname=$~[1]
           if currentmap>=0
             for reqtype in requiredtypes.keys
               if !foundtypes.include?(reqtype)
                 raise _INTL("Required value '{1}' not given in section '{2}'\r\n{3}",reqtype,currentmap,FileLineData.linereport)
               end
             end
             foundtypes.clear
           end
           currentmap=sectionname.to_i
           types[currentmap]=[currentmap,nil,nil,false,false,[],[],[]]
         else
           if currentmap<0
             raise _INTL("Expected a section at the beginning of the file\r\n{1}",FileLineData.linereport)
           end
           if !line[/^\s*(\w+)\s*=\s*(.*)$/]
             raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}",FileLineData.linereport)
           end
           matchData=$~
           schema=nil
           FileLineData.setSection(currentmap,matchData[1],matchData[2])
           if requiredtypes.keys.include?(matchData[1])
             schema=requiredtypes[matchData[1]]
             foundtypes.push(matchData[1])
           else
             schema=optionaltypes[matchData[1]]
           end
           if schema
             record=pbGetCsvRecord(matchData[2],lineno,schema)
             types[currentmap][schema[0]]=record
           end
         end
      }
      types.compact!
      maxValue=0
      for type in types; maxValue=[maxValue,type[0]].max; end
      pseudotypes=[]
      specialtypes=[]
      typenames=[]
      typeinames=[]
      typehash={}
      for type in types
        pseudotypes.push(type[0]) if type[3]
        typenames[type[0]]=type[1]
        typeinames[type[0]]=type[2]
        typehash[type[0]]=type
      end
      for type in types
        n=type[1]
        for w in type[5]; if !typeinames.include?(w)
          raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Weaknesses)",w,n)
        end; end
        for w in type[6]; if !typeinames.include?(w)
          raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Resistances)",w,n)
        end; end
        for w in type[7]; if !typeinames.include?(w)
          raise _INTL("'{1}' is not a defined type (PBS/types.txt, {2}, Immunities)",w,n)
        end; end
      end
      for i in 0..maxValue
        pseudotypes.push(i) if !typehash[i]
      end
      pseudotypes.sort!
      for type in types; specialtypes.push(type[0]) if type[4]; end
      specialtypes.sort!
      MessageTypes.setMessages(MessageTypes::Types,typenames)
      code="class PBTypes\r\n"
      for type in types
        code+="#{type[2]}=#{type[0]}\r\n"
      end
      code+="def PBTypes.getName(id)\r\nreturn pbGetMessage(MessageTypes::Types,id)\r\nend\r\n"
      code+="def PBTypes.getCount; return #{types.length}; end\r\n"
      code+="def PBTypes.maxValue; return #{maxValue}; end\r\n"
      count=maxValue+1
      for i in 0...count
        type=typehash[i]
        j=0; k=i; while j<count
          typechart[k]=2
          atype=typehash[j]
          if type && atype
            typechart[k]=4 if type[5].include?(atype[2]) # weakness
            typechart[k]=1 if type[6].include?(atype[2]) # resistance
            typechart[k]=0 if type[7].include?(atype[2]) # immune
          end
          j+=1
          k+=count
        end
      end
      code+="end\r\n"
      eval(code)
      save_data([pseudotypes,specialtypes,typechart],"Data/types.dat")
      pbAddScript(code,"PBTypes")
      Graphics.update
    end
    
    #===============================================================================
    # Compile town map points
    #===============================================================================
    def pbCompileTownMap
      nonglobaltypes={
         "Name"=>[0,"s"],
         "Filename"=>[1,"s"],
         "Point"=>[2,"uussUUUU"]
      }
      currentmap=-1
      rgnnames=[]
      placenames=[]
      placedescs=[]
      sections=[]
      pbCompilerEachCommentedLine("PBS/townmap.txt"){|line,lineno|
         if line[/^\s*\[\s*(\d+)\s*\]\s*$/]
           currentmap=$~[1].to_i
           sections[currentmap]=[]
         else
           if currentmap<0
             raise _INTL("Expected a section at the beginning of the file\r\n{1}",FileLineData.linereport)
           end
           if !line[/^\s*(\w+)\s*=\s*(.*)$/]
             raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}",FileLineData.linereport)
           end
           settingname=$~[1]
           schema=nonglobaltypes[settingname]
           if schema
             record=pbGetCsvRecord($~[2],lineno,schema)
             if settingname=="Name"
               rgnnames[currentmap]=record
             elsif settingname=="Point"
               placenames.push(record[2])
               placedescs.push(record[3])
               sections[currentmap][schema[0]]=[] if !sections[currentmap][schema[0]]
               sections[currentmap][schema[0]].push(record)
             else   # Filename
               sections[currentmap][schema[0]]=record
             end
           end
         end
      }
      File.open("Data/townmap.dat","wb"){|f|
         Marshal.dump(sections,f)
      }
      MessageTypes.setMessages(
         MessageTypes::RegionNames,rgnnames
      )
      MessageTypes.setMessagesAsHash(
         MessageTypes::PlaceNames,placenames
      )
      MessageTypes.setMessagesAsHash(
         MessageTypes::PlaceDescriptions,placedescs
      )
    end
    
    #===============================================================================
    # Compile map connections
    #===============================================================================
    def pbCompileConnections
      records=[]
      constants=""
      itemnames=[]
      pbCompilerEachPreppedLine("PBS/connections.txt"){|line,lineno|
         hashenum={
            "N"=>"N","North"=>"N",
            "E"=>"E","East"=>"E",
            "S"=>"S","South"=>"S",
            "W"=>"W","West"=>"W"
         }
         record=[]
         thisline=line.dup
         record.push(csvInt!(thisline,lineno))
         record.push(csvEnumFieldOrInt!(thisline,hashenum,"",sprintf("(line %d)",lineno)))
         record.push(csvInt!(thisline,lineno))
         record.push(csvInt!(thisline,lineno))
         record.push(csvEnumFieldOrInt!(thisline,hashenum,"",sprintf("(line %d)",lineno)))
         record.push(csvInt!(thisline,lineno))          
         if !pbRgssExists?(sprintf("Data/Map%03d.rxdata",record[0])) &&
            !pbRgssExists?(sprintf("Data/Map%03d.rvdata",record[0]))
           print _INTL("Warning: Map {1}, as mentioned in the map\r\nconnection data, was not found.\r\n{2}",record[0],FileLineData.linereport)
         end
         if !pbRgssExists?(sprintf("Data/Map%03d.rxdata",record[3])) &&
            !pbRgssExists?(sprintf("Data/Map%03d.rvdata",record[3]))
           print _INTL("Warning: Map {1}, as mentioned in the map\r\nconnection data, was not found.\r\n{2}",record[3],FileLineData.linereport)
         end
         case record[1]
         when "N"
           raise _INTL("North side of first map must connect with south side of second map\r\n{1}",FileLineData.linereport) if record[4]!="S"
         when "S"
           raise _INTL("South side of first map must connect with north side of second map\r\n{1}",FileLineData.linereport) if record[4]!="N"
         when "E"
           raise _INTL("East side of first map must connect with west side of second map\r\n{1}",FileLineData.linereport) if record[4]!="W"
         when "W"
           raise _INTL("West side of first map must connect with east side of second map\r\n{1}",FileLineData.linereport) if record[4]!="E"
         end
         records.push(record)
      }
      save_data(records,"Data/connections.dat")
      Graphics.update
    end
    
    #===============================================================================
    # Compile abilities
    #===============================================================================
    def pbCompileAbilities
      records=[]
      movenames=[]
      movedescs=[]
      maxValue=0
      pbCompilerEachPreppedLine("PBS/abilities.txt"){|line,lineno|
         record=pbGetCsvRecord(line,lineno,[0,"vnss"])
         movenames[record[0]]=record[2]
         movedescs[record[0]]=record[3]
         maxValue=[maxValue,record[0]].max
         records.push(record)
      }
      MessageTypes.setMessages(MessageTypes::Abilities,movenames)
      MessageTypes.setMessages(MessageTypes::AbilityDescs,movedescs)
      code="class PBAbilities\r\n"
      for rec in records
        code+="#{rec[1]}=#{rec[0]}\r\n"
      end
      code+="\r\ndef PBAbilities.getName(id)\r\nreturn pbGetMessage(MessageTypes::Abilities,id)\r\nend"
      code+="\r\ndef PBAbilities.getCount\r\nreturn #{records.length}\r\nend\r\n"
      code+="\r\ndef PBAbilities.maxValue\r\nreturn #{maxValue}\r\nend\r\nend"
      eval(code)
      pbAddScript(code,"PBAbilities")
    end
    
    #===============================================================================
    # Compile move data
    #===============================================================================
    class PBMoveDataOld
      attr_reader :function,:basedamage,:type,:accuracy
      attr_reader :totalpp,:addlEffect,:target,:priority
      attr_reader :flags
      attr_reader :category,:contestType #~~ Pokémon Contests ~~ Required
    
      def initialize(moveid)
        movedata=pbRgssOpen("Data/rsattacks.dat")
        movedata.pos=moveid*9
        @function=movedata.fgetb
        @basedamage=movedata.fgetb
        @type=movedata.fgetb
        @accuracy=movedata.fgetb
        @totalpp=movedata.fgetb
        @addlEffect=movedata.fgetb
        @target=movedata.fgetb
        @priority=movedata.fgetsb
        @flags=movedata.fgetb
        movedata.close
      end
    
      def category
        return 2 if @basedamage==0
        return @type<10 ? 0 : 1
      end
    end
    
    def pbCompileMoves
      records=[]
      movenames=[]
      movedescs=[]
      movedata=[]
      maxValue=0
      pbCompilerEachPreppedLine("PBS/moves.txt"){|line,lineno|
         thisline=line.clone
         record=[]
         flags=0
         #~~ Pokémon Contests ~~ Required
         begin
           record=pbGetCsvRecord(line,lineno,[0,"vnsxueeuuuxises",
              nil,nil,nil,nil,nil,PBTypes,["Physical","Special","Status"],
              nil,nil,nil,nil,nil,nil,["Cool","Beauty","Cute","Smart","Tough"],nil
           ])
           #~~
           pbCheckWord(record[3],_INTL("Function code"))
           flags|=1 if record[12][/a/]
           flags|=2 if record[12][/b/]
           flags|=4 if record[12][/c/]
           flags|=8 if record[12][/d/]
           flags|=16 if record[12][/e/]
           flags|=32 if record[12][/f/]
           flags|=64 if record[12][/g/]
           flags|=128 if record[12][/h/]
           flags|=256 if record[12][/i/]
           flags|=512 if record[12][/j/]
           flags|=1024 if record[12][/k/]
           flags|=2048 if record[12][/l/]
           flags|=4096 if record[12][/m/]
           flags|=8192 if record[12][/n/]
           flags|=16384 if record[12][/o/]
           flags|=32768 if record[12][/p/]
         rescue
           oldmessage=$!.message
           raise if !pbRgssExists?("Data/rsattacks.dat")
           begin
             oldrecord=pbGetCsvRecord(thisline,lineno,[0,"unss",nil,nil,nil,nil])
           rescue
             raise $!.message+"\r\n"+oldmessage
           end
           oldmovedata=PBMoveDataOld.new(oldrecord[0])
           flags=oldmovedata.flags
           record=[oldrecord[0],oldrecord[1],oldrecord[2],
              oldmovedata.function,
              oldmovedata.basedamage,
              oldmovedata.type,
              oldmovedata.category,
              oldmovedata.accuracy,
              oldmovedata.totalpp,
              oldmovedata.addlEffect,
              oldmovedata.target,
              oldmovedata.priority,
              oldmovedata.flags,
              0, # No contest type defined
              oldrecord[3]]
         end
         pbCheckWord(record[3],_INTL("Function code"))
         pbCheckByte(record[4],_INTL("Base damage"))
         if record[6]==2 && record[4]!=0
           raise _INTL("Status moves must have a base damage of 0, use either Physical or Special\r\n{1}",FileLineData.linereport)
         end
         if record[6]!=2 && record[4]==0
           print _INTL("Warning: Physical and special moves can't have a base damage of 0, changing to a Status move\r\n{1}",FileLineData.linereport)
           record[6]=2
         end
         pbCheckByte(record[7],_INTL("Accuracy"))
         pbCheckByte(record[8],_INTL("Total PP"))
         pbCheckByte(record[9],_INTL("Additional Effect"))
         pbCheckWord(record[10],_INTL("Target"))
         pbCheckSignedByte(record[11],_INTL("Priority"))
         maxValue=[maxValue,record[0]].max
         movedata[record[0]]=[
            record[3],  # Function code
            record[4],  # Damage
            record[5],  # Type
            record[6],  # Category
            record[7],  # Accuracy
            record[8],  # Total PP
            record[9],  # Effect chance
            record[10], # Target
            record[11], # Priority
            flags,      # Flags
            record[13]  # Contest type #~~ Pokémon Contests ~~ Required
         ].pack("vCCCCCCvCvC")
         movenames[record[0]]=record[2]  # Name
         movedescs[record[0]]=record[14] # Description # Changed to 14
         records.push(record)
      }
      defaultdata=[0,0,0,0,0,0,0,0,0,0,0].pack("vCCCCCCvCvC")
      File.open("Data/moves.dat","wb"){|file|
         for i in 0...movedata.length
           file.write(movedata[i] ? movedata[i] : defaultdata)
         end
      }
      MessageTypes.setMessages(MessageTypes::Moves,movenames)
      MessageTypes.setMessages(MessageTypes::MoveDescriptions,movedescs)
      code="class PBMoves\r\n"
      for rec in records
        code+="#{rec[1]}=#{rec[0]}\r\n"
      end
      code+="\r\ndef PBMoves.getName(id)\r\nreturn pbGetMessage(MessageTypes::Moves,id)\r\nend"
      code+="\r\ndef PBMoves.getCount\r\nreturn #{records.length}\r\nend"
      code+="\r\ndef PBMoves.maxValue\r\nreturn #{maxValue}\r\nend\r\nend"
      eval(code)
      pbAddScript(code,"PBMoves")
    end
    
    #~~ Pokémon Contests ~~ Required
    def pbCompileContestMoves
      records=[]
      contestmovenames=[]
      contestmovedescs=[]
      contestmovedata=[]
      maxValue=0
      haveRsAttacks=pbRgssExists?("Data/rsattacks.dat")
      pbCompilerEachPreppedLine("PBS/contestmoves.txt"){|line,lineno|
         thisline=line.clone
         record=[]
         flags=0
    
           record=pbGetCsvRecord(line,lineno,[0,"vnseUUUs",
              nil,nil,nil,["Cool","Beauty","Cute","Smart","Tough"],nil,nil,nil,nil
           ])
         
         maxValue=[maxValue,record[0]].max
         contestmovedata[record[0]]=[
            record[3],  # Contest Type
            record[4],  # Hearts
            record[5],  # Jam
            record[6]   # Function Code
         ].pack("CCCC")
         contestmovenames[record[0]]=record[2]  # Name
         contestmovedescs[record[0]]=record[7] # Description
         records.push(record)
         }
      defaultdata=[0,0,0,0].pack("CCCC")
      File.open("Data/contestmoves.dat","wb"){|file|
         for i in 0...contestmovedata.length
           file.write(contestmovedata[i] ? contestmovedata[i] : defaultdata)
         end
      }
      MessageTypes.setMessages(MessageTypes::ContestMoves,contestmovenames)
      MessageTypes.setMessages(MessageTypes::ContestMoveDescriptions,contestmovedescs)
      code="class PBContestMoves\r\n"
      for rec in records
        code+="#{rec[1]}=#{rec[0]}\r\n"
      end
      code+="\r\ndef self.getName(id)\r\nreturn pbGetMessage(MessageTypes::Moves,id)\r\nend"
      code+="\r\ndef self.getCount\r\nreturn #{records.length}\r\nend"
      code+="\r\ndef self.maxValue\r\nreturn #{maxValue}\r\nend\r\nend"
      eval(code)
      pbAddScript(code,"PBContestMoves")
    end
    #~~
    
    #===============================================================================
    # Compile items
    #===============================================================================
    class ItemList
      include Enumerable
    
      def initialize; @list=[]; end
      def length; @list.length; end
      def []=(x,v); @list[x]=v; end
     
      def [](x)
        if !@list[x]
          defrecord=SerialRecord.new
          defrecord.push(0)
          defrecord.push("????????")
          defrecord.push(0)
          defrecord.push(0)
          defrecord.push("????????")
          @list[x]=defrecord
          return defrecord
        end
        return @list[x]
      end
    
      def each
        for i in 0...self.length
          yield self[i]
        end
      end
    end
    
    
    
    def readItemList(filename)
      ret=ItemList.new
      if !pbRgssExists?(filename)
        return ret
      end
      pbRgssOpen(filename,"rb"){|file|
         numrec=file.fgetdw>>3
         curpos=0
         for i in 0...numrec
           file.pos=curpos
           offset=file.fgetdw
           length=file.fgetdw
           record=SerialRecord.decode(file,offset,length)
           ret[record[0]]=record
           curpos+=8
         end
      }
      return ret
    end
    
    def pbCompileItems
      records=[]
      constants=""
      itemnames=[]
      itempluralnames=[]
      itemdescs=[]
      maxValue=0
      pbCompilerEachCommentedLine("PBS/items.txt"){|line,lineno|
         linerecord=pbGetCsvRecord(line,lineno,[0,"vnssuusuuUN"])
         record=SerialRecord.new
         record[ITEMID]        = linerecord[0]
         constant=linerecord[1]
         constants+="#{constant}=#{record[0]}\r\n"
         record[ITEMNAME]      = linerecord[2]
         itemnames[record[0]]=linerecord[2]
         record[ITEMPLURAL]    = linerecord[3]
         itempluralnames[record[0]]=linerecord[3]
         record[ITEMPOCKET]    = linerecord[4]
         record[ITEMPRICE]     = linerecord[5]
         record[ITEMDESC]      = linerecord[6]
         itemdescs[record[0]]=linerecord[6]
         record[ITEMUSE]       = linerecord[7]
         record[ITEMBATTLEUSE] = linerecord[8]
         record[ITEMTYPE]      = linerecord[9]
         if linerecord[9]!="" && linerecord[10]
           record[ITEMMACHINE] = parseMove(linerecord[10])
         else
           record[ITEMMACHINE] = 0
         end
         maxValue=[maxValue,record[0]].max
         records.push(record)
      }
      MessageTypes.setMessages(MessageTypes::Items,itemnames)
      MessageTypes.setMessages(MessageTypes::ItemPlurals,itempluralnames)
      MessageTypes.setMessages(MessageTypes::ItemDescriptions,itemdescs)
      writeSerialRecords("Data/items.dat",records)
      code="class PBItems\r\n#{constants}"
      code+="\r\ndef PBItems.getName(id)\r\nreturn pbGetMessage(MessageTypes::Items,id)\r\nend\r\n"
      code+="\r\ndef PBItems.getNamePlural(id)\r\nreturn pbGetMessage(MessageTypes::ItemPlurals,id)\r\nend\r\n"
      code+="\r\ndef PBItems.getCount\r\nreturn #{records.length}\r\nend\r\n"
      code+="\r\ndef PBItems.maxValue\r\nreturn #{maxValue}\r\nend\r\nend"
      eval(code)
      pbAddScript(code,"PBItems")
      Graphics.update
    end
    
    #===============================================================================
    # Compile berry plants
    #===============================================================================
    def pbCompileBerryPlants
      sections=[]
      if File.exists?("PBS/berryplants.txt")
        pbCompilerEachCommentedLine("PBS/berryplants.txt"){|line,lineno|
           if line[ /^([^=]+)=(.*)$/ ]
             key=$1
             value=$2
             value=value.split(",")
             for i in 0...value.length
               value[i].sub!(/^\s*/){}
               value[i].sub!(/\s*$/){}
               value[i]=value[i].to_i
             end
             item=parseItem(key)
             sections[item]=value
           end
        }
      end
      save_data(sections,"Data/berryplants.dat")
    end
    
    #===============================================================================
    # Compile Pokémon
    #===============================================================================
    def pbCompilePokemonData
      # Free bytes: 0, 1, 17, 29, 30, 37, 56-75
      sections=[]
      requiredtypes={
         "Name"=>[0,"s"],
         "Kind"=>[0,"s"],
         "InternalName"=>[0,"c"],
         "Pokedex"=>[0,"S"],
         "Moves"=>[0,"*uE",nil,PBMoves],
         "Color"=>[6,"e",PBColors],
         "Type1"=>[8,"e",PBTypes],
         "BaseStats"=>[10,"uuuuuu"],
         "Rareness"=>[16,"u"],
         "GenderRate"=>[18,"e",{"AlwaysMale"=>0,"FemaleOneEighth"=>31,
            "Female25Percent"=>63,"Female50Percent"=>127,"Female75Percent"=>191,
            "FemaleSevenEighths"=>223,"AlwaysFemale"=>254,"Genderless"=>255}],
         "Happiness"=>[19,"u"],
         "GrowthRate"=>[20,"e",{"Medium"=>0,"MediumFast"=>0,"Erratic"=>1,
            "Fluctuating"=>2,"Parabolic"=>3,"MediumSlow"=>3,"Fast"=>4,"Slow"=>5}],
         "StepsToHatch"=>[21,"w"],
         "EffortPoints"=>[23,"uuuuuu"],
         "Compatibility"=>[31,"eg",PBEggGroups,PBEggGroups],
         "Height"=>[33,"f"],
         "Weight"=>[35,"f"],
         "BaseEXP"=>[38,"w"],
      }
      optionaltypes={
         "BattlerPlayerY"=>[0,"i"],
         "BattlerEnemyY"=>[0,"i"],
         "BattlerAltitude"=>[0,"i"],
         "EggMoves"=>[0,"*E",PBMoves],
         "FormNames"=>[0,"S"],
         "RegionalNumbers"=>[0,"*w"],
         "Evolutions"=>[0,"*ses",nil,PBEvolution],
         "Abilities"=>[2,"EG",PBAbilities,PBAbilities],
         "Habitat"=>[7,"e",["","Grassland","Forest","WatersEdge","Sea","Cave","Mountain","RoughTerrain","Urban","Rare"]],
         "Type2"=>[9,"e",PBTypes],
         "HiddenAbility"=>[40,"EGGG",PBAbilities,PBAbilities,PBAbilities,PBAbilities],
         "WildItemCommon"=>[48,"E",PBItems],
         "WildItemUncommon"=>[50,"E",PBItems],
         "WildItemRare"=>[52,"E",PBItems],
         "Incense"=>[54,"E",PBItems]
      }
      currentmap=-1
      dexdatas=[]
      eggmoves=[]
      entries=[]
      kinds=[]
      speciesnames=[]
      moves=[]
      evolutions=[]
      regionals=[]
      formnames=[]
      metrics=[SignedWordArray.new,SignedWordArray.new,SignedWordArray.new]
      constants=""
      maxValue=0
      File.open("PBS/pokemon.txt","rb"){|f|
         FileLineData.file="PBS/pokemon.txt"
         pbEachFileSection(f){|lastsection,currentmap|
            dexdata=[]
            for i in 0...76
              dexdata[i]=0
            end
            thesemoves=[]
            theseevos=[]
            if !lastsection["Type2"] || lastsection["Type2"]==""
              if !lastsection["Type1"] || lastsection["Type1"]==""
                raise _INTL("No Pokémon type is defined in section {2} (PBS/pokemon.txt)",key,sectionDisplay) if hash==requiredtypes
                next
              end
              lastsection["Type2"]=lastsection["Type1"].clone
            end
            [requiredtypes,optionaltypes].each{|hash|
               for key in hash.keys
                 FileLineData.setSection(currentmap,key,lastsection[key])
                 maxValue=[maxValue,currentmap].max
                 sectionDisplay=currentmap.to_s
                 next if hash[key][0]<0
                 if currentmap==0
                   raise _INTL("A Pokemon species can't be numbered 0 (PBS/pokemon.txt)")
                 end
                 if !lastsection[key] || lastsection[key]==""
                   raise _INTL("Required entry {1} is missing or empty in section {2} (PBS/pokemon.txt)",key,sectionDisplay) if hash==requiredtypes
                   next
                 end
                 secvalue=lastsection[key]
                 rtschema=hash[key]
                 schema=hash[key][1]
                 valueindex=0
                 loop do
                   offset=0
                   for i in 0...schema.length
                     next if schema[i,1]=="*"
                     minus1=(schema[0,1]=="*") ? -1 : 0
                     if (schema[i,1]=="g" || schema[i,1]=="G") && secvalue==""
                       if key=="Compatibility"
                         dexdata[rtschema[0]+offset]=dexdata[rtschema[0]]
                       end
                       break
                     end
                     case schema[i,1]
                     when "e", "g"
                       value=csvEnumField!(secvalue,rtschema[2+i+minus1],key,sectionDisplay)
                       bytes=1
                     when "E", "G"
                       value=csvEnumField!(secvalue,rtschema[2+i+minus1],key,sectionDisplay)
                       bytes=2
                     when "i"
                       value=csvInt!(secvalue,key)
                       bytes=1
                     when "u"
                       value=csvPosInt!(secvalue,key)
                       bytes=1
                     when "w"
                       value=csvPosInt!(secvalue,key)
                       bytes=2
                     when "f"
                       value=csvFloat!(secvalue,key,sectionDisplay)
                       value=(value*10).round
                       if value<=0
                         raise _INTL("Value '{1}' can't be less than or close to 0 (section {2}, PBS/pokemon.txt)",key,currentmap)
                       end
                       bytes=2
                     when "c", "s"
                       value=csvfield!(secvalue)
                     when "S"
                       value=secvalue
                       secvalue=""
                     end
                     if key=="EggMoves"
                       eggmoves[currentmap]=[] if !eggmoves[currentmap]
                       eggmoves[currentmap].push(value)
                     elsif key=="Moves"
                       thesemoves.push(value)
                     elsif key=="RegionalNumbers"
                       regionals[valueindex]=[] if !regionals[valueindex]
                       regionals[valueindex][currentmap]=value
                     elsif key=="Evolutions"
                       theseevos.push(value)
                     elsif key=="InternalName"
                       raise _INTL("Invalid internal name: {1} (section {2}, PBS/pokemon.txt)",value,currentmap) if !value[/^(?![0-9])\w*$/]
                       constants+="#{value}=#{currentmap}\r\n"
                     elsif key=="Kind"
                       raise _INTL("Kind {1} is greater than 20 characters long (section {2}, PBS/pokemon.txt)",value,currentmap) if value.length>20
                       kinds[currentmap]=value
                     elsif key=="Pokedex"
                       entries[currentmap]=value
                     elsif key=="BattlerPlayerY"
                       pbCheckSignedWord(value,key)
                       metrics[0][currentmap]=value
                     elsif key=="BattlerEnemyY"
                       pbCheckSignedWord(value,key)
                       metrics[1][currentmap]=value
                     elsif key=="BattlerAltitude"
                       pbCheckSignedWord(value,key)
                       metrics[2][currentmap]=value
                     elsif key=="Name"
                       raise _INTL("Species name {1} is greater than 20 characters long (section {2}, PBS/pokemon.txt)",value,currentmap) if value.length>20
                       speciesnames[currentmap]=value
                     elsif key=="FormNames"
                       formnames[currentmap]=value
                     else
                       dexdata[rtschema[0]+offset]=value&0xFF
                       dexdata[rtschema[0]+1+offset]=(value>>8)&0xFF if bytes>1
                       offset+=bytes
                     end
                     valueindex+=1
                   end
                   break if secvalue==""
                   break if schema[0,1]!="*"
                 end
               end
            }
            movelist=[]
            evolist=[]
            for i in 0...thesemoves.length/2
              movelist.push([thesemoves[i*2],thesemoves[i*2+1],i])
            end
            movelist.sort!{|a,b| a[0]==b[0] ? a[2]<=>b[2] : a[0]<=>b[0]}
            for i in movelist; i.pop; end
            for i in 0...theseevos.length/3
              evolist.push([theseevos[i*3],theseevos[i*3+1],theseevos[i*3+2]])
            end
            moves[currentmap]=movelist
            evolutions[currentmap]=evolist
            dexdatas[currentmap]=dexdata
         }
      }
      if dexdatas.length==0
        raise _INTL("No Pokémon species are defined in pokemon.txt")
      end
      count=dexdatas.compact.length
      code="module PBSpecies\r\n#{constants}"
      for i in 0...speciesnames.length
        speciesnames[i]="????????" if !speciesnames[i]
      end
      code+="def PBSpecies.getName(id)\r\nreturn pbGetMessage(MessageTypes::Species,id)\r\nend\r\n"
      code+="def PBSpecies.getCount\r\nreturn #{count}\r\nend\r\n"
      code+="def PBSpecies.maxValue\r\nreturn #{maxValue}\r\nend\r\nend"
      eval(code)
      pbAddScript(code,"PBSpecies")
      for e in 0...evolutions.length
        evolist=evolutions[e]
        next if !evolist
        for i in 0...evolist.length
          FileLineData.setSection(i,"Evolutions","")
          evonib=evolist[i][1]
          evolist[i][0]=csvEnumField!(evolist[i][0],PBSpecies,"Evolutions",i)
          case PBEvolution::EVOPARAM[evonib]
          when 1
            evolist[i][2]=csvPosInt!(evolist[i][2])
          when 2
            evolist[i][2]=csvEnumField!(evolist[i][2],PBItems,"Evolutions",i)
          when 3
            evolist[i][2]=csvEnumField!(evolist[i][2],PBMoves,"Evolutions",i)
          when 4
            evolist[i][2]=csvEnumField!(evolist[i][2],PBSpecies,"Evolutions",i)
          when 5
            evolist[i][2]=csvEnumField!(evolist[i][2],PBTypes,"Evolutions",i)
          else
            evolist[i][2]=0
          end
          evolist[i][3]=0
        end
      end
      _EVODATAMASK=0xC0
      _EVONEXTFORM=0x00
      _EVOPREVFORM=0x40
      for e in 0...evolutions.length
        evolist=evolutions[e]
        next if !evolist
        parent=nil
        child=-1
        for f in 0...evolutions.length
          evolist=evolutions[f]
          next if !evolist || e==f
          for g in evolist
            if g[0]==e && (g[3]&_EVODATAMASK)==_EVONEXTFORM
              parent=g
              child=f
              break
            end
          end
          break if parent
        end
        if parent
          evolutions[e]=[[child,parent[1],parent[2],_EVOPREVFORM]].concat(evolutions[e])
        end
      end
      metrics[0].fillNils(dexdatas.length,0) # player Y
      metrics[1].fillNils(dexdatas.length,0) # enemy Y
      metrics[2].fillNils(dexdatas.length,0) # altitude
      save_data(metrics,"Data/metrics.dat")
      File.open("Data/regionals.dat","wb"){|f|
         f.fputw(regionals.length)
         f.fputw(dexdatas.length)
         for i in 0...regionals.length
           for j in 0...dexdatas.length
             num=regionals[i][j]
             num=0 if !num
             f.fputw(num)
           end
         end
      }
      File.open("Data/evolutions.dat","wb"){|f|
         mx=[maxValue,evolutions.length-1].max
         offset=mx*8
         for i in 1..mx
           f.fputdw(offset)
           f.fputdw(evolutions[i] ? evolutions[i].length*5 : 0)
           offset+=evolutions[i] ? evolutions[i].length*5 : 0
         end
         for i in 1..mx
           next if !evolutions[i]
           for j in evolutions[i]
             f.fputb(j[3]|j[1])
             f.fputw(j[2])
             f.fputw(j[0])
           end
         end
      }
      File.open("Data/dexdata.dat","wb"){|f|
         mx=[maxValue,dexdatas.length-1].max
         for i in 1..mx
           if dexdatas[i]
             dexdatas[i].each {|item| f.fputb(item)}
           else
             76.times { f.fputb(0) }
           end
         end
      }
      File.open("Data/eggEmerald.dat","wb"){|f|
         mx=[maxValue,eggmoves.length-1].max
         offset=mx*8
         for i in 1..mx
           f.fputdw(offset)
           f.fputdw(eggmoves[i] ? eggmoves[i].length : 0)
           offset+=eggmoves[i] ? eggmoves[i].length*2 : 0
         end
         for i in 1..mx
           next if !eggmoves[i]
           for j in eggmoves[i]
             f.fputw(j)
           end
         end
      }
      MessageTypes.setMessages(MessageTypes::Species,speciesnames)
      MessageTypes.setMessages(MessageTypes::Kinds,kinds)
      MessageTypes.setMessages(MessageTypes::Entries,entries)
      MessageTypes.setMessages(MessageTypes::FormNames,formnames)
      File.open("Data/attacksRS.dat","wb"){|f|
         mx=[maxValue,moves.length-1].max
         offset=mx*8
         for i in 1..mx
           f.fputdw(offset)
           f.fputdw(moves[i] ? moves[i].length*2 : 0)
           offset+=moves[i] ? moves[i].length*4 : 0
         end
         for i in 1..mx
           next if !moves[i]
           for j in moves[i]
             f.fputw(j[0])
             f.fputw(j[1])
           end
         end
      }
    end
    
    #===============================================================================
    # Compile TM/TM/Move Tutor compatibilities
    #===============================================================================
    def pbTMRS   # Backup Gen 3 TM list
      rstm=[# TMs
            :FOCUSPUNCH,:DRAGONCLAW,:WATERPULSE,:CALMMIND,:ROAR,
            :TOXIC,:HAIL,:BULKUP,:BULLETSEED,:HIDDENPOWER,
            :SUNNYDAY,:TAUNT,:ICEBEAM,:BLIZZARD,:HYPERBEAM,
            :LIGHTSCREEN,:PROTECT,:RAINDANCE,:GIGADRAIN,:SAFEGUARD,
            :FRUSTRATION,:SOLARBEAM,:IRONTAIL,:THUNDERBOLT,:THUNDER,
            :EARTHQUAKE,:RETURN,:DIG,:PSYCHIC,:SHADOWBALL,
            :BRICKBREAK,:DOUBLETEAM,:REFLECT,:SHOCKWAVE,:FLAMETHROWER,
            :SLUDGEBOMB,:SANDSTORM,:FIREBLAST,:ROCKTOMB,:AERIALACE,
            :TORMENT,:FACADE,:SECRETPOWER,:REST,:ATTRACT,
            :THIEF,:STEELWING,:SKILLSWAP,:SNATCH,:OVERHEAT,
            # HMs
            :CUT,:FLY,:SURF,:STRENGTH,:FLASH,:ROCKSMASH,:WATERFALL,:DIVE]
      ret=[]
      for i in 0...rstm.length
        ret.push((parseMove(rstm.to_s) rescue 0))
      end
      return ret
    end
    
    def pbCompileMachines
      lineno=1
      havesection=false
      sectionname=nil
      sections=[]
      if safeExists?("PBS/tm.txt")
        f=File.open("PBS/tm.txt","rb")
        FileLineData.file="PBS/tm.txt"
        f.each_line {|line|
           if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
             line=line[3,line.length-3]
           end
           FileLineData.setLine(line,lineno)
           if !line[/^\#/] && !line[/^\s*$/]
             if line[/^\s*\[\s*(.*)\s*\]\s*$/]
               sectionname=parseMove($~[1])
               sections[sectionname]=WordArray.new
               havesection=true
             else
               if sectionname==nil
                 raise _INTL("Expected a section at the beginning of the file. This error may also occur if the file was not saved in UTF-8.\r\n{1}",FileLineData.linereport)
               end
               specieslist=line.sub(/\s+$/,"").split(",")
               for species in specieslist
                 next if !species || species==""
                 sec=sections[sectionname]
                 sec[sec.length]=parseSpecies(species)
               end
             end
           end
           lineno+=1
           if lineno%500==0
             Graphics.update
           end
           if lineno%50==0
             Win32API.SetWindowText(_INTL("Processing line {1}",lineno))
           end
        }
        f.close
      elsif safeExists?("Data/tmRS.dat")
        tmrs=pbTMRS()
        for i in 0...58
          next if !tmrs[i] || tmrs[i]==0
          sections[tmrs[i]]=[]
        end
        File.open("Data/tmRS.dat","rb"){|f|
           species=1
           while !f.eof?
             data=f.read(8)+"\0\0\0\0\0\0\0\0"
             for i in 0...58
               next if !tmrs[i] || tmrs[i]==0
               if (data[i>>3]&(1<<(i&7)))!=0
                 sections[tmrs[i]].push(species)
               end
             end
             species+=1
           end
        }
      end
      save_data(sections,"Data/tm.dat")
    end
    
    #===============================================================================
    # Extract trainer types to PBS file, compile trainer types and individual trainers
    #===============================================================================
    def pbExtractTrainers
      trainertypes=nil
      pbRgssOpen("Data/trainertypes.dat","rb"){|f|
         trainertypes=Marshal.load(f)
      }
      return if !trainertypes
      File.open("trainertypes.txt","wb"){|f|
         f.write(0xEF.chr)
         f.write(0xBB.chr)
         f.write(0xBF.chr)
         for i in 0...trainertypes.length
           next if !trainertypes[i]
           record=trainertypes[i]
           begin
             cnst=getConstantName(PBTrainers,record[0])
           rescue
             next
           end
           f.write(sprintf("%d,%s,%s,%d,%s,%s,%s,%s\r\n",
              record[0],csvquote(cnst),csvquote(record[2]),
              record[3],csvquote(record[4]),csvquote(record[5]),csvquote(record[6]),
              record[7] ? ["Male","Female","Mixed"][record[7]] : "Mixed"
           ))
         end
      }
    end
    
    def pbCompileTrainers
      # Trainer types
      records=[]
      trainernames=[]
      count=0
      maxValue=0
      pbCompilerEachPreppedLine("PBS/trainertypes.txt"){|line,lineno|
         record=pbGetCsvRecord(line,lineno,[0,"unsUSSSeUs", # ID can be 0
            nil,nil,nil,nil,nil,nil,nil,{
            ""=>2,"Male"=>0,"M"=>0,"0"=>0,"Female"=>1,"F"=>1,"1"=>1,"Mixed"=>2,"X"=>2,"2"=>2
            },nil,nil]
         )
         if record[3] && (record[3]<0 || record[3]>255)
           raise _INTL("Bad money amount (must be from 0 through 255)\r\n{1}",FileLineData.linereport)
         end
         record[3]=30 if !record[3]
         if record[8] && (record[8]<0 || record[8]>255)
           raise _INTL("Bad skill value (must be from 0 through 255)\r\n{1}",FileLineData.linereport)
         end
         record[8]=record[3] if !record[8]
         record[9]="" if !record[9]
         trainernames[record[0]]=record[2]
         if records[record[0]]
           raise _INTL("Two trainer types ({1} and {2}) have the same ID ({3}), which is not allowed.\r\n{4}",
              records[record[0]][1],record[1],record[0],FileLineData.linereport)
         end
         records[record[0]]=record
         maxValue=[maxValue,record[0]].max
      }
      count=records.compact.length
      MessageTypes.setMessages(MessageTypes::TrainerTypes,trainernames)
      code="class PBTrainers\r\n"
      for rec in records
        next if !rec
        code+="#{rec[1]}=#{rec[0]}\r\n"
      end
      code+="\r\ndef PBTrainers.getName(id)\r\nreturn pbGetMessage(MessageTypes::TrainerTypes,id)\r\nend"
      code+="\r\ndef PBTrainers.getCount\r\nreturn #{count}\r\nend"
      code+="\r\ndef PBTrainers.maxValue\r\nreturn #{maxValue}\r\nend\r\nend"
      eval(code)
      pbAddScript(code,"PBTrainers")
      File.open("Data/trainertypes.dat","wb"){|f|
         Marshal.dump(records,f)
      }
      # Individual trainers
      lines=[]
      linenos=[]
      lineno=1
      File.open("PBS/trainers.txt","rb"){|f|
         FileLineData.file="PBS/trainers.txt"
         f.each_line {|line|
            if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
              line=line[3,line.length-3]
            end
            line=prepline(line)
            if line!=""
              lines.push(line)
              linenos.push(lineno)
            end
            lineno+=1
         }
      }
      nameoffset=0
      trainers=[]
      trainernames.clear
      i=0; loop do break unless i<lines.length
        FileLineData.setLine(lines[i],linenos[i])
        trainername=parseTrainer(lines[i])
        FileLineData.setLine(lines[i+1],linenos[i+1])
        nameline=strsplit(lines[i+1],/\s*,\s*/)
        name=nameline[0]
        raise _INTL("Trainer name too long\r\n{1}",FileLineData.linereport) if name.length>=0x10000
        trainernames.push(name)
        partyid=0
        if nameline[1] && nameline[1]!=""
          raise _INTL("Expected a number for the trainer battle ID\r\n{1}",FileLineData.linereport) if !nameline[1][/^\d+$/]
          partyid=nameline[1].to_i
        end
        FileLineData.setLine(lines[i+2],linenos[i+2])
        items=strsplit(lines[i+2],/\s*,\s*/)
        items[0].gsub!(/^\s+/,"")   # Number of Pokémon
        raise _INTL("Expected a number for the number of Pokémon\r\n{1}",FileLineData.linereport) if !items[0][/^\d+$/]
        numpoke=items[0].to_i
        realitems=[]
        for j in 1...items.length   # Items held by Trainer
          realitems.push(parseItem(items[j])) if items[j] && items[j]!=""
        end
        pkmn=[]
        for j in 0...numpoke
          FileLineData.setLine(lines[i+j+3],linenos[i+j+3])
          poke=strsplit(lines[i+j+3],/\s*,\s*/)
          begin
            # Species
            poke[TPSPECIES]=parseSpecies(poke[TPSPECIES])
          rescue
            raise _INTL("Expected a species name: {1}\r\n{2}",poke[0],FileLineData.linereport)
          end
          # Level
          poke[TPLEVEL]=poke[TPLEVEL].to_i
          raise _INTL("Bad level: {1} (must be from 1-{2})\r\n{3}",poke[TPLEVEL],
            PBExperience::MAXLEVEL,FileLineData.linereport) if poke[TPLEVEL]<=0 || poke[TPLEVEL]>PBExperience::MAXLEVEL
          # Held item
          if !poke[TPITEM] || poke[TPITEM]==""
            poke[TPITEM]=TPDEFAULTS[TPITEM]
          else
            poke[TPITEM]=parseItem(poke[TPITEM])
          end
          # Moves
          moves=[]
          for j in [TPMOVE1,TPMOVE2,TPMOVE3,TPMOVE4]
            moves.push(parseMove(poke[j])) if poke[j] && poke[j]!=""
          end
          for j in 0...4
            index=[TPMOVE1,TPMOVE2,TPMOVE3,TPMOVE4][j]
            if moves[j] && moves[j]!=0
              poke[index]=moves[j]
            else
              poke[index]=TPDEFAULTS[index]
            end
          end
          # Ability
          if !poke[TPABILITY] || poke[TPABILITY]==""
            poke[TPABILITY]=TPDEFAULTS[TPABILITY]
          else
            poke[TPABILITY]=poke[TPABILITY].to_i
            raise _INTL("Bad abilityflag: {1} (must be 0 or 1 or 2-5)\r\n{2}",poke[TPABILITY],FileLineData.linereport) if poke[TPABILITY]<0 || poke[TPABILITY]>5
          end
          # Gender
          if !poke[TPGENDER] || poke[TPGENDER]==""
            poke[TPGENDER]=TPDEFAULTS[TPGENDER]
          else
            if poke[TPGENDER]=="M"
              poke[TPGENDER]=0
            elsif poke[TPGENDER]=="F"
              poke[TPGENDER]=1
            else
              poke[TPGENDER]=poke[TPGENDER].to_i
              raise _INTL("Bad genderflag: {1} (must be M or F, or 0 or 1)\r\n{2}",poke[TPGENDER],FileLineData.linereport) if poke[TPGENDER]<0 || poke[TPGENDER]>1
            end
          end
          # Form
          if !poke[TPFORM] || poke[TPFORM]==""
            poke[TPFORM]=TPDEFAULTS[TPFORM]
          else
            poke[TPFORM]=poke[TPFORM].to_i
            raise _INTL("Bad form: {1} (must be 0 or greater)\r\n{2}",poke[TPFORM],FileLineData.linereport) if poke[TPFORM]<0
          end
          # Shiny
          if !poke[TPSHINY] || poke[TPSHINY]==""
            poke[TPSHINY]=TPDEFAULTS[TPSHINY]
          elsif poke[TPSHINY]=="shiny"
            poke[TPSHINY]=true
          else
            poke[TPSHINY]=csvBoolean!(poke[TPSHINY].clone)
          end
          # Nature
          if !poke[TPNATURE] || poke[TPNATURE]==""
            poke[TPNATURE]=TPDEFAULTS[TPNATURE]
          else
            poke[TPNATURE]=parseNature(poke[TPNATURE])
          end
          # IVs
          if !poke[TPIV] || poke[TPIV]==""
            poke[TPIV]=TPDEFAULTS[TPIV]
          else
            poke[TPIV]=poke[TPIV].to_i
            raise _INTL("Bad IV: {1} (must be from 0-31)\r\n{2}",poke[TPIV],FileLineData.linereport) if poke[TPIV]<0 || poke[TPIV]>31
          end
          # Happiness
          if !poke[TPHAPPINESS] || poke[TPHAPPINESS]==""
            poke[TPHAPPINESS]=TPDEFAULTS[TPHAPPINESS]
          else
            poke[TPHAPPINESS]=poke[TPHAPPINESS].to_i
            raise _INTL("Bad happiness: {1} (must be from 0-255)\r\n{2}",poke[TPHAPPINESS],FileLineData.linereport) if poke[TPHAPPINESS]<0 || poke[TPHAPPINESS]>255
          end
          # Nickname
          if !poke[TPNAME] || poke[TPNAME]==""
            poke[TPNAME]=TPDEFAULTS[TPNAME]
          else
            poke[TPNAME]=poke[TPNAME].to_s
            raise _INTL("Bad nickname: {1} (must be 1-20 characters)\r\n{2}",poke[TPNAME],FileLineData.linereport) if (poke[TPNAME].to_s).length>20
          end
          # Shadow
          if !poke[TPSHADOW] || poke[TPSHADOW]==""
            poke[TPSHADOW]=TPDEFAULTS[TPSHADOW]
          else
            poke[TPSHADOW]=csvBoolean!(poke[TPSHADOW].clone)
          end
          # Ball
          if !poke[TPBALL] || poke[TPBALL]==""
            poke[TPBALL]=TPDEFAULTS[TPBALL]
          else
            poke[TPBALL]=poke[TPBALL].to_i
            raise _INTL("Bad form: {1} (must be 0 or greater)\r\n{2}",poke[TPBALL],FileLineData.linereport) if poke[TPBALL]<0
          end
          pkmn.push(poke)
        end
        i+=3+numpoke
        MessageTypes.setMessagesAsHash(MessageTypes::TrainerNames,trainernames)
        trainers.push([trainername,name,realitems,pkmn,partyid])
        nameoffset+=name.length
      end
      save_data(trainers,"Data/trainers.dat")
    end
    
    #===============================================================================
    # Compile phone messages
    #===============================================================================
    def pbCompilePhoneData
      return if !safeExists?("PBS/phone.txt")
      database=PhoneDatabase.new
      sections=[]
      File.open("PBS/phone.txt","rb"){|f|
         pbEachSection(f){|section,name|
            if name=="<Generics>"
              database.generics=section
              sections.concat(section)
            elsif name=="<BattleRequests>"
              database.battleRequests=section 
              sections.concat(section)
            elsif name=="<GreetingsMorning>"
              database.greetingsMorning=section 
              sections.concat(section)
            elsif name=="<GreetingsEvening>"
              database.greetingsEvening=section 
              sections.concat(section)
            elsif name=="<Greetings>"
              database.greetings=section
              sections.concat(section)
            elsif name=="<Bodies1>"
              database.bodies1=section 
              sections.concat(section)
            elsif name=="<Bodies2>"
              database.bodies2=section 
              sections.concat(section)
            end
         }
      }
      MessageTypes.setMessagesAsHash(MessageTypes::PhoneMessages,sections)
      save_data(database,"Data/phone.dat")
    end
    
    #===============================================================================
    # Compile metadata
    #===============================================================================
    class PBTrainers; end
    
    
    
    def pbCompileMetadata
      sections=[]
      currentmap=-1
      pbCompilerEachCommentedLine("PBS/metadata.txt") {|line,lineno|
         if line[/^\s*\[\s*(\d+)\s*\]\s*$/]
           sectionname=$~[1]
           if currentmap==0
             if sections[currentmap][MetadataHome]==nil
               raise _INTL("The entry Home is required in metadata.txt section [{1}]",sectionname)
             end
             if sections[currentmap][MetadataPlayerA]==nil
               raise _INTL("The entry PlayerA is required in metadata.txt section [{1}]",sectionname)
             end
           end
           currentmap=sectionname.to_i
           sections[currentmap]=[]
         else
           if currentmap<0
             raise _INTL("Expected a section at the beginning of the file\r\n{1}",FileLineData.linereport)
           end
           if !line[/^\s*(\w+)\s*=\s*(.*)$/]
             raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}",FileLineData.linereport)
           end
           matchData=$~
           schema=nil
           FileLineData.setSection(currentmap,matchData[1],matchData[2])
           if currentmap==0
             schema=PokemonMetadata::GlobalTypes[matchData[1]]
           else
             schema=PokemonMetadata::NonGlobalTypes[matchData[1]]
           end
           if schema
             record=pbGetCsvRecord(matchData[2],lineno,schema)
             sections[currentmap][schema[0]]=record
           end
         end
      }
      File.open("Data/metadata.dat","wb"){|f|
         Marshal.dump(sections,f)
      }
    end
    
    #===============================================================================
    # Compile Battle Tower and other Cups trainers/Pokémon
    #===============================================================================
    def pbCompileBTTrainers(filename)
      sections=[]
      btTrainersRequiredTypes={
         "Type"=>[0,"e",PBTrainers],
         "Name"=>[1,"s"],
         "BeginSpeech"=>[2,"s"],
         "EndSpeechWin"=>[3,"s"],
         "EndSpeechLose"=>[4,"s"],
         "PokemonNos"=>[5,"*u"]
      }
      requiredtypes=btTrainersRequiredTypes
      trainernames=[]
      beginspeech=[]
      endspeechwin=[]
      endspeechlose=[]
      if safeExists?(filename)
        File.open(filename,"rb"){|f|
           FileLineData.file=filename
           pbEachFileSectionEx(f){|section,name|
              rsection=[]
              for key in section.keys
                FileLineData.setSection(name,key,section[key])
                schema=requiredtypes[key]
                next if !schema
                record=pbGetCsvRecord(section[key],0,schema)
                rsection[schema[0]]=record  
              end
              trainernames.push(rsection[1]) 
              beginspeech.push(rsection[2])
              endspeechwin.push(rsection[3])
              endspeechlose.push(rsection[4])
              sections.push(rsection)
           }
        }
      end
      MessageTypes.addMessagesAsHash(MessageTypes::TrainerNames,trainernames)
      MessageTypes.addMessagesAsHash(MessageTypes::BeginSpeech,beginspeech)
      MessageTypes.addMessagesAsHash(MessageTypes::EndSpeechWin,endspeechwin)
      MessageTypes.addMessagesAsHash(MessageTypes::EndSpeechLose,endspeechlose)
      return sections
    end
    
    def pbCompileTrainerLists
      btTrainersRequiredTypes={
         "Trainers"=>[0,"s"],
         "Pokemon"=>[1,"s"],
         "Challenges"=>[2,"*s"]
      }
      if !safeExists?("PBS/trainerlists.txt")
        File.open("PBS/trainerlists.txt","wb"){|f|
           f.write(0xEF.chr)
           f.write(0xBB.chr)
           f.write(0xBF.chr)
           f.write("[DefaultTrainerList]\r\nTrainers=bttrainers.txt\r\nPokemon=btpokemon.txt\r\n")
        }
      end
      database=[]
      sections=[]
      MessageTypes.setMessagesAsHash(MessageTypes::BeginSpeech,[])
      MessageTypes.setMessagesAsHash(MessageTypes::EndSpeechWin,[])
      MessageTypes.setMessagesAsHash(MessageTypes::EndSpeechLose,[])
      File.open("PBS/trainerlists.txt","rb"){|f|
         pbEachFileSectionEx(f){|section,name|
            next if name!="DefaultTrainerList" && name!="TrainerList"
            rsection=[]
            for key in section.keys
              FileLineData.setSection(name,key,section[key])
              schema=btTrainersRequiredTypes[key]
              next if key=="Challenges" && name=="DefaultTrainerList"
              next if !schema
              record=pbGetCsvRecord(section[key],0,schema)
              rsection[schema[0]]=record  
            end
            if !rsection[0]
              raise _INTL("No trainer data file given in section {1}\r\n{2}",name,FileLineData.linereport)
            end
            if !rsection[1]
              raise _INTL("No trainer data file given in section {1}\r\n{2}",name,FileLineData.linereport)
            end
            rsection[3]=rsection[0]
            rsection[4]=rsection[1]
            rsection[5]=(name=="DefaultTrainerList")
            if safeExists?("PBS/"+rsection[0])
              rsection[0]=pbCompileBTTrainers("PBS/"+rsection[0])
            else
              rsection[0]=[]
            end
            if safeExists?("PBS/"+rsection[1])
              filename="PBS/"+rsection[1]
              rsection[1]=[]
              pbCompilerEachCommentedLine(filename){|line,lineno|
                 rsection[1].push(PBPokemon.fromInspected(line))
              }
            else
              rsection[1]=[]
            end
            if !rsection[2]
              rsection[2]=[]
            end
            while rsection[2].include?("")
              rsection[2].delete("")
            end
            rsection[2].compact!
            sections.push(rsection)
         }
      }
      save_data(sections,"Data/trainerlists.dat")
    end
    
    #===============================================================================
    # Compile wild encounters
    #===============================================================================
    def pbCompileEncounters
      lines=[]
      linenos=[]
      FileLineData.file="PBS/encounters.txt"
      File.open("PBS/encounters.txt","rb"){|f|
         lineno=1
         f.each_line {|line|
            if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
              line=line[3,line.length-3]
            end
            line=prepline(line)
            if line.length!=0
              lines[lines.length]=line
              linenos[linenos.length]=lineno
            end
            lineno+=1
         }
      }
      encounters={}
      thisenc=nil
      lastenc=-1
      lastenclen=0
      needdensity=false
      lastmapid=-1
      i=0;
      while i<lines.length
        line=lines[i]
        FileLineData.setLine(line,linenos[i])
        mapid=line[/^\d+$/]
        if mapid
          lastmapid=mapid
          if thisenc && (thisenc[1][EncounterTypes::Land] ||
                         thisenc[1][EncounterTypes::LandMorning] ||
                         thisenc[1][EncounterTypes::LandDay] ||
                         thisenc[1][EncounterTypes::LandNight] ||
                         thisenc[1][EncounterTypes::BugContest]) &&
                         thisenc[1][EncounterTypes::Cave]
            raise _INTL("Can't define both Land and Cave encounters in the same area (map ID {1})",mapid)
          end
          thisenc=[EncounterTypes::EnctypeDensities.clone,[]]
          encounters[mapid.to_i]=thisenc
          needdensity=true
          i+=1
          next
        end
        enc=findIndex(EncounterTypes::Names){|val| val==line}
        if enc>=0
          needdensity=false
          enclines=EncounterTypes::EnctypeChances[enc].length
          encarray=[]
          j=i+1; k=0
          while j<lines.length && k<enclines
            line=lines[j]
            FileLineData.setLine(lines[j],linenos[j])
            splitarr=strsplit(line,/\s*,\s*/)
            if !splitarr || splitarr.length<2
              raise _INTL("In encounters.txt, expected a species entry line,\r\ngot \"{1}\" instead (probably too few entries in an encounter type).\r\nPlease check the format of the section numbered {2},\r\nwhich is just before this line.\r\n{3}",
                 line,lastmapid,FileLineData.linereport)
            end
            splitarr[2]=splitarr[1] if splitarr.length==2
            splitarr[1]=splitarr[1].to_i
            splitarr[2]=splitarr[2].to_i
            maxlevel=PBExperience::MAXLEVEL
            if splitarr[1]<=0 || splitarr[1]>maxlevel
              raise _INTL("Level number is not valid: {1}\r\n{2}",splitarr[1],FileLineData.linereport)
            end
            if splitarr[2]<=0 || splitarr[2]>maxlevel
              raise _INTL("Level number is not valid: {1}\r\n{2}",splitarr[2],FileLineData.linereport)
            end
            if splitarr[1]>splitarr[2]
              raise _INTL("Minimum level is greater than maximum level: {1}\r\n{2}",line,FileLineData.linereport)
            end
            splitarr[0]=parseSpecies(splitarr[0])
            linearr=splitarr
            encarray.push(linearr)
            thisenc[1][enc]=encarray
            j+=1
            k+=1
          end
          if j==lines.length && k<enclines
             raise _INTL("Reached end of file unexpectedly. There were too few entries in the last section, expected {1} entries.\r\nPlease check the format of the section numbered {2}.\r\n{3}",
                enclines,lastmapid,FileLineData.linereport)
          end
          i=j
        elsif needdensity
          needdensity=false
          nums=strsplit(line,/,/)
          if nums && nums.length>=3
            for j in 0...EncounterTypes::EnctypeChances.length
              next if !EncounterTypes::EnctypeChances[j] ||
                      EncounterTypes::EnctypeChances[j].length==0
              next if EncounterTypes::EnctypeCompileDens[j]==0
              thisenc[0][j]=nums[EncounterTypes::EnctypeCompileDens[j]-1].to_i
            end
          else
            raise _INTL("Wrong syntax for densities in encounters.txt; got \"{1}\"\r\n{2}",line,FileLineData.linereport)
          end
          i+=1
        else
          raise _INTL("Undefined encounter type {1}, expected one of the following:\r\n{2}\r\n{3}",
             line,EncounterTypes::Names.inspect,FileLineData.linereport)
        end
      end
      save_data(encounters,"Data/encounters.dat")
    end
    
    #===============================================================================
    # Compile Shadow moves
    #===============================================================================
    def pbCompileShadowMoves
      sections=[]
      if File.exists?("PBS/shadowmoves.txt")
        pbCompilerEachCommentedLine("PBS/shadowmoves.txt"){|line,lineno|
           if line[ /^([^=]+)=(.*)$/ ]
             key=$1
             value=$2
             value=value.split(",")
             species=parseSpecies(key)
             moves=[]
             for i in 0...[4,value.length].min
               moves.push((parseMove(value[i]) rescue nil))
             end
             moves.compact!
             sections[species]=moves if moves.length>0
           end
        }
      end
      save_data(sections,"Data/shadowmoves.dat")
    end
    
    #===============================================================================
    # Compile battle animations
    #===============================================================================
    def pbCompileAnimations
      begin
        if $RPGVX
          pbanims=load_data("Data/PkmnAnimations.rvdata")
        else
          pbanims=load_data("Data/PkmnAnimations.rxdata")
        end
      rescue
        pbanims=PBAnimations.new
      end
      move2anim=[[],[]]
    =begin
      if $RPGVX
        anims=load_data("Data/Animations.rvdata")
      else
        anims=load_data("Data/Animations.rxdata")
      end
      for anim in anims
        next if !anim || anim.frames.length==1
        found=false
        for i in 0...pbanims.length
          if pbanims[i] && pbanims[i].id==anim.id
            found=true if pbanims[i].array.length>1
            break
          end
        end
        if !found
          pbanims[anim.id]=pbConvertRPGAnimation(anim)
        end
      end
    =end
      for i in 0...pbanims.length
        next if !pbanims[i]
        if pbanims[i].name[/^OppMove\:\s*(.*)$/]
          if Kernel.hasConst?(PBMoves,$~[1])
            moveid=PBMoves.const_get($~[1])
            move2anim[1][moveid]=i
          end
        elsif pbanims[i].name[/^Move\:\s*(.*)$/]
          if Kernel.hasConst?(PBMoves,$~[1])
            moveid=PBMoves.const_get($~[1])
            move2anim[0][moveid]=i
          end
        end
      end
      save_data(move2anim,"Data/move2anim.dat")
      save_data(pbanims,"Data/PkmnAnimations.rxdata")
    end
    
    #===============================================================================
    # Generate and modify events
    #===============================================================================
    def pbGenerateMoveRoute(commands)
      route=RPG::MoveRoute.new
      route.repeat=false
      route.skippable=true
      route.list.clear
      i=0; while i<commands.length
        case commands[i]
        when PBMoveRoute::Wait, PBMoveRoute::SwitchOn, PBMoveRoute::SwitchOff,
             PBMoveRoute::ChangeSpeed, PBMoveRoute::ChangeFreq, PBMoveRoute::Opacity,
             PBMoveRoute::Blending, PBMoveRoute::PlaySE, PBMoveRoute::Script
          route.list.push(RPG::MoveCommand.new(commands[i],[commands[i+1]]))
          i+=1
        when PBMoveRoute::ScriptAsync
          route.list.push(RPG::MoveCommand.new(PBMoveRoute::Script,[commands[i+1]]))
          route.list.push(RPG::MoveCommand.new(PBMoveRoute::Wait,[0]))
          i+=1
        when PBMoveRoute::Jump
          route.list.push(RPG::MoveCommand.new(commands[i],[commands[i+1],commands[i+2]]))
          i+=2
        when PBMoveRoute::Graphic
          route.list.push(RPG::MoveCommand.new(commands[i],[commands[i+1],commands[i+2],commands[i+3],commands[i+4]]))
          i+=4
        else
          route.list.push(RPG::MoveCommand.new(commands[i]))
        end
        i+=1
      end
      route.list.push(RPG::MoveCommand.new(0))
      return route
    end
    
    def pbPushMoveRoute(list,character,route,indent=0)
      if route.is_a?(Array)
        route=pbGenerateMoveRoute(route)
      end
      for i in 0...route.list.length
        list.push(RPG::EventCommand.new(
           i==0 ? 209 : 509,indent,
           i==0 ? [character,route] : [route.list[i-1]]))
      end
    end
    
    def pbPushMoveRouteAndWait(list,character,route,indent=0)
      pbPushMoveRoute(list,character,route,indent)
      pbPushEvent(list,210,[],indent)
    end
    
    def pbPushWait(list,frames,indent=0)
      pbPushEvent(list,106,[frames],indent)
    end
    
    def pbPushEvent(list,cmd,params=nil,indent=0)
      list.push(RPG::EventCommand.new(cmd,indent,params ? params : []))
    end
    
    def pbPushEnd(list)
      list.push(RPG::EventCommand.new(0,0,[]))
    end
    
    def pbPushComment(list,cmt,indent=0)
      textsplit2=cmt.split(/\n/)
      for i in 0...textsplit2.length
        list.push(RPG::EventCommand.new(i==0 ? 108 : 408,indent,[textsplit2[i].gsub(/\s+$/,"")]))
      end
    end
    
    def pbPushText(list,text,indent=0)
      return if !text
      textsplit=text.split(/\\m/)
      for t in textsplit
        first=true
        if $RPGVX
          list.push(RPG::EventCommand.new(101,indent,["",0,0,2]))
          first=false
        end
        textsplit2=t.split(/\n/)
        for i in 0...textsplit2.length
          textchunk=textsplit2[i].gsub(/\s+$/,"")
          if textchunk && textchunk!=""
            list.push(RPG::EventCommand.new(first ? 101 : 401,indent,[textchunk]))
            first=false
          end
        end
      end
    end
    
    def pbPushScript(list,script,indent=0)
      return if !script
      first=true
      textsplit2=script.split(/\n/)
      for i in 0...textsplit2.length
        textchunk=textsplit2[i].gsub(/\s+$/,"")
        if textchunk && textchunk!=""
          list.push(RPG::EventCommand.new(first ? 355 : 655,indent,[textchunk]))
          first=false
        end
      end
    end
    
    def pbPushExit(list,indent=0)
      list.push(RPG::EventCommand.new(115,indent,[]))
    end
    
    def pbPushElse(list,indent=0)
      list.push(RPG::EventCommand.new(0,indent,[]))
      list.push(RPG::EventCommand.new(411,indent-1,[]))
    end
    
    def pbPushBranchEnd(list,indent=0)
      list.push(RPG::EventCommand.new(0,indent,[]))
      list.push(RPG::EventCommand.new(412,indent-1,[]))
    end
    
    def pbPushBranch(list,script,indent=0)
      list.push(RPG::EventCommand.new(111,indent,[12,script]))
    end
    
    def pbPushSelfSwitch(list,swtch,switchOn,indent=0)
      list.push(RPG::EventCommand.new(123,indent,[swtch,switchOn ? 0 : 1]))
    end
    
    def safequote(x)
      x=x.gsub(/\"\#\'\\/){|a| "\\"+a }
      x=x.gsub(/\t/,"\\t")
      x=x.gsub(/\r/,"\\r")
      x=x.gsub(/\n/,"\\n")
      return x
    end
    
    def safequote2(x)
      x=x.gsub(/\"\#\'\\/){|a| "\\"+a }
      x=x.gsub(/\t/,"\\t")
      x=x.gsub(/\r/,"\\r")
      x=x.gsub(/\n/," ")
      return x
    end
    
    def pbEventId(event)
      list=event.pages[0].list
      return nil if list.length==0
      codes=[]
      i=0;while i<list.length
        codes.push(list[i].code)
        i+=1
      end
    end
    
    
    
    class MapData
      def initialize
        @mapinfos=pbLoadRxData("Data/MapInfos")
        @system=pbLoadRxData("Data/System")
        @tilesets=pbLoadRxData("Data/Tilesets")
        @mapxy=[]
        @mapWidths=[]
        @mapHeights=[]
        @maps=[]
        @registeredSwitches={}
      end
    
      def registerSwitch(switch)
        if @registeredSwitches[switch]
          return @registeredSwitches[switch]
        end
        for id in 1..5000
          [email protected][id]
          if !name || name=="" || name==switch
            @system.switches[id]=switch
            @registeredSwitches[switch]=id
            return id
          end
        end
        return 1
      end
    
      def saveTilesets
        filename="Data/Tilesets"
        if $RPGVX
          filename+=".rvdata"
        else
          filename+=".rxdata"
        end
        save_data(@tilesets,filename)
        filename="Data/System"
        if $RPGVX
          filename+=".rvdata"
        else
          filename+=".rxdata"
        end
        save_data(@system,filename)
      end
    
      def switchName(id)
        return @system.switches[id] || ""
      end
    
      def mapFilename(mapID)
        filename=sprintf("Data/map%03d",mapID)
        if $RPGVX
          filename+=".rvdata"
        else
          filename+=".rxdata"
        end
        return filename
      end
    
      def getMap(mapID)
        if @maps[mapID]
          return @maps[mapID]
        else
          begin
            @maps[mapID]=load_data(mapFilename(mapID))
            return @maps[mapID]
          rescue
            return nil
          end
        end
      end
    
      def isPassable?(mapID,x,y)
        if !$RPGVX
          map=getMap(mapID)
          return false if !map
          return false if x<0 || x>=map.width || y<0 || y>=map.height
          passages=@tilesets[map.tileset_id].passages
          priorities=@tilesets[map.tileset_id].priorities
          for i in [2, 1, 0]
            tile_id = map.data[x, y, i]
            return false if tile_id == nil
            return false if passages[tile_id] & 0x0f == 0x0f
            return true if priorities[tile_id] == 0
          end
        end
        return true
      end
    
      def setCounterTile(mapID,x,y)
        if !$RPGVX
          map=getMap(mapID)
          return if !map
          passages=@tilesets[map.tileset_id].passages
          for i in [2, 1, 0]
            tile_id = map.data[x, y, i]
            next if tile_id == 0 || tile_id==nil || !passages[tile_id]
            passages[tile_id]|=0x80
            break
          end
        end
      end
    
      def isCounterTile?(mapID,x,y)
        return false if $RPGVX
        map=getMap(mapID)
        return false if !map
        passages=@tilesets[map.tileset_id].passages
        for i in [2, 1, 0]
          tile_id = map.data[x, y, i]
          return false if tile_id == nil
          return true if passages[tile_id] && passages[tile_id] & 0x80 == 0x80
        end
        return false
      end
    
      def saveMap(mapID)
        save_data(getMap(mapID),mapFilename(mapID)) rescue nil
      end
    
      def getEventFromXY(mapID,x,y)
        return nil if x<0 || y<0
        mapPositions=@mapxy[mapID]
        if mapPositions
          return mapPositions[y*@mapWidths[mapID]+x]
        else
          map=getMap(mapID)
          return nil if !map
          @mapWidths[mapID]=map.width
          @mapHeights[mapID]=map.height
          mapPositions=[]
          width=map.width
          for e in map.events.values
            mapPositions[e.y*width+e.x]=e if e
          end
          @mapxy[mapID]=mapPositions
          return mapPositions[y*width+x]
        end
      end
    
      def getEventFromID(mapID,id)
        map=getMap(mapID)
        return nil if !map
        return map.events[id]
      end
    
      def mapinfos
        return @mapinfos
      end
    end
    
    
    
    class TrainerChecker
      def initialize
        @trainers=nil
        @trainertypes=nil
        @dontaskagain=false
      end
    
      def pbTrainerTypeCheck(symbol)
        ret=true
        if $DEBUG  
          return if @dontaskagain
          if !hasConst?(PBTrainers,symbol)
            ret=false
          else
            trtype=PBTrainers.const_get(symbol)
            @trainertypes=load_data("Data/trainertypes.dat") if !@trainertypes
            if !@trainertypes || !@trainertypes[trtype]     
              ret=false   
            end
          end  
          if !ret
            if Kernel.pbConfirmMessage(_INTL("Add new trainer named {1}?",symbol))
              pbTrainerTypeEditorNew(symbol.to_s)
              @trainers=nil
              @trainertypes=nil
            end
    #        if pbMapInterpreter
    #          pbMapInterpreter.command_end rescue nil
    #        end
          end
        end 
        return ret
      end
    
      def pbTrainerBattleCheck(trtype,trname,trid)
        if $DEBUG
          return if @dontaskagain
          if trtype.is_a?(String) || trtype.is_a?(Symbol)
            pbTrainerTypeCheck(trtype)
            return if !hasConst?(PBTrainers,trtype)
            trtype=PBTrainers.const_get(trtype)
          end
          @trainers=load_data("Data/trainers.dat") if !@trainers
          if @trainers
            for trainer in @trainers
              name=trainer[1]
              thistrainerid=trainer[0]
              thispartyid=trainer[4]
              next if name!=trname || thistrainerid!=trtype || thispartyid!=trid
              return
            end
          end
          cmd=pbMissingTrainer(trtype,trname,trid)
          if cmd==2
            @dontaskagain=true
            Graphics.update
          end
          @trainers=nil
          @trainertypes=nil
        end
      end
    end
    
    
    
    def pbCompileTrainerEvents(mustcompile)
      mapdata=MapData.new
      t = Time.now.to_i
      Graphics.update
      trainerChecker=TrainerChecker.new
      for id in mapdata.mapinfos.keys.sort
        changed=false
        map=mapdata.getMap(id)
        next if !map || !mapdata.mapinfos[id]
        Win32API.SetWindowText(_INTL("Processing map {1} ({2})",id,mapdata.mapinfos[id].name))
        for key in map.events.keys
          if Time.now.to_i - t >= 5
            Graphics.update
            t = Time.now.to_i
          end
          newevent=pbConvertToTrainerEvent(map.events[key],trainerChecker)
          if newevent
            changed=true
            map.events[key]=newevent
          end
          newevent=pbConvertToItemEvent(map.events[key])
          if newevent
            changed=true
            map.events[key]=newevent
          end
          newevent=pbFixEventUse(map.events[key],id,mapdata)
          if newevent
            changed=true
            map.events[key]=newevent
          end
        end
        if Time.now.to_i - t >= 5
          Graphics.update
          t = Time.now.to_i
        end
        changed=true if pbCheckCounters(map,id,mapdata)
        if changed
          mapdata.saveMap(id)
          mapdata.saveTilesets
        end
      end
      changed=false
      if Time.now.to_i-t>=5
        Graphics.update
        t=Time.now.to_i
      end
      commonEvents=pbLoadRxData("Data/CommonEvents")
      Win32API.SetWindowText(_INTL("Processing common events"))
      for key in 0...commonEvents.length
        newevent=pbFixEventUse(commonEvents[key],0,mapdata)
        if newevent
          changed=true
          map.events[key]=newevent
        end
      end
      if changed
        if $RPGVX
          save_data(commonEvents,"Data/CommonEvents.rvdata")
        else
          save_data(commonEvents,"Data/CommonEvents.rxdata")
        end
      end
    #  if !$RPGVX && $INTERNAL
    #    convertVXProject(mapdata)
    #  end
    end
    
    def isPlainEvent?(event)
      return event && event.pages.length<=1 && 
             event.pages[0].list.length<=1 &&
             event.pages[0].move_type==0 &&
             event.pages[0].condition.switch1_valid==false &&
             event.pages[0].condition.switch2_valid==false &&
             event.pages[0].condition.variable_valid==false &&
             event.pages[0].condition.self_switch_valid==false
    end
    
    def isPlainEventOrMart?(event)
      return event &&
             event.pages.length<=1 && 
             event.pages[0].move_type==0 &&
             event.pages[0].condition.switch1_valid==false &&
             event.pages[0].condition.switch2_valid==false &&
             event.pages[0].condition.variable_valid==false &&
             event.pages[0].condition.self_switch_valid==false &&
             ((event.pages[0].list.length<=1) || (
             event.pages[0].list.length<=12 &&
             event.pages[0].graphic.character_name!="" &&
             event.pages[0].list[0].code==355 &&
             event.pages[0].list[0].parameters[0][/^pbPokemonMart/]) || (
             event.pages[0].list.length>8 &&
             event.pages[0].graphic.character_name!="" &&
             event.pages[0].list[0].code==355 &&
             event.pages[0].list[0].parameters[0][/^Kernel\.pbSetPokemonCenter/])
             )
    end
    
    def applyPages(page,pages)
      for p in pages
        p.graphic=page.graphic
        p.walk_anime=page.walk_anime
        p.step_anime=page.step_anime
        p.direction_fix=page.direction_fix
        p.through=page.through
        p.always_on_top=page.always_on_top
      end
    end
    
    def isLikelyCounter?(thisEvent,otherEvent,mapID,mapdata)
      # Check whether other event is likely on a counter tile
      yonderX=otherEvent.x+(otherEvent.x-thisEvent.x)
      yonderY=otherEvent.y+(otherEvent.y-thisEvent.y)
      return true if mapdata.isCounterTile?(mapID,otherEvent.x,otherEvent.y)
      return thisEvent.pages[0].graphic.character_name!="" &&
             otherEvent.pages[0].graphic.character_name=="" &&
             otherEvent.pages[0].trigger==0 &&
             mapdata.isPassable?(mapID,thisEvent.x,thisEvent.y) &&
             !mapdata.isPassable?(mapID,otherEvent.x,otherEvent.y) &&
             mapdata.isPassable?(mapID,yonderX,yonderY)
    end
    
    def isLikelyPassage?(thisEvent,mapID,mapdata)
      return false if !thisEvent || thisEvent.pages.length==0
      return false if thisEvent.pages.length!=1
      if thisEvent.pages[0].graphic.character_name=="" &&
         thisEvent.pages[0].list.length<=12 &&
         thisEvent.pages[0].list.any? {|cmd| cmd.code==201 } &&
    #     mapdata.isPassable?(mapID,thisEvent.x,thisEvent.y+1) &&
         mapdata.isPassable?(mapID,thisEvent.x,thisEvent.y) &&
         !mapdata.isPassable?(mapID,thisEvent.x-1,thisEvent.y) &&
         !mapdata.isPassable?(mapID,thisEvent.x+1,thisEvent.y) &&
         !mapdata.isPassable?(mapID,thisEvent.x-1,thisEvent.y-1) &&
         !mapdata.isPassable?(mapID,thisEvent.x+1,thisEvent.y-1)
        return true
      end
      return false
    end
    
    def pbCheckCounters(map,mapID,mapdata)
      todelete=[]
      changed=false
      for key in map.events.keys
        event=map.events[key]
        next if !event
        firstCommand=event.pages[0].list[0]
        if isPlainEventOrMart?(event)
          # Empty event, check for counter events
          neighbors=[]
          neighbors.push(mapdata.getEventFromXY(mapID,event.x,event.y-1))
          neighbors.push(mapdata.getEventFromXY(mapID,event.x,event.y+1))
          neighbors.push(mapdata.getEventFromXY(mapID,event.x-1,event.y))
          neighbors.push(mapdata.getEventFromXY(mapID,event.x+1,event.y))
          neighbors.compact!
          for otherEvent in neighbors
            next if isPlainEvent?(otherEvent)
            if isLikelyCounter?(event,otherEvent,mapID,mapdata)
              mapdata.setCounterTile(mapID,otherEvent.x,otherEvent.y)
              savedPage=event.pages[0]
              event.pages=otherEvent.pages
              applyPages(savedPage,event.pages)
              todelete.push(otherEvent.id)
              changed=true
            end
          end
        end
      end
      for key in todelete
        map.events.delete(key)
      end
      return changed
    end
    
    def pbAddPassageList(event,mapdata)
      return if !event || event.pages.length==0
      page=RPG::Event::Page.new
      page.condition.switch1_valid=true
      page.condition.switch1_id=mapdata.registerSwitch('s:tsOff?("A")')
      page.graphic.character_name=""
      page.trigger=3 # Autorun
      page.list.clear
      list=page.list
      pbPushBranch(list,"get_character(0).onEvent?")
      pbPushEvent(list,208,[0],1)
      pbPushWait(list,6,1)
      pbPushEvent(list,208,[1],1)
      pbPushMoveRouteAndWait(list,-1,[PBMoveRoute::Down],1)
      pbPushBranchEnd(list,1)
      pbPushScript(list,"setTempSwitchOn(\"A\")")
      pbPushEnd(list)
      event.pages.push(page)
    end
    
    def pbUpdateDoor(event,mapdata)
      changed=false
      return false if event.is_a?(RPG::CommonEvent)
      if event.pages.length>=2 && 
         event.pages[event.pages.length-1].condition.switch1_valid &&
         event.pages[event.pages.length-1].condition.switch1_id==22 &&
         event.pages[event.pages.length-1].list.length>5 &&
         event.pages[event.pages.length-1].graphic.character_name!="" &&
         mapdata.switchName(event.pages[event.pages.length-1].condition.switch1_id)!='s:tsOff?("A")' &&
         event.pages[event.pages.length-1].list[0].code==111
        event.pages[event.pages.length-1].condition.switch1_id=mapdata.registerSwitch('s:tsOff?("A")')
        changed=true
      end
      if event.pages.length>=2 && 
         event.pages[event.pages.length-1].condition.switch1_valid &&
         event.pages[event.pages.length-1].list.length>5 &&
         event.pages[event.pages.length-1].graphic.character_name!="" &&
         mapdata.switchName(event.pages[event.pages.length-1].condition.switch1_id)=='s:tsOff?("A")' &&
         event.pages[event.pages.length-1].list[0].code==111
        list=event.pages[event.pages.length-2].list
        transferCommand=list.find_all {|cmd| cmd.code==201 }
        if transferCommand.length==1 && !list.any?{|cmd| cmd.code==208 }
          list.clear
          pbPushMoveRouteAndWait(list,0,[
             PBMoveRoute::PlaySE,RPG::AudioFile.new("Entering Door"),PBMoveRoute::Wait,2,
             PBMoveRoute::TurnLeft,PBMoveRoute::Wait,2,
             PBMoveRoute::TurnRight,PBMoveRoute::Wait,2,
             PBMoveRoute::TurnUp,PBMoveRoute::Wait,2])
          pbPushMoveRouteAndWait(list,-1,[
             PBMoveRoute::ThroughOn,PBMoveRoute::Up,PBMoveRoute::ThroughOff])
          pbPushEvent(list,208,[0]) # Change Transparent Flag
          pbPushMoveRouteAndWait(list,0,[PBMoveRoute::Wait,2,
             PBMoveRoute::TurnRight,PBMoveRoute::Wait,2,
             PBMoveRoute::TurnLeft,PBMoveRoute::Wait,2,
             PBMoveRoute::TurnDown,PBMoveRoute::Wait,2])
          pbPushEvent(list,223,[Tone.new(-255,-255,-255),6])
          pbPushWait(list,8)
          pbPushEvent(list,208,[1])
          pbPushEvent(list,transferCommand[0].code,transferCommand[0].parameters)
          pbPushEvent(list,223,[Tone.new(0,0,0),6])
          pbPushEnd(list)
          list=event.pages[event.pages.length-1].list
          list.clear
          pbPushBranch(list,"get_character(0).onEvent?")
          pbPushEvent(list,208,[0],1)
          pbPushMoveRouteAndWait(list,0,[
             PBMoveRoute::TurnLeft,PBMoveRoute::Wait,6],1)
          pbPushEvent(list,208,[1],1)
          pbPushMoveRouteAndWait(list,-1,[PBMoveRoute::Down],1)
          pbPushMoveRouteAndWait(list,0,[
             PBMoveRoute::TurnUp,PBMoveRoute::Wait,2,
             PBMoveRoute::TurnRight,PBMoveRoute::Wait,2,
             PBMoveRoute::TurnDown,PBMoveRoute::Wait,2],1)
          pbPushBranchEnd(list,1)
          pbPushScript(list,"setTempSwitchOn(\"A\")")
          pbPushEnd(list)
          changed=true
        end
      end
      return changed
    end
    
    def pbEventIsEmpty?(e)
      return true if !e
      return false if e.is_a?(RPG::CommonEvent)
      return e.pages.length==0
    end
    
    def pbStartsWith(s,pfx)
      return s[0,pfx.length]==pfx
    end
    
    def pbEachPage(e)
      return true if !e
      if e.is_a?(RPG::CommonEvent)
        yield e
      else
        e.pages.each {|page| yield page }
      end 
    end
    
    def pbChangeScript(script,re)
      tmp=script[0].gsub(re){ yield($~) }
      if script[0]!=tmp
        script[0]=tmp; return true
      end
      return false
    end
    
    def pbChangeScripts(script)
      changed=false
      changed|=pbChangeScript(script,/\$game_variables\[(\d+)\](?!\s*(?:\=|\!|<|>))/){|m| "pbGet("+m[1]+")" }
      changed|=pbChangeScript(script,/\$Trainer\.party\[\s*pbGet\((\d+)\)\s*\]/){|m| "pbGetPokemon("+m[1]+")" }
      return changed
    end
    
    def pbFixEventUse(event,mapID,mapdata)
      return nil if pbEventIsEmpty?(event)
      changed=false
      trainerMoneyRE=/^\s*\$Trainer\.money\s*(<|<=|>|>=)\s*(\d+)\s*$/
      itemBallRE=/^\s*(Kernel\.)?pbItemBall/
      if pbUpdateDoor(event,mapdata)
        changed=true
      end
      pbEachPage(event) do |page|
        i=0
        list=page.list
        while i<list.length
          params=list[i].parameters
          if list[i].code==655
            x=[params[0]]
            changed|=pbChangeScripts(x)
            params[0]=x[0]
          elsif list[i].code==355
            lastScript=i
            if !params[0].is_a?(String)
              i+=1
              next
            end
            x=[params[0]]
            changed|=pbChangeScripts(x)
            params[0]=x[0]
            if params[0][0,1]!="f" && params[0][0,1]!="p" && params[0][0,1]!="K"
              i+=1
              next
            end
            script=" "+params[0]
            j=i+1
            while j<list.length
              break if list[j].code!=655
              script+=list[j].parameters[0]
              lastScript=j
              j+=1
            end
            script.gsub!(/\s+/,"")
            # Using old method of recovering
            if script=="foriin$Trainer.partyi.healend"
              for j in i..lastScript
                list.delete_at(i)
              end
              list.insert(i,
                 RPG::EventCommand.new(314,list[i].indent,[0]) # Recover All
              )
              changed=true
            elsif script=="pbFadeOutIn(99999){foriin$Trainer.partyi.healend}"
              oldIndent=list[i].indent
              for j in i..lastScript
                list.delete_at(i)
              end
              list.insert(i,
                 RPG::EventCommand.new(223,oldIndent,[Tone.new(-255,-255,-255),6]), # Fade to black
                 RPG::EventCommand.new(106,oldIndent,[6]), # Wait
                 RPG::EventCommand.new(314,oldIndent,[0]), # Recover All
                 RPG::EventCommand.new(223,oldIndent,[Tone.new(0,0,0),6]), # Fade to normal
                 RPG::EventCommand.new(106,oldIndent,[6]) # Wait
              )
              changed=true
            end
          elsif list[i].code==108
            if params[0][/SellItem\s*\(\s*(\w+)\s*\,\s*(\d+)\s*\)/]
              itemname=$1
              cost=$2.to_i
              if hasConst?(PBItems,itemname)
                oldIndent=list[i].indent
                list.delete_at(i)
                newEvents=[]
                if cost==0
                  pbPushBranch(newEvents,"$PokemonBag.pbCanStore?(PBItems:"+":#{itemname})",oldIndent)
                  pbPushText(newEvents,_INTL("Here you go!"),oldIndent+1)
                  pbPushScript(newEvents,"Kernel.pbReceiveItem(PBItems:"+":#{itemname})",oldIndent+1)
                  pbPushElse(newEvents,oldIndent+1)
                  pbPushText(newEvents,_INTL("You have no room left in the Bag."),oldIndent+1)
                  pbPushBranchEnd(newEvents,oldIndent+1)
                else
                  pbPushEvent(newEvents,111,[7,cost,0],oldIndent)
                  pbPushBranch(newEvents,"$PokemonBag.pbCanStore?(PBItems:"+":#{itemname})",oldIndent+1)
                  pbPushEvent(newEvents,125,[1,0,cost],oldIndent+2)
                  pbPushText(newEvents,_INTL("\\GHere you go!"),oldIndent+2)
                  pbPushScript(newEvents,"Kernel.pbReceiveItem(PBItems:"+":#{itemname})",oldIndent+2)
                  pbPushElse(newEvents,oldIndent+2)
                  pbPushText(newEvents,_INTL("\\GYou have no room left in the Bag."),oldIndent+2)
                  pbPushBranchEnd(newEvents,oldIndent+2)
                  pbPushElse(newEvents,oldIndent+1)
                  pbPushText(newEvents,_INTL("\\GYou don't have enough money."),oldIndent+1)
                  pbPushBranchEnd(newEvents,oldIndent+1)
                end
                list[i,0]=newEvents # insert 'newEvents' at index 'i'
                changed=true
              end
            end
          elsif list[i].code==115 && i==list.length-2
            # Superfluous exit command
            list.delete_at(i)
            changed=true
          elsif list[i].code==201 && list.length<=8
            if params[0]==0
              # Transfer back to door
              e=mapdata.getEventFromXY(params[1],params[2],params[3]-1)
              if e && e.pages.length>=2 && 
                 e.pages[e.pages.length-1].condition.switch1_valid &&
                 e.pages[e.pages.length-1].condition.switch1_id==22 &&
                 mapdata.switchName(e.pages[e.pages.length-1].condition.switch1_id)!='s:tsOff?("A")' &&
                 e.pages[e.pages.length-1].list.length>5 &&
                 e.pages[e.pages.length-1].list[0].code==111
                e.pages[e.pages.length-1].condition.switch1_id=mapdata.registerSwitch('s:tsOff?("A")')
                mapdata.saveMap(params[1])
                changed=true
              end
              if isLikelyPassage?(e,params[1],mapdata)
                pbAddPassageList(e,mapdata)
                mapdata.saveMap(params[1])
                changed=true
              end
              if e && e.pages.length>=2 && 
                 e.pages[e.pages.length-1].condition.switch1_valid &&
                mapdata.switchName(e.pages[e.pages.length-1].condition.switch1_id)=='s:tsOff?("A")'
                # If this is really a door, move transfer target to it
                params[3]-=1
                params[5]=1 # No fade
                changed=true
              end
              deletedRoute=nil
              deleteMoveRouteAt=proc{|list,_i|
                 arr=[]
                 if list[_i] && list[_i].code==209
                   arr.push(list[_i]);list.delete_at(_i)
                   while _i<list.length
                     break if !list[_i] || list[_i].code!=509
                     arr.push(list[_i]);list.delete_at(_i)     
                   end
                 end
                 next arr
              }
              insertMoveRouteAt=proc{|list,_i,route|
                 _j=route.length-1
                 while _j>=0
                   list.insert(_i,route[_j])
                   _j-=1
                 end
              }
              if params[4]==0 && # Retain direction
                 i+1<list.length && list[i+1].code==209 && list[i+1].parameters[0]==-1
                route=list[i+1].parameters[1]
                if route && route.list.length<=2
                  # Delete superfluous move route command if necessary
                  if route.list[0].code==16 # Player/Turn Down
                    deleteMoveRouteAt.call(list,i+1); params[4]=2; changed=true
                  elsif route.list[0].code==17 # Left
                    deleteMoveRouteAt.call(list,i+1); params[4]=4; changed=true
                  elsif route.list[0].code==18 # Right
                    deleteMoveRouteAt.call(list,i+1); params[4]=6; changed=true
                  elsif route.list[0].code==19 # Up
                    deleteMoveRouteAt.call(list,i+1); params[4]=8; changed=true
                  elsif (route.list[0].code==1 || route.list[0].code==2 ||
                     route.list[0].code==3 || route.list[0].code==4) && list.length==4
                    params[4]=[0,2,4,6,8][route.list[0].code]
                    deletedRoute=deleteMoveRouteAt.call(list,i+1); changed=true
                  end
                end
              elsif params[4]==0 && i>3
                for j in 0...i
                  if list[j].code==209 && list[j].parameters[0]==-1
                    route=list[j].parameters[1]
                    oldlistlength=list.length
                    if route && route.list.length<=2
                      # Delete superfluous move route command if necessary
                      if route.list[0].code==16 # Player/Turn Down
                        deleteMoveRouteAt.call(list,j); params[4]=2; changed=true;i-=(oldlistlength-list.length)
                      elsif route.list[0].code==17 # Left
                        deleteMoveRouteAt.call(list,j); params[4]=4; changed=true;i-=(oldlistlength-list.length)
                      elsif route.list[0].code==18 # Right
                        deleteMoveRouteAt.call(list,j); params[4]=6; changed=true;i-=(oldlistlength-list.length)
                      elsif route.list[0].code==19 # Up
                        deleteMoveRouteAt.call(list,j); params[4]=8; changed=true;i-=(oldlistlength-list.length)
                      end
                    end
                  end
                end
              elsif params[4]==0 && # Retain direction
                 i+2<list.length && 
                 list[i+1].code==223 &&
                 list[i+2].code==209 && 
                 list[i+2].parameters[0]==-1
                route=list[i+2].parameters[1]
                if route && route.list.length<=2
                  # Delete superfluous move route command if necessary
                  if route.list[0].code==16 # Player/Turn Down
                    deleteMoveRouteAt.call(list,i+2); params[4]=2; changed=true
                  elsif route.list[0].code==17 # Left
                    deleteMoveRouteAt.call(list,i+2); params[4]=4; changed=true
                  elsif route.list[0].code==18 # Right
                    deleteMoveRouteAt.call(list,i+2); params[4]=6; changed=true
                  elsif route.list[0].code==19 # Up
                    deleteMoveRouteAt.call(list,i+2); params[4]=8; changed=true
                  end
                end
              end
            end
            # If this is the only event command, convert to a full event
            if list.length==2 || (list.length==3 && (list[0].code==250 || list[1].code==250))
              params[5]=1 # No fade
              fullTransfer=list[i]
              indent=list[i].indent
              (list.length-1).times { list.delete_at(0) }
              list.insert(0,
                 RPG::EventCommand.new(250,indent,[RPG::AudioFile.new("Exit Door",80,100)]), # Play SE
                 RPG::EventCommand.new(223,indent,[Tone.new(-255,-255,-255),6]), # Fade to black
                 RPG::EventCommand.new(106,indent,[8]), # Wait
                 fullTransfer, # Transfer event
                 RPG::EventCommand.new(223,indent,[Tone.new(0,0,0),6]) # Fade to normal
              )
              changed=true
            end
            if deletedRoute
              insertMoveRouteAt.call(list,list.length-1,deletedRoute)
              changed=true
            end
          elsif list[i].code==101 
            if list[i].parameters[0][0,1]=="\\"
              newx=list[i].parameters[0].clone
              newx.sub!(/^\\[Bb]\s+/,"\\b")
              newx.sub!(/^\\[Rr]\s+/,"\\r")
              newx.sub!(/^\\[Pp][Gg]\s+/,"\\pg")
              newx.sub!(/^\\[Pp][Oo][Gg]\s+/,"\\pog")
              newx.sub!(/^\\[Gg]\s+/,"\\G")
              newx.sub!(/^\\[Cc][Nn]\s+/,"\\CN")
              if list[i].parameters[0]!=newx
                list[i].parameters[0]=newx
                changed=true
              end
            end
            lines=1
            j=i+1; while j<list.length
              break if list[j].code!=401
              if lines%4==0
                list[j].code=101
                changed=true
              end
              lines+=1
              j+=1
            end
            if lines>=2 && list[i].parameters[0].length>0 && list[i].parameters[0].length<=20 &&
               !list[i].parameters[0][/\\n/]
              # Very short line
              list[i].parameters[0]+="\\n"+list[i+1].parameters[0]
              list.delete_at(i+1)
              i-=1 # revisit this text command
              changed=true
            elsif lines>=3 && list[i+lines] && list[i+lines].code==101
              # Check whether a sentence is being broken midway 
              # between two Text commands
              lastLine=list[i+lines-1].parameters[0].sub(/\s+$/,"")
              if lastLine.length>0 && !lastLine[/[\\<]/] && lastLine[/[^\.,\!\?\;\-\"]$/]
                message=list[i].parameters[0]
                j=i+1; while j<list.length
                  break if list[j].code!=401
                  message+="\n"+list[j].parameters[0]
                  j+=1
                end
                punct=[message.rindex(". "),message.rindex(".\n"),
                   message.rindex("!"),message.rindex("?"),-1].compact.max
                if punct==-1
                  punct=[message.rindex(", "),message.rindex(",\n"),-1].compact.max
                end
                if punct!=-1
                  # Delete old message
                  indent=list[i].indent
                  newMessage=message[0,punct+1].split("\n")
                  nextMessage=message[punct+1,message.length].sub(/^\s+/,"").split("\n")
                  list[i+lines].code=401
                  lines.times { list.delete_at(i) }
                  j=nextMessage.length-1;while j>=0
                    list.insert(i,RPG::EventCommand.new(
                    j==0 ? 101 : 401,indent,[nextMessage[j]]))
                    j-=1
                  end
                  j=newMessage.length-1;while j>=0
                    list.insert(i,RPG::EventCommand.new(
                    j==0 ? 101 : 401,indent,[newMessage[j]]))
                    j-=1
                  end
                  changed=true
                  i+=1
                  next
                end
              end
            end
          elsif list[i].code==111 && list[i].parameters[0]==12
            x=
    [list[i].parameters[1]]
            changed|=pbChangeScripts(x)
            list[i].parameters[1]=x[0]
            script=x[0]
            if script[trainerMoneyRE]
              # Checking money directly
              operator=$1
              amount=$2.to_i
              params[0]=7
              if operator=="<"
                params[2]=1
                params[1]=amount-1
              elsif operator=="<="
                params[2]=1
                params[1]=amount
              elsif operator==">"
                params[2]=0
                params[1]=amount+1
              elsif operator==">="
                params[2]=0
                params[1]=amount
              end
              changed=true
            elsif script[itemBallRE] && i>0
              # Using pbItemBall on non-item events
              list[i].parameters[1]=script.sub(/pbItemBall/,"pbReceiveItem")
              changed=true
            elsif script[/^\s*(Kernel\.)?(pbTrainerBattle|pbDoubleTrainerBattle)/]
              # Empty trainer battle conditional branches
              j=i+1
              isempty=true
              elseIndex=-1
              # Check if page is empty
              while j<page.list.length
                if list[j].indent<=list[i].indent
                  if list[j].code==411 # Else
                    elseIndex=j
                  else
                    break
                  end
                end
                if list[j].code!=0 && list[j].code!=411
                  isempty=false
                  break
                end 
                j+=1
              end
              if isempty
                if elseIndex>=0
                  list.insert(elseIndex+1,
                     RPG::EventCommand.new(115,list[i].indent+1,[]) # Exit Event Processing
                  )
                else
                  list.insert(i+1,
                     RPG::EventCommand.new(0,list[i].indent+1,[]), # Empty Event
                     RPG::EventCommand.new(411,list[i].indent,[]), # Else
                     RPG::EventCommand.new(115,list[i].indent+1,[]) # Exit Event Processing
                  )
                end
                changed=true
              end
            end
          end
          i+=1
        end
      end
      return changed ? event : nil
    end
    
    def pbConvertToItemEvent(event)
      return nil if !event || event.pages.length==0
      ret=RPG::Event.new(event.x,event.y)
      name=event.name
      ret.name=event.name
      ret.id=event.id
      ret.pages=[]
      itemid=nil
      itemname=""
      hidden=false
      if name[/^HiddenItem\:\s*(\w+)\s*$/]
        itemname=$1
        return nil if !hasConst?(PBItems,itemname)
        itemid=PBItems.const_get(itemname)
        ret.name="HiddenItem"
        hidden=true
      elsif name[/^Item\:\s*(\w+)\s*$/]
        itemname=$1
        return nil if !hasConst?(PBItems,itemname)
        itemid=PBItems.const_get(itemname)
        ret.name="Item"
      else
        return nil
      end
      # Event page 1
      page=RPG::Event::Page.new
      if !hidden
        page.graphic.character_name="Object ball"
      end
      page.list=[]
      pbPushBranch(page.list,
         sprintf("Kernel.pbItemBall(:%s)",itemname))
      pbPushSelfSwitch(page.list,"A",true,1)
      pbPushElse(page.list,1)
      pbPushBranchEnd(page.list,1)
      pbPushEnd(page.list)
      ret.pages.push(page)
      # Event page 2
      page=RPG::Event::Page.new
      page.condition.self_switch_valid=true
      page.condition.self_switch_ch="A"
      ret.pages.push(page)
      return ret
    end
    
    def pbConvertToTrainerEvent(event,trainerChecker)
      return nil if !event || event.pages.length==0
      ret=RPG::Event.new(event.x,event.y)
      ret.name=event.name
      ret.id=event.id
      commands=[]
      list=event.pages[0].list
      return nil if list.length<2
      isFirstCommand=false
      i=0; while i<list.length
        if list[i].code==108
          command=list[i].parameters[0]
          j=i+1; while j<list.length
            break if list[j].code!=408
            command+="\r\n"+list[j].parameters[0]
            j+=1
          end
          if command[/^(Battle\:|Type\:|Name\:|EndSpeech\:|VanishIfSwitch\:|EndBattle\:|RegSpeech\:|BattleID\:|EndIfSwitch\:|DoubleBattle\:|Backdrop\:|Continue\:|Outcome\:)/i]
            commands.push(command)
            isFirstCommand=true if i==0
          end
        end
        i+=1
      end
      return nil if commands.length==0
      if isFirstCommand && !event.name[/Trainer/]
        ret.name="Trainer(3)"
      elsif isFirstCommand && event.name[/^\s*Trainer\s+\((\d+)\)\s*$/]
        ret.name="Trainer(#{$1})"
      end
      firstpage=Marshal::load(Marshal.dump(event.pages[0]))
      firstpage.trigger=2
      firstpage.list=[]
      trtype=nil
      trname=nil
      battles=[]
      endbattles=[]
      realcommands=[]
      endspeeches=[]
      regspeech=nil
      backdrop=nil
      battleid=0
      endifswitch=[]
      vanishifswitch=[]
      doublebattle=false
      continue=false
      outcome=0
      for command in commands
        if command[/^Battle\:\s*([\s\S]+)$/i]
          battles.push($~[1])
          pbPushComment(firstpage.list,command)
        end
        if command[/^Type\:\s*([\s\S]+)$/i]
          trtype=$~[1].gsub(/^\s+/,"").gsub(/\s+$/,"")
          pbPushComment(firstpage.list,command)
        end
        if command[/^Name\:\s*([\s\S]+)$/i]
          trname=$~[1].gsub(/^\s+/,"").gsub(/\s+$/,"")
          pbPushComment(firstpage.list,command)
        end
        if command[/^EndSpeech\:\s*([\s\S]+)$/i]
          endspeeches.push($~[1].gsub(/^\s+/,"").gsub(/\s+$/,""))
          pbPushComment(firstpage.list,command)
        end
        if command[/^EndIfSwitch\:\s*([\s\S]+)$/i]
          endifswitch.push(($~[1].gsub(/^\s+/,"").gsub(/\s+$/,"")).to_i)
          pbPushComment(firstpage.list,command)
        end
        if command[/^DoubleBattle\:\s*([\s\S]+)$/i]
          value=$~[1].gsub(/^\s+/,"").gsub(/\s+$/,"")
          doublebattle=true if value.upcase=="TRUE" || value.upcase=="YES"
          pbPushComment(firstpage.list,command)
        end
        if command[/^VanishIfSwitch\:\s*([\s\S]+)$/i]
          vanishifswitch.push(($~[1].gsub(/^\s+/,"").gsub(/\s+$/,"")).to_i)
          pbPushComment(firstpage.list,command)
        end
        if command[/^Backdrop\:\s*([\s\S]+)$/i]
          backdrop=$~[1].gsub(/^\s+/,"").gsub(/\s+$/,"")
          pbPushComment(firstpage.list,command)
        end
        if command[/^RegSpeech\:\s*([\s\S]+)$/i]
          regspeech=$~[1].gsub(/^\s+/,"").gsub(/\s+$/,"")
          pbPushComment(firstpage.list,command)
        end
        if command[/^EndBattle\:\s*([\s\S]+)$/i]
          endbattles.push($~[1].gsub(/^\s+/,"").gsub(/\s+$/,""))
          pbPushComment(firstpage.list,command)
        end
        if command[/^BattleID\:\s*(\d+)$/i]
          battleid=$~[1].to_i
          pbPushComment(firstpage.list,command)
        end
        if command[/^Continue\:\s*([\s\S]+)$/i]
          value=$~[1].gsub(/^\s+/,"").gsub(/\s+$/,"")
          continue=true if value.upcase=="TRUE" || value.upcase=="YES"
          pbPushComment(firstpage.list,command)
        end
        if command[/^Outcome\:\s*(\d+)$/i]
          outcome=$~[1].to_i
          pbPushComment(firstpage.list,command)
        end
      end
      if battles.length<=0
        return nil
      end
      if firstpage.graphic.character_name=="" && hasConst?(PBTrainers,trtype)
        trainerid=getConst(PBTrainers,trtype)
        if trainerid
          filename=pbTrainerCharNameFile(trainerid)
          if FileTest.image_exist?("Graphics/Characters/"+filename)
            firstpage.graphic.character_name=sprintf(filename)
          end
        end
      end
      safetrcombo=sprintf("PBTrainers:"+":%s,\"%s\"",trtype,safequote(trname))
      safetrcombo2=sprintf(":%s,\"%s\"",trtype,safequote(trname))
      introplay=sprintf("pbTrainerIntro(:%s)",trtype)
      pbPushScript(firstpage.list,introplay)
      pbPushScript(firstpage.list,"Kernel.pbNoticePlayer(get_character(0))")
      pbPushText(firstpage.list,battles[0])
      if battles.length>1
        pbPushScript(firstpage.list,sprintf("Kernel.pbTrainerCheck(%s,%d,%d)",safetrcombo2,battles.length,battleid))
      end
      if backdrop
        pbPushScript(firstpage.list,sprintf("$PokemonGlobal.nextBattleBack=\"%s\"",safequote(backdrop)))
      end
      espeech=(endspeeches[0]) ? endspeeches[0] : "..."
      # Run trainer check now, except in editor
      trainerChecker.pbTrainerBattleCheck(trtype,trname,battleid) if !$INEDITOR
      pbPushBranch(firstpage.list,
         sprintf("pbTrainerBattle(%s,_I(\"%s\"),%s,%d,%s,%d)",
         safetrcombo,safequote2(espeech),
         doublebattle ? "true" : "false",
         battleid,
         continue ? "true" : "false",
         outcome)
      )
      if battles.length>1
        pbPushScript(firstpage.list,sprintf("pbPhoneRegisterBattle(_I(\"%s\"),get_character(0),%s,%d)",regspeech,safetrcombo,battles.length),1)
      end
      pbPushSelfSwitch(firstpage.list,"A",true,1)
      pbPushBranchEnd(firstpage.list,1)
      pbPushScript(firstpage.list,"pbTrainerEnd",0)
      pbPushEnd(firstpage.list)
      secondpage=Marshal::load(Marshal.dump(firstpage))
      secondpage.list=[]
      secondpage.trigger=0
      secondpage.condition=firstpage.condition.clone
      thirdpage=Marshal::load(Marshal.dump(secondpage))
      thirdpage.list=secondpage.list.clone
      thirdpage.condition=secondpage.condition.clone
      secondpage.condition.self_switch_valid=true
      secondpage.condition.self_switch_ch="A"
      thirdpage.condition.self_switch_valid=true
      thirdpage.condition.self_switch_ch="B"
      for i in 1...battles.length
        if endspeeches.length==0
          espeech="..."
        else
          espeech=(endspeeches[i]) ? endspeeches[i] : endspeeches[endspeeches.length-1]
        end
        if endbattles.length==0
          ebattle=nil
        else
          ebattle=(endbattles[i]) ? endbattles[i] : endbattles[endbattles.length-1]
        end
        if i==battles.length-1
          pbPushBranch(thirdpage.list,sprintf("pbPhoneBattleCount(%s)>=%d",safetrcombo,i))
          pbPushBranch(secondpage.list,sprintf("pbPhoneBattleCount(%s)>%d",safetrcombo,i))
        else
          pbPushBranch(thirdpage.list,sprintf("pbPhoneBattleCount(%s)==%d",safetrcombo,i))
          pbPushBranch(secondpage.list,sprintf("pbPhoneBattleCount(%s)==%d",safetrcombo,i))
        end
        pbPushText(secondpage.list,ebattle,1)
        pbPushScript(secondpage.list,sprintf("pbPhoneRegisterBattle(_I(\"%s\"),get_character(0),%s,%d)",regspeech,safetrcombo,battles.length),1)
        pbPushExit(secondpage.list,1)
        pbPushBranchEnd(secondpage.list,1)
        pbPushScript(thirdpage.list,introplay,1)
        pbPushText(thirdpage.list,battles[i],1)
        # Run trainer check now, except in editor
        trainerChecker.pbTrainerBattleCheck(trtype,trname,battleid+i) if !$INEDITOR
        if backdrop
          pbPushScript(thirdpage.list,sprintf("$PokemonGlobal.nextBattleBack=\"%s\"",safequote(backdrop)),1)
        end
        pbPushBranch(thirdpage.list,
           sprintf("pbTrainerBattle(%s,_I(\"%s\"),%s,%d,%s,%d)",
           safetrcombo,safequote2(espeech),
           doublebattle ? "true" : "false",
           battleid+i,
           continue ? "true" : "false",
           outcome),1
        )
        pbPushScript(thirdpage.list,
           sprintf("pbPhoneIncrement(%s,%d)",safetrcombo,battles.length),2)
        pbPushSelfSwitch(thirdpage.list,"A",true,2)
        pbPushSelfSwitch(thirdpage.list,"B",false,2)
        pbPushScript(thirdpage.list,"pbTrainerEnd",2)
        pbPushBranchEnd(thirdpage.list,2)
        pbPushExit(thirdpage.list,1)
        pbPushBranchEnd(thirdpage.list,1)
      end
      ebattle=(endbattles[0]) ? endbattles[0] : "..."
      pbPushText(secondpage.list,ebattle)
      if battles.length>1
        pbPushScript(secondpage.list,sprintf("pbPhoneRegisterBattle(_I(\"%s\"),get_character(0),%s,%d)",regspeech,safetrcombo,battles.length))
      end
      pbPushEnd(secondpage.list)
      pbPushEnd(thirdpage.list)
      if battles.length==1
        ret.pages=[firstpage,secondpage]
      else
        ret.pages=[firstpage,thirdpage,secondpage]
      end
      for endswitch in endifswitch
        ebattle=(endbattles[0]) ? endbattles[0] : "..."
        endIfSwitchPage=Marshal::load(Marshal.dump(secondpage))
        endIfSwitchPage.condition=secondpage.condition.clone
        if endIfSwitchPage.condition.switch1_valid
          endIfSwitchPage.condition.switch2_valid=true
          endIfSwitchPage.condition.switch2_id=endswitch
        else
          endIfSwitchPage.condition.switch1_valid=true
          endIfSwitchPage.condition.switch1_id=endswitch
        end
        endIfSwitchPage.condition.self_switch_valid=false
        endIfSwitchPage.list=[]
        pbPushText(endIfSwitchPage.list,ebattle)
        pbPushEnd(endIfSwitchPage.list)
        ret.pages.push(endIfSwitchPage)
      end
      for endswitch in vanishifswitch
        ebattle=(endbattles[0]) ? endbattles[0] : "..."
        endIfSwitchPage=Marshal::load(Marshal.dump(secondpage))
        endIfSwitchPage.graphic.character_name="" # make blank
        endIfSwitchPage.condition=secondpage.condition.clone
        if endIfSwitchPage.condition.switch1_valid
          endIfSwitchPage.condition.switch2_valid=true
          endIfSwitchPage.condition.switch2_id=endswitch
        else
          endIfSwitchPage.condition.switch1_valid=true
          endIfSwitchPage.condition.switch1_id=endswitch
        end
        endIfSwitchPage.condition.self_switch_valid=false
        endIfSwitchPage.list=[]
        pbPushEnd(endIfSwitchPage.list)
        ret.pages.push(endIfSwitchPage)
      end
      return ret
    end
    
    #===============================================================================
    # Add new map files to the map tree
    #===============================================================================
    def pbImportNewMaps
      return false if !$DEBUG
      mapfiles={}
      # Get IDs of all maps in the Data folder
      Dir.chdir("Data"){
         mapdata=sprintf("Map*.%s","rxdata",$RPGVX ? "rvdata" : "rxdata")
         for map in Dir.glob(mapdata)
           if map[/map(\d+)\.rxdata/i]
             mapfiles[$1.to_i(10)]=true
           end
         end
      }
      mapinfos=pbLoadRxData("Data/MapInfos")
      maxOrder=0
      # Exclude maps found in mapinfos
      for id in mapinfos.keys
        next if !mapinfos.id
        if mapfiles[id]
          mapfiles.delete(id)
        end
        maxOrder=[maxOrder,mapinfos[id].order].max
      end
      # Import maps not found in mapinfos
      maxOrder+=1
      imported=false
      for id in mapfiles.keys
        next if id==999 # Ignore 999 (random dungeon map)
        mapname=sprintf("MAP%03d",id)
        mapinfo=RPG::MapInfo.new
        mapinfo.order=maxOrder
        maxOrder+=1
        mapinfo.name=mapname
        mapinfos[id]=mapinfo
        imported=true
      end
      if imported
        if $RPGVX
          save_data(mapinfos,"Data/MapInfos.rvdata")
        else
          save_data(mapinfos,"Data/MapInfos.rxdata") 
        end
        Kernel.pbMessage(_INTL("New maps copied to the Data folder were successfully imported.",id))
      end
      return imported
    end
    
    #===============================================================================
    # Compile all data
    #===============================================================================
    def pbCompileAllData(mustcompile)
      FileLineData.clear
      if mustcompile
        if (!$INEDITOR || LANGUAGES.length<2) && pbRgssExists?("Data/messages.dat")
          MessageTypes.loadMessageFile("Data/messages.dat")
        end
        # No dependencies
        yield(_INTL("Compiling type data"))
        pbCompileTypes
        # No dependencies
        yield(_INTL("Compiling town map data"))
        pbCompileTownMap
        # No dependencies
        yield(_INTL("Compiling map connection data"))
        pbCompileConnections
        # No dependencies  
        yield(_INTL("Compiling ability data"))
        pbCompileAbilities
        # Depends on PBTypes
        yield(_INTL("Compiling move data"))
        pbCompileMoves
        # Depends on PBMoves
        yield(_INTL("Compiling item data"))
        pbCompileItems
        # Depends on PBItems
        yield(_INTL("Compiling berry plant data"))
        pbCompileBerryPlants
        # Depends on PBMoves, PBItems, PBTypes, PBAbilities
        yield(_INTL("Compiling Pokemon data"))
        pbCompilePokemonData
        # Depends on PBSpecies, PBMoves
        yield(_INTL("Compiling machine data"))
        pbCompileMachines
        # Depends on PBSpecies, PBItems, PBMoves
        yield(_INTL("Compiling Trainer data"))
        pbCompileTrainers
        # Depends on PBTrainers
        yield(_INTL("Compiling phone data"))
        pbCompilePhoneData
        # Depends on PBTrainers
        yield(_INTL("Compiling metadata"))
        pbCompileMetadata
        # Depends on PBTrainers
        yield(_INTL("Compiling battle Trainer data"))
        pbCompileTrainerLists
        # Depends on PBSpecies
        yield(_INTL("Compiling encounter data"))
        pbCompileEncounters
        # Depends on PBSpecies, PBMoves
        yield(_INTL("Compiling shadow move data"))
        pbCompileShadowMoves
        #Depends on PBContestMoves #~ Required for Pokémon Contests
        yield(_INTL("Compiling contest moves"))
        pbCompileContestMoves
        yield(_INTL("Compiling messages"))
      else
        if (!$INEDITOR || LANGUAGES.length<2) && safeExists?("Data/messages.dat")
          MessageTypes.loadMessageFile("Data/messages.dat")
        end
      end
      pbCompileAnimations
      pbCompileTrainerEvents(mustcompile)
      pbSetTextMessages
      MessageTypes.saveMessages
      if !$INEDITOR && LANGUAGES.length>=2
        pbLoadMessages("Data/"+LANGUAGES[$PokemonSystem.language][1])
      end
    end
    
    begin
      if $DEBUG
        datafiles=[
                   "attacksRS.dat",
                   "berryplants.dat",
                   "connections.dat",
                   "dexdata.dat",
                   "eggEmerald.dat",
                   "encounters.dat",
                   "evolutions.dat",
                   "items.dat",
                   "metadata.dat",
                   "metrics.dat",
                   "moves.dat",
                   "contestmoves.dat", #~ Required for Pokémon Contests
                   "phone.dat",
                   "regionals.dat",
                   "shadowmoves.dat",
                   "tm.dat",
                   "townmap.dat",
                   "trainerlists.dat",
                   "trainers.dat",
                   "trainertypes.dat",
                   "types.dat",
                   "Constants.rxdata"
                   ]
        textfiles=[
                   "abilities.txt",
                   "berryplants.txt",
                   "connections.txt",
                   "encounters.txt",
                   "items.txt",
                   "metadata.txt",
                   "moves.txt",
                   "contestmoves.txt", #~ Required for Pokémon Contests            
                   "phone.txt",
                   "pokemon.txt",
                   "shadowmoves.txt",
                   "tm.txt",
                   "townmap.txt",
                   "trainerlists.txt",
                   "trainers.txt",
                   "trainertypes.txt",
                   "types.txt"
                   ]
        latestdatatime=0
        latesttexttime=0
        mustcompile=false
        mustcompile|=pbImportNewMaps
        mustcompile|=!(PBSpecies.respond_to?("maxValue") rescue false)
        if !safeIsDirectory?("PBS")
          Dir.mkdir("PBS") rescue nil
          pbSaveAllData()
          mustcompile=true
        end
        for i in 0...datafiles.length
          begin
            File.open("Data/#{datafiles[i]}"){|file|
               latestdatatime=[latestdatatime,file.mtime.to_i].max
            }
          rescue SystemCallError
            mustcompile=true
          end
        end
        for i in 0...textfiles.length
          begin
            File.open("PBS/#{textfiles[i]}"){|file|
               latesttexttime=[latesttexttime,file.mtime.to_i].max
            }
          rescue SystemCallError
          end
        end
        mustcompile=mustcompile || (latesttexttime>=latestdatatime)
        Input.update
        mustcompile=true if Input.press?(Input::CTRL)
        if mustcompile
          for i in 0...datafiles.length
            begin
              File.delete("Data/#{datafiles[i]}")
            rescue SystemCallError
            end
          end
        end
        pbCompileAllData(mustcompile){|msg| Win32API.SetWindowText(msg) }
      end
    rescue Exception
      e=$!
      raise e if "#{e.class}"=="Reset" || e.is_a?(Reset) || e.is_a?(SystemExit)
      pbPrintException(e)
      for i in 0...datafiles.length
        begin
          File.delete("Data/#{datafiles[i]}")
        rescue SystemCallError
        end
      end
      raise Reset.new if e.is_a?(Hangup)
      loop do
        Graphics.update
      end
    end

    And Intl_Messages should be this:
    Code:
    def pbAddScriptTexts(items,script)
      script.scan(/(?:_I)\s*\(\s*\"((?:[^\\\"]*\\\"?)*[^\"]*)\"/){|s|
         string=s[0]
         string.gsub!(/\\\"/,"\"")
         string.gsub!(/\\\\/,"\\")
         items.push(string)
      }
    end
    
    def pbAddRgssScriptTexts(items,script)
      script.scan(/(?:_INTL|_ISPRINTF)\s*\(\s*\"((?:[^\\\"]*\\\"?)*[^\"]*)\"/){|s|
         string=s[0]
         string.gsub!(/\\r/,"\r")
         string.gsub!(/\\n/,"\n")
         string.gsub!(/\\1/,"\1")
         string.gsub!(/\\\"/,"\"")
         string.gsub!(/\\\\/,"\\")
         items.push(string)
      }
    end
    
    def pbSetTextMessages
      Graphics.update
      begin
        t = Time.now.to_i
        texts=[]
        for script in $RGSS_SCRIPTS
          if Time.now.to_i - t >= 5
            t = Time.now.to_i
            Graphics.update
          end
          scr=Zlib::Inflate.inflate(script[2])
          pbAddRgssScriptTexts(texts,scr)
        end
        # Must add messages because this code is used by both game system and Editor
        MessageTypes.addMessagesAsHash(MessageTypes::ScriptTexts,texts)
        commonevents=pbLoadRxData("Data/CommonEvents")
        items=[]
        choices=[]
        for event in commonevents.compact
          if Time.now.to_i - t >= 5
            t = Time.now.to_i
            Graphics.update
          end
          begin
            neednewline=false
            lastitem=""
            for j in 0...event.list.size
              list = event.list[j]
              if neednewline && list.code!=401
                if lastitem!=""
                  lastitem.gsub!(/([^\.\!\?])\s\s+/){|m| $1+" "}
                  items.push(lastitem)
                  lastitem=""
                end         
                neednewline=false
              end
              if list.code == 101
                lastitem+="#{list.parameters[0]}" if !$RPGVX
                neednewline=true
              elsif list.code == 102
                for k in 0...list.parameters[0].length
                  choices.push(list.parameters[0][k])
                end
                neednewline=false
              elsif list.code == 401
                lastitem+=" " if lastitem!=""
                lastitem+="#{list.parameters[0]}"
                neednewline=true
              elsif list.code == 355 || list.code == 655
                pbAddScriptTexts(items,list.parameters[0])
              elsif list.code == 111 && list.parameters[0]==12
                pbAddScriptTexts(items,list.parameters[1])
              elsif list.code == 209
                route=list.parameters[1]
                for k in 0...route.list.size
                  if route.list[k].code == 45
                    pbAddScriptTexts(items,route.list[k].parameters[0])
                  end
                end
              end
            end
            if neednewline
              if lastitem!=""
                items.push(lastitem)
                lastitem=""
              end         
            end
          end
        end
        if Time.now.to_i - t >= 5
          t = Time.now.to_i
          Graphics.update
        end
        items|=[]
        choices|=[]
        items.concat(choices)
        MessageTypes.setMapMessagesAsHash(0,items)
        mapinfos = pbLoadRxData("Data/MapInfos")
        mapnames=[]
        for id in mapinfos.keys
          mapnames[id]=mapinfos[id].name
        end
        MessageTypes.setMessages(MessageTypes::MapNames,mapnames)
        for id in mapinfos.keys
          if Time.now.to_i - t >= 5
            t = Time.now.to_i
            Graphics.update
          end
          filename=sprintf("Data/Map%03d.%s",id,$RPGVX ? "rvdata" : "rxdata")
          next if !pbRgssExists?(filename)
          map = load_data(filename)
          items=[]
          choices=[]
          for event in map.events.values
            if Time.now.to_i - t >= 5
              t = Time.now.to_i
              Graphics.update
            end
            begin
              for i in 0...event.pages.size
                neednewline=false
                lastitem=""
                for j in 0...event.pages[i].list.size
                  list = event.pages[i].list[j]
                  if neednewline && list.code!=401
                    if lastitem!=""
                      lastitem.gsub!(/([^\.\!\?])\s\s+/){|m| $1+" "}
                      items.push(lastitem)
                      lastitem=""
                    end         
                    neednewline=false
                  end
                  if list.code == 101
                    lastitem+="#{list.parameters[0]}" if !$RPGVX
                    neednewline=true
                  elsif list.code == 102
                    for k in 0...list.parameters[0].length
                      choices.push(list.parameters[0][k])
                    end
                    neednewline=false
                  elsif list.code == 401
                    lastitem+=" " if lastitem!=""
                    lastitem+="#{list.parameters[0]}"
                    neednewline=true
                  elsif list.code == 355 || list.code==655
                    pbAddScriptTexts(items,list.parameters[0])
                  elsif list.code == 111 && list.parameters[0]==12
                    pbAddScriptTexts(items,list.parameters[1])
                  elsif list.code==209
                    route=list.parameters[1]
                    for k in 0...route.list.size
                      if route.list[k].code==45
                        pbAddScriptTexts(items,route.list[k].parameters[0])
                      end
                    end
                  end
                end
                if neednewline
                  if lastitem!=""
                    items.push(lastitem)
                    lastitem=""
                  end         
                end
              end
            end
          end
          if Time.now.to_i - t >= 5
            t = Time.now.to_i
            Graphics.update
          end
          items|=[]
          choices|=[]
          items.concat(choices)
          MessageTypes.setMapMessagesAsHash(id,items)
          if Time.now.to_i - t >= 5
            t = Time.now.to_i
            Graphics.update
          end
        end
      rescue Hangup
      end
      Graphics.update
    end
    
    def pbEachIntlSection(file)
      lineno=1
      re=/^\s*\[\s*([^\]]+)\s*\]\s*$/
      havesection=false
      sectionname=nil
      lastsection=[]
      file.each_line {|line|
         if lineno==1 && line[0]==0xEF && line[1]==0xBB && line[2]==0xBF
           line=line[3,line.length-3]
         end
         if !line[/^\#/] && !line[/^\s*$/]
           if line[re]
             if havesection
               yield lastsection,sectionname 
             end
             lastsection.clear
             sectionname=$~[1]
             havesection=true
           else
             if sectionname==nil
               raise _INTL("Expected a section at the beginning of the file (line {1})",lineno)
             end
             lastsection.push(line.gsub(/\s+$/,""))
           end
         end
         lineno+=1
         if lineno%500==0
           Graphics.update
         end
      }
      if havesection
        yield lastsection,sectionname 
      end
    end
    
    def pbGetText(infile)
      begin
        file=File.open(infile,"rb") 
      rescue
        raise _INTL("Can't find {1}",infile)
      end
      intldat=[]
      begin
        pbEachIntlSection(file){|section,name|
           index=name
           if section.length==0
             next
           end
           if !name[/^([Mm][Aa][Pp])?(\d+)$/]
             raise _INTL("Invalid section name {1}",name)
           end
           ismap=$~[1] && $~[1]!=""
           id=$~[2].to_i
           itemlength=0
           if section[0][/^\d+$/]
             intlhash=[]
             itemlength=3
             if ismap
               raise _INTL("Section {1} can't be an ordered list (section was recognized as an ordered list because its first line is a number)",name)
             end
             if section.length%3!=0
               raise _INTL("Section {1}'s line count is not divisible by 3 (section was recognized as an ordered list because its first line is a number)",name)
             end
           else
             intlhash=OrderedHash.new
             itemlength=2
             if section.length%2!=0
               raise _INTL("Section {1} has an odd number of entries (section was recognized as a hash because its first line is not a number)",name)
             end
           end
           i=0;loop do break unless i<section.length
             if itemlength==3
               if !section[i][/^\d+$/]
                 raise _INTL("Expected a number in section {1}, got {2} instead",name,section[i])
               end
               key=section[i].to_i
               i+=1
             else
               key=MessageTypes.denormalizeValue(section[i])
             end
             intlhash[key]=MessageTypes.denormalizeValue(section[i+1])
             i+=2
           end
           if ismap
             intldat[0]=[] if !intldat[0]
             intldat[0][id]=intlhash
           else
             intldat[id]=intlhash
           end
        }
      ensure
        file.close
      end
      return intldat
    end
    
    def pbCompileText
      outfile=File.open("intl.dat","wb")
      begin
        intldat=pbGetText("intl.txt")
        Marshal.dump(intldat,outfile)
      rescue
        raise
      ensure
        outfile.close
      end
    end
    
    
    
    class OrderedHash < Hash
      def initialize
        @keys=[]
        super
      end
    
      def keys
        return @keys.clone
      end
    
      def inspect
        str="{"
        for i in [email protected]
          str+=", " if i>0
          str+=@keys[i].inspect+"=>"+self[@keys[i]].inspect
        end
        str+="}"
        return str
      end
    
      alias :to_s :inspect
    
      def []=(key,value)
        oldvalue=self[key]
        if !oldvalue && value
          @keys.push(key)
        elsif !value
          @keys|=[]
          @keys-=[key]
        end
        return super(key,value)
      end
    
      def self._load(string)
        ret=self.new
        keysvalues=Marshal.load(string)
        keys=keysvalues[0]
        values=keysvalues[1]
        for i in 0...keys.length
          ret[keys[i]]=values[i]
        end
        return ret
      end
    
      def _dump(depth=100)
        values=[]
        for key in @keys
          values.push(self[key])
        end
        return Marshal.dump([@keys,values])
      end
    end
    
    
    
    class Messages
      def initialize(filename=nil,delayLoad=false)
        @messages=nil
        @filename=filename
        if @filename && !delayLoad
          loadMessageFile(@filename)
        end
      end
    
      def delayedLoad
        if @filename && !@messages
          loadMessageFile(@filename)
          @filename=nil
        end
      end
    
      def self.stringToKey(str)
        if str[/[\r\n\t\1]|^\s+|\s+$|\s{2,}/]
           key=str.clone
           key.gsub!(/^\s+/,"")
           key.gsub!(/\s+$/,"")
           key.gsub!(/\s{2,}/," ")
           return key
        end
        return str
      end
    
      def self.normalizeValue(value)
        if value[/[\r\n\t\x01]|^[\[\]]/]
          ret=value.clone
          ret.gsub!(/\r/,"<<r>>")
          ret.gsub!(/\n/,"<<n>>")
          ret.gsub!(/\t/,"<<t>>")
          ret.gsub!(/\[/,"<<[>>")
          ret.gsub!(/\]/,"<<]>>")
          ret.gsub!(/\x01/,"<<1>>")
          return ret
        end
        return value
      end
    
      def self.denormalizeValue(value)
        if value[/<<[rnt1\[\]]>>/]
          ret=value.clone
          ret.gsub!(/<<1>>/,"\1")
          ret.gsub!(/<<r>>/,"\r")
          ret.gsub!(/<<n>>/,"\n")
          ret.gsub!(/<<\[>>/,"[")
          ret.gsub!(/<<\]>>/,"]")
          ret.gsub!(/<<t>>/,"\t")
          return ret
        end
        return value
      end
    
      def self.writeObject(f,msgs,secname,origMessages=nil)
        return if !msgs
        if msgs.is_a?(Array)
          f.write("[#{secname}]\r\n")
          for j in 0...msgs.length
            next if msgs[j]==nil || msgs[j]==""
            value=Messages.normalizeValue(msgs[j])
            origValue=""
            if origMessages
              origValue=Messages.normalizeValue(origMessages.get(secname,j))
            else
              origValue=Messages.normalizeValue(MessageTypes.get(secname,j))
            end
            f.write("#{j}\r\n")
            f.write(origValue+"\r\n")
            f.write(value+"\r\n")
          end
        elsif msgs.is_a?(OrderedHash)
          f.write("[#{secname}]\r\n")
          keys=msgs.keys
          for key in keys
            next if msgs[key]==nil || msgs[key]==""
            value=Messages.normalizeValue(msgs[key])
            valkey=Messages.normalizeValue(key)
            # key is already serialized
            f.write(valkey+"\r\n")
            f.write(value+"\r\n")
          end
        end
      end
    
      def messages
        return @messages || []
      end
    
      def extract(outfile)
    #    return if !@messages
        origMessages=Messages.new("Data/messages.dat")
        File.open(outfile,"wb"){|f|
           f.write(0xef.chr)
           f.write(0xbb.chr)
           f.write(0xbf.chr)
           f.write("# To localize this text for a particular language, please\r\n")
           f.write("# translate every second line of this file.\r\n")
           if origMessages.messages[0]
             for i in 0...origMessages.messages[0].length
               msgs=origMessages.messages[0][i]
               Messages.writeObject(f,msgs,"Map#{i}",origMessages)
             end
           end
           for i in 1...origMessages.messages.length
             msgs=origMessages.messages[i]
             Messages.writeObject(f,msgs,i,origMessages)
           end
        }
      end
    
      def setMessages(type,array)
        arr=[]
        @messages=[] if !@messages
        for i in 0...array.length
          arr[i]=(array[i]) ? array[i] : ""
        end
        @messages[type]=arr
      end
    
      def self.createHash(type,array)
        arr=OrderedHash.new
        for i in 0...array.length
          if array[i]
            key=Messages.stringToKey(array[i])
            arr[key]=array[i]
          end
        end
        return arr
      end
    
      def self.addToHash(type,array,hash)
        if !hash
          hash=OrderedHash.new
        end
        for i in 0...array.length
          if array[i]
            key=Messages.stringToKey(array[i])
            hash[key]=array[i]
          end
        end
        return hash
      end
    
      def setMapMessagesAsHash(type,array)
        @messages=[] if !@messages
        @messages[0]=[] if !@messages[0]
        @messages[0][type]=Messages.createHash(type,array)
      end
    
      def addMapMessagesAsHash(type,array)
        @messages=[] if !@messages
        @messages[0]=[] if !@messages[0]
        @messages[0][type]=Messages.addToHash(type,array,@messages[0][type])
      end
    
      def setMessagesAsHash(type,array)
        @messages=[] if !@messages
        @messages[type]=Messages.createHash(type,array)
      end
    
      def addMessagesAsHash(type,array)
        @messages=[] if !@messages
        @messages[type]=Messages.addToHash(type,array,@messages[type])
      end
    
      def saveMessages(filename=nil)
        filename="Data/messages.dat" if !filename
        File.open(filename,"wb"){|f|
           Marshal.dump(@messages,f)
        }
      end
    
      def loadMessageFile(filename)
        begin
          Kernel.pbRgssOpen(filename,"rb"){|f|
             @messages=Marshal.load(f)
          }
          if [email protected]_a?(Array)
            @messages=nil
            raise "Corrupted data"
          end
          return @messages
        rescue
          @messages=nil
          return nil
        end
      end
    
      def set(type,id,value)
        delayedLoad
        return if !@messages
        return if !@messages[type]
        @messages[type][id]=value
      end
    
      def getCount(type)
        delayedLoad
        return 0 if !@messages
        return 0 if !@messages[type]
        return @messages[type].length
      end
    
      def get(type,id)
        delayedLoad
        return "" if !@messages
        return "" if !@messages[type]
        return "" if !@messages[type][id]
        return @messages[type][id]
      end
    
      def getFromHash(type,key)
        delayedLoad
        return key if !@messages
        return key if !@messages[type]
        id=Messages.stringToKey(key)
        return key if !@messages[type][id]
        return @messages[type][id]
      end
    
      def getFromMapHash(type,key)
        delayedLoad
        return key if !@messages
        return key if !@messages[0]
        return key if !@messages[0][type] && !@messages[0][0]
        id=Messages.stringToKey(key)
        if @messages[0][type] &&  @messages[0][type][id]
          return @messages[0][type][id]
        elsif @messages[0][0] && @messages[0][0][id]
          return @messages[0][0][id]
        end
        return key
      end
    end
    
    
    
    module MessageTypes
      # Value 0 is used for common event and map event text
      Species           = 1
      Kinds             = 2
      Entries           = 3
      FormNames         = 4
      Moves             = 5
      MoveDescriptions  = 6
      Items             = 7
      ItemPlurals       = 8
      ItemDescriptions  = 9
      Abilities         = 10
      AbilityDescs      = 11
      Types             = 12
      TrainerTypes      = 13
      TrainerNames      = 14
      BeginSpeech       = 15
      EndSpeechWin      = 16
      EndSpeechLose     = 17
      RegionNames       = 18
      PlaceNames        = 19
      PlaceDescriptions = 20
      MapNames          = 21
      PhoneMessages     = 22
      ScriptTexts       = 23
      ContestMoves      = 24
      ContestMoveDescriptions = 25
      @@messages         = Messages.new
      @@messagesFallback = Messages.new("Data/messages.dat",true)
    
      def self.stringToKey(str)
        return Messages.stringToKey(str)
      end
    
      def self.normalizeValue(value)
        return Messages.normalizeValue(value)
      end
    
      def self.denormalizeValue(value)
        Messages.denormalizeValue(value)
      end
    
      def self.writeObject(f,msgs,secname)
        Messages.denormalizeValue(str)
      end
    
      def self.extract(outfile)
        @@messages.extract(outfile)
      end
    
      def self.setMessages(type,array)
        @@messages.setMessages(type,array)
      end
    
      def self.createHash(type,array)
        Messages.createHash(type,array)
      end
    
      def self.addMapMessagesAsHash(type,array)
        @@messages.addMapMessagesAsHash(type,array)
      end
    
      def self.setMapMessagesAsHash(type,array)
        @@messages.setMapMessagesAsHash(type,array)
      end
    
      def self.addMessagesAsHash(type,array)
        @@messages.addMessagesAsHash(type,array)
      end
    
      def self.setMessagesAsHash(type,array)
        @@messages.setMessagesAsHash(type,array)
      end
    
      def self.saveMessages(filename=nil)
        @@messages.saveMessages(filename)
      end
    
      def self.loadMessageFile(filename)
        @@messages.loadMessageFile(filename)
      end
    
      def self.get(type,id)
        ret=@@messages.get(type,id)
        if ret==""
          ret=@@messagesFallback.get(type,id)
        end
        return ret
      end
    
      def self.getCount(type)
        c1=@@messages.getCount(type)
        c2=@@messagesFallback.getCount(type)
        return c1>c2 ? c1 : c2
      end
    
      def self.getOriginal(type,id)
        return @@messagesFallback.get(type,id)
      end
    
      def self.getFromHash(type,key)
        @@messages.getFromHash(type,key)
      end
    
      def self.getFromMapHash(type,key)
        @@messages.getFromMapHash(type,key)
      end
    end
    
    
    
    def pbLoadMessages(file)
      return MessageTypes.loadMessageFile(file)
    end
    
    def pbGetMessageCount(type)
      return MessageTypes.getCount(type)
    end
    
    def pbGetMessage(type,id)
      return MessageTypes.get(type,id)
    end
    
    def pbGetMessageFromHash(type,id)
      return MessageTypes.getFromHash(type,id)
    end
    
    # Replaces first argument with a localized version and formats the other
    # parameters by replacing {1}, {2}, etc. with those placeholders.
    def _INTL(*arg)
      begin
        string=MessageTypes.getFromHash(MessageTypes::ScriptTexts,arg[0])
      rescue
        string=arg[0]
      end
      string=string.clone
      for i in 1...arg.length
        string.gsub!(/\{#{i}\}/,"#{arg[i]}")
      end
      return string
    end
    
    # Replaces first argument with a localized version and formats the other
    # parameters by replacing {1}, {2}, etc. with those placeholders.
    # This version acts more like sprintf, supports e.g. {1:d} or {2:s}
    def _ISPRINTF(*arg)
      begin
        string=MessageTypes.getFromHash(MessageTypes::ScriptTexts,arg[0])
      rescue
        string=arg[0]
      end
      string=string.clone
      for i in 1...arg.length
        string.gsub!(/\{#{i}\:([^\}]+?)\}/){|m|
           next sprintf("%"+$1,arg[i])
        }
      end
      return string
    end
    
    def _I(str)
      return _MAPINTL($game_map.map_id,str)
    end
    
    def _MAPINTL(mapid,*arg)
      string=MessageTypes.getFromMapHash(mapid,arg[0])
      string=string.clone
      for i in 1...arg.length
        string.gsub!(/\{#{i}\}/,"#{arg[i]}")
      end
      return string
    end
    
    def _MAPISPRINTF(mapid,*arg)
      string=MessageTypes.getFromMapHash(mapid,arg[0])
      string=string.clone
      for i in 1...arg.length
        string.gsub!(/\{#{i}\:([^\}]+?)\}/){|m|
           next sprintf("%"+$1,arg[i])
        }
      end
      return string
    end

    Again don't forget to use Thread Tools Show Printable Version.
     

    mewlover22

    Pokemon Creator
    455
    Posts
    15
    Years
  • Will all of this make the script work right when it gets to loading round one and two other questions one how do we make the pokebolocks work and how do we set it up so people can see what type of contest move it is?
     
    31
    Posts
    8
    Years
  • Yeah it should all work right.
    I am uploading it to my google drive account
    https://drive.google.com/file/d/0B7-78oA2YokuZXowNV9reG9yWnM/view?usp=sharing
    It is v.16.1 with all the fixes and changes in a fresh download of Pokemon Essentials v16.1
    This one includes The Elite Battle System, 6 Gen Project (All Pokémon (721), All The Items (All items I have so you will not have one on the list and I am still working on the Pokéblock Case)), Show Species updated to work with the animated battlers, and Pokémon Following.
    This is all required if you want the animated battlers.
    (And Pokémon Following script isn't required, but I just included anyways.)

    Also there are still some problems with the Contest Script like sometimes when your pokemon should be the winner it isn't and I don't know how to fix.
    I had pikachu in the cool contest and squirtle won even though the bar shows pikachu had more points and should have been the winner...
    And I am sure there are still other problems with the script, but the person who started this doesn't seem to want to work on any of it.
     
    Last edited:

    mewlover22

    Pokemon Creator
    455
    Posts
    15
    Years
  • It works on the version i have i just need to know hoe to get pokeblocks to work right and i figured out how to make the summary screen show contest move type buy changing a few things from the contest kit when i copy over the storage and summary stuff.
     
    Last edited:
    31
    Posts
    8
    Years
  • All I know is that you add the Berry Item Effects to PItem_ItemEffects under the BattleUseOnPokemon handlers (at the bottom of that list is where I put it). And that is the pokeblocks effects. The current problem is no one has finished the pokeblock case or done the conditions summary screen so that you can see the pokeblocks effects on your pokemon.

    It looks like it is being used
    Code:
      case @contestType
      when "Cool"
        @prelim1+=20 if isConst?($Trainer.party[$game_variables[36]].item,PBItems,:REDSCARF)
        @prelim1+=($Trainer.party[$game_variables[36]].cool/8).floor
      when "Beauty"
        @prelim1+=20 if isConst?($Trainer.party[$game_variables[36]].item,PBItems,:BLUESCARF)
        @prelim1+=($Trainer.party[$game_variables[36]].beauty/8).floor
      when "Smart"
        @prelim1+=20 if isConst?($Trainer.party[$game_variables[36]].item,PBItems,:GREENSCARF)
        @prelim1+=($Trainer.party[$game_variables[36]].smart/8).floor
      when "Tough"
        @prelim1+=20 if isConst?($Trainer.party[$game_variables[36]].item,PBItems,:YELLOWSCARF)
        @prelim1+=($Trainer.party[$game_variables[36]].tough/8).floor
      when "Cute"
        @prelim1+=20 if isConst?($Trainer.party[$game_variables[36]].item,PBItems,:PINKSCARF)  
        @prelim1+=($Trainer.party[$game_variables[36]].cute/8).floor
      end

    I just thought about it and and we may need to change all the pokemon.cool, pokemon.beauty, pokemon.cute, pokemon.smart, and pokemon.tough to the variable being used or set it to it's own variables and tweek the script for the new variables under the same area of the contest script....
    I am unsure if the pokeblocks really are being taken into account as is...
     
    Last edited:

    mewlover22

    Pokemon Creator
    455
    Posts
    15
    Years
  • mej71 has them set up right but there's no summary screen for them you can use them on the poekmon but idk what they do as it's using the default text from gen 3.
     

    Pokébook1

    Marene
    114
    Posts
    8
    Years
  • I know it is to late to write here because it passed maybe a month but I have got problems with this script, I got this error message:

    Spoiler:
     
    1,224
    Posts
    10
    Years
  • I know it is to late to write here because it passed maybe a month but I have got problems with this script, I got this error message:

    Spoiler:

    The method egg? no longer exists in Essentials, and was replaced with isEgg?
     
    155
    Posts
    10
    Years
    • Seen Jun 11, 2021
    I know it is to late to write here because it passed maybe a month but I have got problems with this script, I got this error message:

    Spoiler:
    You need to replace every instance of "egg?" to "isEgg?". That should be it.
     
    Last edited:

    Pokébook1

    Marene
    114
    Posts
    8
    Years
  • The method egg? no longer exists in Essentials, and was replaced with isEgg?
    I replaced "egg?" with "isEgg?" in PokeBattle_Battler but when I playtest and go inside the Contest Hall and talk to the lady in front of the desk, the screen turns black and this error message pops up:

    Spoiler:


    I already searched pbExecuteScript in the Script section but I couldn't find it :(
    If you know where I must replace it, it would be great and I use the newest Essentials and I don't know if this script supports the new Essentials. Since those scripts have no "isEgg?" in it.
     

    Zeak6464

    Zeak #3205 - Discord
    1,101
    Posts
    11
    Years
  • I replaced "egg?" with "isEgg?" in PokeBattle_Battler but when I playtest and go inside the Contest Hall and talk to the lady in front of the desk, the screen turns black and this error message pops up:

    Spoiler:


    I already searched pbExecuteScript in the Script section but I couldn't find it :(
    If you know where I must replace it, it would be great and I use the newest Essentials and I don't know if this script supports the new Essentials. Since those scripts have no "isEgg?" in it.

    pbChoosePokemon(36,2,proc {|poke|!poke.egg? && !(poke.isShadow? rescue false) && !poke.hasRibbon?(4)})

    replace the poke.egg? to poke.isEgg?
     

    Maruno

    Lead Dev of Pokémon Essentials
    5,286
    Posts
    16
    Years
    • Seen May 3, 2024
    Because Zeak didn't say so, that line of code is actually in an event, not in the scripts. Specifically, the desk lady's event.
     

    Pokébook1

    Marene
    114
    Posts
    8
    Years
  • pbChoosePokemon(36,2,proc {|poke|!poke.egg? && !(poke.isShadow? rescue false) && !poke.hasRibbon?(4)})

    replace the poke.egg? to poke.isEgg?

    I searched in the Script editor for "pbChoosePokemon" and could not find the part "egg?" but there just says "isEgg?". Can you please tell me where the section is where I have to replace it.

    Thanks in advance
     
    Back
    Top