# Battle scene (the visuals of the battle) class PokeBattle_Scene attr_accessor :abortable # For non-interactive battles, can quit immediately attr_reader :viewport attr_reader :sprites BLANK = 0 MESSAGE_BOX = 1 COMMAND_BOX = 2 FIGHT_BOX = 3 TARGET_BOX = 4 MESSAGE_PAUSE_TIME = (Graphics.frame_rate*0.25).floor # 1 second #============================================================================= # Updating and refreshing #============================================================================= def pbUpdate(cw=nil) pbGraphicsUpdate pbInputUpdate pbFrameUpdate(cw) end def pbGraphicsUpdate # Update lineup animations if @animations.length>0 shouldCompact = false @animations.each_with_index do |a,i| a.update if a.animDone? a.dispose @animations[i] = nil shouldCompact = true end end @animations.compact! if shouldCompact end # Update other graphics @sprites["battle_bg"].update if @sprites["battle_bg"].respond_to?("update") Graphics.update @frameCounter += 1 @frameCounter = @frameCounter%(Graphics.frame_rate*12/20) end def pbInputUpdate Input.update if Input.trigger?(Input::BACK) && @abortable && !@aborted @aborted = true @battle.pbAbort end end def pbFrameUpdate(cw=nil) cw.update if cw @battle.battlers.each_with_index do |b,i| next if !b @sprites["dataBox_#{i}"].update(@frameCounter) if @sprites["dataBox_#{i}"] @sprites["pokemon_#{i}"].update(@frameCounter) if @sprites["pokemon_#{i}"] @sprites["shadow_#{i}"].update(@frameCounter) if @sprites["shadow_#{i}"] end end def pbRefresh @battle.battlers.each_with_index do |b,i| next if !b @sprites["dataBox_#{i}"].refresh if @sprites["dataBox_#{i}"] end end def pbRefreshOne(idxBattler) @sprites["dataBox_#{idxBattler}"].refresh if @sprites["dataBox_#{idxBattler}"] end #============================================================================= # Party lineup #============================================================================= # Returns whether the party line-ups are currently coming on-screen def inPartyAnimation? return @animations.length>0 end #============================================================================= # Window displays #============================================================================= def pbShowWindow(windowType) # NOTE: If you are not using fancy graphics for the command/fight menus, you # will need to make "messageBox" also visible if the windowtype if # COMMAND_BOX/FIGHT_BOX respectively. @sprites["messageBox"].visible = (windowType==MESSAGE_BOX) @sprites["messageWindow"].visible = (windowType==MESSAGE_BOX) @sprites["commandWindow"].visible = (windowType==COMMAND_BOX) @sprites["fightWindow"].visible = (windowType==FIGHT_BOX) @sprites["targetWindow"].visible = (windowType==TARGET_BOX) end # This is for the end of brief messages, which have been lingering on-screen # while other things happened. This is only called when another message wants # to be shown, and makes the brief message linger for one more second first. # Some animations skip this extra second by setting @briefMessage to false # despite not having any other messages to show. def pbWaitMessage return if !@briefMessage pbShowWindow(MESSAGE_BOX) cw = @sprites["messageWindow"] MESSAGE_PAUSE_TIME.times do pbUpdate(cw) end cw.text = "" cw.visible = false @briefMessage = false end # NOTE: A regular message is displayed for 1 second after it fully appears (or # less if Back/Use is pressed). Disappears automatically after that time. def pbDisplayMessage(msg,brief=false) pbWaitMessage pbShowWindow(MESSAGE_BOX) cw = @sprites["messageWindow"] cw.setText(msg) PBDebug.log(msg) yielded = false i = 0 loop do pbUpdate(cw) if !cw.busy? if !yielded yield if block_given? # For playing SE as soon as the message is all shown yielded = true end if brief # NOTE: A brief message lingers on-screen while other things happen. A # regular message has to end before the game can continue. @briefMessage = true break end if i>=MESSAGE_PAUSE_TIME # Autoclose after 1 second cw.text = "" cw.visible = false break end i += 1 end if Input.trigger?(Input::BACK) || Input.trigger?(Input::USE) || @abortable if cw.busy? pbPlayDecisionSE if cw.pausing? && !@abortable cw.skipAhead elsif !@abortable cw.text = "" cw.visible = false break end end end end alias pbDisplay pbDisplayMessage # NOTE: A paused message has the arrow in the bottom corner indicating there # is another message immediately afterward. It is displayed for 3 # seconds after it fully appears (or less if B/C is pressed) and # disappears automatically after that time, except at the end of battle. def pbDisplayPausedMessage(msg) pbWaitMessage pbShowWindow(MESSAGE_BOX) cw = @sprites["messageWindow"] cw.text = _INTL("{1}\1",msg) PBDebug.log(msg) yielded = false i = 0 loop do pbUpdate(cw) if !cw.busy? if !yielded yield if block_given? # For playing SE as soon as the message is all shown yielded = true end if !@battleEnd if i>=MESSAGE_PAUSE_TIME*3 # Autoclose after 3 seconds cw.text = "" cw.visible = false break end i += 1 end end if Input.trigger?(Input::BACK) || Input.trigger?(Input::USE) || @abortable if cw.busy? pbPlayDecisionSE if cw.pausing? && !@abortable cw.skipAhead elsif !@abortable cw.text = "" pbPlayDecisionSE break end end end end def pbDisplayConfirmMessage(msg) return pbShowCommands(msg,[_INTL("Yes"),_INTL("No")],1)==0 end def pbShowCommands(msg,commands,defaultValue) pbWaitMessage pbShowWindow(MESSAGE_BOX) dw = @sprites["messageWindow"] dw.text = msg cw = Window_CommandPokemon.new(commands) cw.x = Graphics.width-cw.width cw.y = Graphics.height-cw.height-dw.height cw.z = dw.z+1 cw.index = 0 cw.viewport = @viewport PBDebug.log(msg) loop do cw.visible = (!dw.busy?) pbUpdate(cw) dw.update if Input.trigger?(Input::BACK) && defaultValue>=0 if dw.busy? pbPlayDecisionSE if dw.pausing? dw.resume else cw.dispose dw.text = "" return defaultValue end elsif Input.trigger?(Input::USE) if dw.busy? pbPlayDecisionSE if dw.pausing? dw.resume else cw.dispose dw.text = "" return cw.index end end end end #============================================================================= # Sprites #============================================================================= def pbAddSprite(id,x,y,filename,viewport) sprite = IconSprite.new(x,y,viewport) if filename sprite.setBitmap(filename) rescue nil end @sprites[id] = sprite return sprite end def pbAddPlane(id,filename,viewport) sprite = AnimatedPlane.new(viewport) if filename sprite.setBitmap(filename) end @sprites[id] = sprite return sprite end def pbDisposeSprites pbDisposeSpriteHash(@sprites) end # Used by Ally Switch. def pbSwapBattlerSprites(idxA,idxB) @sprites["pokemon_#{idxA}"], @sprites["pokemon_#{idxB}"] = @sprites["pokemon_#{idxB}"], @sprites["pokemon_#{idxA}"] @sprites["shadow_#{idxA}"], @sprites["shadow_#{idxB}"] = @sprites["shadow_#{idxB}"], @sprites["shadow_#{idxA}"] @lastCmd[idxA], @lastCmd[idxB] = @lastCmd[idxB], @lastCmd[idxA] @lastMove[idxA], @lastMove[idxB] = @lastMove[idxB], @lastMove[idxA] [idxA,idxB].each do |i| @sprites["pokemon_#{i}"].index = i @sprites["pokemon_#{i}"].pbSetPosition @sprites["shadow_#{i}"].index = i @sprites["shadow_#{i}"].pbSetPosition @sprites["dataBox_#{i}"].battler = @battle.battlers[i] end pbRefresh end #============================================================================= # Phases #============================================================================= def pbBeginCommandPhase @sprites["messageWindow"].text = "" end def pbBeginAttackPhase pbSelectBattler(-1) pbShowWindow(MESSAGE_BOX) end def pbBeginEndOfRoundPhase end def pbEndBattle(_result) @abortable = false pbShowWindow(BLANK) # Fade out all sprites pbBGMFade(1.0) pbFadeOutAndHide(@sprites) pbDisposeSprites end #============================================================================= # #============================================================================= def pbSelectBattler(idxBattler,selectMode=1) numWindows = @battle.sideSizes.max*2 for i in 0...numWindows sel = (idxBattler.is_a?(Array)) ? !idxBattler[i].nil? : i==idxBattler selVal = (sel) ? selectMode : 0 @sprites["dataBox_#{i}"].selected = selVal if @sprites["dataBox_#{i}"] @sprites["pokemon_#{i}"].selected = selVal if @sprites["pokemon_#{i}"] end end def pbChangePokemon(idxBattler,pkmn) idxBattler = idxBattler.index if idxBattler.respond_to?("index") pkmnSprite = @sprites["pokemon_#{idxBattler}"] shadowSprite = @sprites["shadow_#{idxBattler}"] back = !@battle.opposes?(idxBattler) shadowSprite.setPokemonBitmap(pkmn) pkmnSprite.setPokemonBitmap(pkmn,back) pkmnSprite.mirror=true if back # Set visibility of battler's shadow shadowSprite.visible = true#pkmn.species_data.shows_shadow? if shadowSprite #&& !back end def pbResetMoveIndex(idxBattler) @lastMove[idxBattler] = 0 end #============================================================================= # #============================================================================= # This method is called when the player wins a wild Pokémon battle. # This method can change the battle's music for example. def pbWildBattleSuccess @battleEnd = true pbBGMPlay(pbGetWildVictoryME) end # This method is called when the player wins a trainer battle. # This method can change the battle's music for example. def pbTrainerBattleSuccess @battleEnd = true pbBGMPlay(pbGetTrainerVictoryME(@battle.opponent)) end end