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, 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, 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) id_number = GameData::Move.get(moveID).id_number noFlip = false if (idxUser&1)==0 # On player's side anim = move2anim[0][id_number] else # On opposing side anim = move2anim[1][id_number] noFlip = true if anim anim = move2anim[0][id_number] 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 = GameData::Move.get(moveID) target_data = GameData::Target.get(moveData.target) moveType = moveData.type moveKind = moveData.category moveKind += 3 if target_data.num_targets > 1 || target_data.affects_foe_side moveKind += 3 if moveKind == 2 && target_data.num_targets > 0 # [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] } if typeDefaultAnim[moveType] anims = typeDefaultAnim[moveType] if GameData::Move.exists?(anims[moveKind]) anim = pbFindMoveAnimDetails(move2anim, anims[moveKind], idxUser) end if !anim && moveKind >= 3 && GameData::Move.exists?(anims[moveKind - 3]) anim = pbFindMoveAnimDetails(move2anim, anims[moveKind - 3], idxUser) end if !anim && GameData::Move.exists?(anims[2]) anim = pbFindMoveAnimDetails(move2anim, anims[2], idxUser) end end return anim if anim # Default animation for the move's type not found, use Tackle's animation if GameData::Move.exists?(:TACKLE) return pbFindMoveAnimDetails(move2anim, :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) 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