class PokeBattle_Scene #============================================================================= # Animates the battle intro #============================================================================= def pbBattleIntroAnimation # Make everything appear introAnim = BattleIntroAnimation.new(@sprites,@viewport,@battle) loop do introAnim.update pbUpdate break if introAnim.animDone? end introAnim.dispose # Post-appearance activities # Trainer battle: get ready to show the party lineups (they are brought # on-screen by a separate animation) if @battle.trainerBattle? # NOTE: Here is where you'd make trainer sprites animate if they had an # entrance animation. Be sure to set it up like a Pokémon entrance # animation, i.e. add them to @animations so that they can play out # while party lineups appear and messages show. pbShowPartyLineup(0,true) pbShowPartyLineup(1,true) return end # Wild battle: play wild Pokémon's intro animations (including cry), show # data box(es), return the wild Pokémon's sprite(s) to normal colour, show # shiny animation(s) # Set up data box animation for i in 0...@battle.sideSizes[1] idxBattler = 2*i+1 next if !@battle.battlers[idxBattler] dataBoxAnim = DataBoxAppearAnimation.new(@sprites,@viewport,idxBattler) @animations.push(dataBoxAnim) end # Set up wild Pokémon returning to normal colour and playing intro # animations (including cry) @animations.push(BattleIntroAnimation2.new(@sprites,@viewport,@battle.sideSizes[1])) # Play all the animations while inPartyAnimation?; pbUpdate; end # Show shiny animation for wild Pokémon if @battle.showAnims for i in 0...@battle.sideSizes[1] idxBattler = 2*i+1 next if !@battle.battlers[idxBattler] || !@battle.battlers[idxBattler].shiny? pbCommonAnimation("Shiny",@battle.battlers[idxBattler]) end end end #============================================================================= # Animates a party lineup appearing for the given side #============================================================================= def pbShowPartyLineup(side,fullAnim=false) @animations.push(LineupAppearAnimation.new(@sprites,@viewport, side,@battle.pbParty(side),@battle.pbPartyStarts(side),fullAnim)) if !fullAnim while inPartyAnimation?; pbUpdate; end end end #============================================================================= # Animates an opposing trainer sliding in from off-screen. Will animate a # previous trainer that is already on-screen slide off first. Used at the end # of battle. #============================================================================= def pbShowOpponent(idxTrainer) # Set up trainer appearing animation appearAnim = TrainerAppearAnimation.new(@sprites,@viewport,idxTrainer) @animations.push(appearAnim) # Play the animation while inPartyAnimation?; pbUpdate; end end #============================================================================= # Animates a trainer's sprite and party lineup hiding (if they are visible). # Animates a Pokémon being sent out into battle, then plays the shiny # animation for it if relevant. # sendOuts is an array; each element is itself an array: [idxBattler,pkmn] #============================================================================= def pbSendOutBattlers(sendOuts,startBattle=false) return if sendOuts.length==0 # If party balls are still appearing, wait for them to finish showing up, as # the FadeAnimation will make them disappear. while inPartyAnimation?; pbUpdate; end @briefMessage = false # Make all trainers and party lineups disappear (player-side trainers may # animate throwing a Poké Ball) if @battle.opposes?(sendOuts[0][0]) fadeAnim = TrainerFadeAnimation.new(@sprites,@viewport,startBattle) else fadeAnim = PlayerFadeAnimation.new(@sprites,@viewport,startBattle) end # For each battler being sent out, set the battler's sprite and create two # animations (the Poké Ball moving and battler appearing from it, and its # data box appearing) sendOutAnims = [] sendOuts.each_with_index do |b,i| pkmn = @battle.battlers[b[0]].effects[PBEffects::Illusion] || b[1] pbChangePokemon(b[0],pkmn) pbRefresh if @battle.opposes?(b[0]) sendOutAnim = PokeballTrainerSendOutAnimation.new(@sprites,@viewport, @battle.pbGetOwnerIndexFromBattlerIndex(b[0])+1, @battle.battlers[b[0]],startBattle,i) else sendOutAnim = PokeballPlayerSendOutAnimation.new(@sprites,@viewport, @battle.pbGetOwnerIndexFromBattlerIndex(b[0])+1, @battle.battlers[b[0]],startBattle,i) end dataBoxAnim = DataBoxAppearAnimation.new(@sprites,@viewport,b[0]) sendOutAnims.push([sendOutAnim,dataBoxAnim,false]) end # Play all animations loop do fadeAnim.update sendOutAnims.each do |a| next if a[2] a[0].update a[1].update if a[0].animDone? a[2] = true if a[1].animDone? end pbUpdate if !inPartyAnimation? break if !sendOutAnims.any? { |a| !a[2] } end end fadeAnim.dispose sendOutAnims.each { |a| a[0].dispose; a[1].dispose } # Play shininess animations for shiny Pokémon sendOuts.each do |b| next if !@battle.showAnims || !@battle.battlers[b[0]].shiny? pbCommonAnimation("Shiny",@battle.battlers[b[0]]) end end #============================================================================= # Animates a Pokémon being recalled into its Poké Ball and its data box hiding #============================================================================= def pbRecall(idxBattler) @briefMessage = false # Recall animation recallAnim = BattlerRecallAnimation.new(@sprites,@viewport,idxBattler) loop do recallAnim.update if recallAnim pbUpdate break if recallAnim.animDone? end recallAnim.dispose # Data box disappear animation dataBoxAnim = DataBoxDisappearAnimation.new(@sprites,@viewport,idxBattler) loop do dataBoxAnim.update pbUpdate break if dataBoxAnim.animDone? end dataBoxAnim.dispose end #============================================================================= # Ability splash bar animations #============================================================================= def pbShowAbilitySplash(battler) return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH side = battler.index%2 pbHideAbilitySplash(battler) if @sprites["abilityBar_#{side}"].visible @sprites["abilityBar_#{side}"].battler = battler abilitySplashAnim = AbilitySplashAppearAnimation.new(@sprites,@viewport,side) loop do abilitySplashAnim.update pbUpdate break if abilitySplashAnim.animDone? end abilitySplashAnim.dispose end def pbHideAbilitySplash(battler) return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH side = battler.index%2 return if !@sprites["abilityBar_#{side}"].visible abilitySplashAnim = AbilitySplashDisappearAnimation.new(@sprites,@viewport,side) loop do abilitySplashAnim.update pbUpdate break if abilitySplashAnim.animDone? end abilitySplashAnim.dispose end def pbReplaceAbilitySplash(battler) return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH pbShowAbilitySplash(battler) end #============================================================================= # HP change animations #============================================================================= # Shows a HP-changing common animation and animates a data box's HP bar. # Called by def pbReduceHP, def pbRecoverHP. def pbHPChanged(battler,oldHP,showAnim=false) @briefMessage = false if battler.hp>oldHP pbCommonAnimation("HealthUp",battler) if showAnim && @battle.showAnims elsif battler.hp+{1}\r\nAttack+{2}\r\nDefense+{3}\r\nSp. Atk+{4}\r\nSp. Def+{5}\r\nSpeed+{6}", pkmn.totalhp-oldTotalHP,pkmn.attack-oldAttack,pkmn.defense-oldDefense, pkmn.spatk-oldSpAtk,pkmn.spdef-oldSpDef,pkmn.speed-oldSpeed)) pbTopRightWindow( _INTL("Max. HP{1}\r\nAttack{2}\r\nDefense{3}\r\nSp. Atk{4}\r\nSp. Def{5}\r\nSpeed{6}", pkmn.totalhp,pkmn.attack,pkmn.defense,pkmn.spatk,pkmn.spdef,pkmn.speed)) end #============================================================================= # Animates a Pokémon fainting #============================================================================= def pbFaintBattler(battler) @briefMessage = false # Pokémon plays cry and drops down, data box disappears faintAnim = BattlerFaintAnimation.new(@sprites,@viewport,battler.index,@battle) dataBoxAnim = DataBoxDisappearAnimation.new(@sprites,@viewport,battler.index) loop do faintAnim.update dataBoxAnim.update pbUpdate break if faintAnim.animDone? && dataBoxAnim.animDone? end faintAnim.dispose dataBoxAnim.dispose end #============================================================================= # Animates throwing a Poké Ball at a Pokémon in an attempt to catch it #============================================================================= def pbThrow(ball,shakes,critical,targetBattler,showPlayer=false) @briefMessage = false captureAnim = PokeballThrowCaptureAnimation.new(@sprites,@viewport, pbGetBallType(ball),shakes,critical,@battle.battlers[targetBattler],showPlayer) loop do captureAnim.update pbUpdate break if captureAnim.animDone? && !inPartyAnimation? end captureAnim.dispose end def pbThrowSuccess return if @battle.opponent @briefMessage = false pbMEPlay(pbGetWildCaptureME) i = 0 loop do pbUpdate break if i>=Graphics.frame_rate*3.5 # 3.5 seconds i += 1 end pbMEStop end def pbHideCaptureBall(idxBattler) # NOTE: It's not really worth writing a whole PokeBattle_Animation class for # making the capture ball fade out. ball = @sprites["captureBall"] return if !ball # Data box disappear animation dataBoxAnim = DataBoxDisappearAnimation.new(@sprites,@viewport,idxBattler) loop do dataBoxAnim.update ball.opacity -= 12*20/Graphics.frame_rate if ball.opacity>0 pbUpdate break if dataBoxAnim.animDone? && ball.opacity<=0 end dataBoxAnim.dispose end def pbThrowAndDeflect(ball,idxBattler) @briefMessage = false throwAnim = PokeballThrowDeflectAnimation.new(@sprites,@viewport, pbGetBallType(ball),@battle.battlers[idxBattler]) loop do throwAnim.update pbUpdate break if throwAnim.animDone? end throwAnim.dispose end #============================================================================= # Hides all battler shadows before yielding to a move animation, and then # restores the shadows afterwards #============================================================================= def pbSaveShadows # Remember which shadows were visible shadows = Array.new(@battle.battlers.length) do |i| shadow = @sprites["shadow_#{i}"] ret = (shadow) ? shadow.visible : false shadow.visible = false if shadow next ret end # Yield to other code, i.e. playing an animation yield # Restore shadow visibility for i in 0...@battle.battlers.length shadow = @sprites["shadow_#{i}"] shadow.visible = shadows[i] if shadow end end #============================================================================= # Loads a move/common animation #============================================================================= # Returns the animation ID to use for a given move/user. Returns nil if that # move has no animations defined for it. def pbFindMoveAnimDetails(move2anim,moveID,idxUser,hitNum=0) noFlip = false if (idxUser&1)==0 # On player's side anim = move2anim[0][moveID] else # On opposing side anim = move2anim[1][moveID] noFlip = true if anim anim = move2anim[0][moveID] if !anim end return [anim+hitNum,noFlip] if anim return nil end # Returns the animation ID to use for a given move. If the move has no # animations, tries to use a default move animation depending on the move's # type. If that default move animation doesn't exist, trues to use Tackle's # move animation. Returns nil if it can't find any of these animations to use. def pbFindMoveAnimation(moveID,idxUser,hitNum) begin move2anim = pbLoadMoveToAnim # Find actual animation requested (an opponent using the animation first # looks for an OppMove version then a Move version) anim = pbFindMoveAnimDetails(move2anim,moveID,idxUser,hitNum) return anim if anim # Actual animation not found, get the default animation for the move's type moveData = pbGetMoveData(moveID) moveType = moveData[MOVE_TYPE] moveKind = moveData[MOVE_CATEGORY] moveKind += 3 if PBTargets.multipleTargets?(moveData[MOVE_TARGET]) || PBTargets.targetsFoeSide?(moveData[MOVE_TARGET]) moveKind += 3 if moveKind==2 && moveData[MOVE_TARGET]!=PBTargets::User && moveData[MOVE_TARGET]!=PBTargets::UserSide # [one target physical, one target special, user status, # multiple targets physical, multiple targets special, non-user status] typeDefaultAnim = { :NORMAL => [:TACKLE,:SONICBOOM,:DEFENSECURL,:EXPLOSION,:SWIFT,:TAILWHIP], :FIGHTING => [:MACHPUNCH,:AURASPHERE,:DETECT,nil,nil,nil], :FLYING => [:WINGATTACK,:GUST,:ROOST,nil,:AIRCUTTER,:FEATHERDANCE], :POISON => [:POISONSTING,:SLUDGE,:ACIDARMOR,nil,:ACID,:POISONPOWDER], :GROUND => [:SANDTOMB,:MUDSLAP,nil,:EARTHQUAKE,:EARTHPOWER,:MUDSPORT], :ROCK => [:ROCKTHROW,:POWERGEM,:ROCKPOLISH,:ROCKSLIDE,nil,:SANDSTORM], :BUG => [:TWINEEDLE,:BUGBUZZ,:QUIVERDANCE,nil,:STRUGGLEBUG,:STRINGSHOT], :GHOST => [:LICK,:SHADOWBALL,:GRUDGE,nil,nil,:CONFUSERAY], :STEEL => [:IRONHEAD,:MIRRORSHOT,:IRONDEFENSE,nil,nil,:METALSOUND], :FIRE => [:FIREPUNCH,:EMBER,:SUNNYDAY,nil,:INCINERATE,:WILLOWISP], :WATER => [:CRABHAMMER,:WATERGUN,:AQUARING,nil,:SURF,:WATERSPORT], :GRASS => [:VINEWHIP,:MEGADRAIN,:COTTONGUARD,:RAZORLEAF,nil,:SPORE], :ELECTRIC => [:THUNDERPUNCH,:THUNDERSHOCK,:CHARGE,nil,:DISCHARGE,:THUNDERWAVE], :PSYCHIC => [:ZENHEADBUTT,:CONFUSION,:CALMMIND,nil,:SYNCHRONOISE,:MIRACLEEYE], :ICE => [:ICEPUNCH,:ICEBEAM,:MIST,nil,:POWDERSNOW,:HAIL], :DRAGON => [:DRAGONCLAW,:DRAGONRAGE,:DRAGONDANCE,nil,:TWISTER,nil], :DARK => [:PURSUIT,:DARKPULSE,:HONECLAWS,nil,:SNARL,:EMBARGO], :FAIRY => [:TACKLE,:FAIRYWIND,:MOONLIGHT,nil,:SWIFT,:SWEETKISS] } typeDefaultAnim.each do |type, anims| next if !isConst?(moveType,PBTypes,type) if anims[moveKind] && hasConst?(PBMoves,anims[moveKind]) anim = pbFindMoveAnimDetails(move2anim,getConst(PBMoves,anims[moveKind]),idxUser) end break if anim if moveKind>=3 && anims[moveKind-3] && hasConst?(PBMoves,anims[moveKind-3]) anim = pbFindMoveAnimDetails(move2anim,getConst(PBMoves,anims[moveKind-3]),idxUser) end break if anim if anims[2] && hasConst?(PBMoves,anims[2]) anim = pbFindMoveAnimDetails(move2anim,getConst(PBMoves,anims[2]),idxUser) end break end return anim if anim # Default animation for the move's type not found, use Tackle's animation if hasConst?(PBMoves,:TACKLE) return pbFindMoveAnimDetails(move2anim,getConst(PBMoves,:TACKLE),idxUser) end rescue end return nil end #============================================================================= # Plays a move/common animation #============================================================================= # Plays a move animation. def pbAnimation(moveID,user,targets,hitNum=0) animID = pbFindMoveAnimation(moveID,user.index,hitNum) return if !animID anim = animID[0] target = (targets && targets.is_a?(Array)) ? targets[0] : targets animations = pbLoadBattleAnimations return if !animations pbSaveShadows { if animID[1] # On opposing side and using OppMove animation pbAnimationCore(animations[anim],target,user,true) else # On player's side, and/or using Move animation pbAnimationCore(animations[anim],user,target) end } end # Plays a common animation. def pbCommonAnimation(animName,user=nil,target=nil,hitNum=0) return if !animName || animName=="" target = target[0] if target && target.is_a?(Array) animations = pbLoadBattleAnimations return if !animations animations.each do |a| next if !a || a.name!="Common:"+animName pbAnimationCore(a,user,(target!=nil) ? target : user) return end end def pbAnimationCore(animation,user,target,oppMove=false) return if !animation @briefMessage = false userSprite = (user) ? @sprites["pokemon_#{user.index}"] : nil targetSprite = (target) ? @sprites["pokemon_#{target.index}"] : nil # Remember the original positions of Pokémon sprites oldUserX = (userSprite) ? userSprite.x : 0 oldUserY = (userSprite) ? userSprite.y : 0 oldTargetX = (targetSprite) ? targetSprite.x : oldUserX oldTargetY = (targetSprite) ? targetSprite.y : oldUserY # Create the animation player animPlayer = PBAnimationPlayerX.new(animation,user,target,self,oppMove) # Apply a transformation to the animation based on where the user and target # actually are. Get the centres of each sprite. userHeight = (userSprite && userSprite.bitmap && !userSprite.bitmap.disposed?) ? userSprite.bitmap.height : 128 if targetSprite targetHeight = (targetSprite.bitmap && !targetSprite.bitmap.disposed?) ? targetSprite.bitmap.height : 128 else targetHeight = userHeight end animPlayer.setLineTransform( PokeBattle_SceneConstants::FOCUSUSER_X,PokeBattle_SceneConstants::FOCUSUSER_Y, PokeBattle_SceneConstants::FOCUSTARGET_X,PokeBattle_SceneConstants::FOCUSTARGET_Y, oldUserX,oldUserY-userHeight/2, oldTargetX,oldTargetY-targetHeight/2) # Play the animation animPlayer.start loop do animPlayer.update pbUpdate break if animPlayer.animDone? end animPlayer.dispose # Return Pokémon sprites to their original positions if userSprite userSprite.x = oldUserX userSprite.y = oldUserY userSprite.pbSetOrigin end if targetSprite targetSprite.x = oldTargetX targetSprite.y = oldTargetY targetSprite.pbSetOrigin end end end