diff --git a/Data/Scripts/902_Anim GameData/001_Animation.rb b/Data/Scripts/902_Anim GameData/001_Animation.rb index f3dcd6612..d73daed83 100644 --- a/Data/Scripts/902_Anim GameData/001_Animation.rb +++ b/Data/Scripts/902_Anim GameData/001_Animation.rb @@ -19,6 +19,7 @@ module GameData # :user_and_target, plus there's :foreground in PARTICLE_DEFAULT_VALUES # below. # TODO: Add :user_ground, :target_ground? + # TODO: Add :opposing_side_foreground and :opposing_side_background? FOCUS_TYPES = { "Foreground" => :foreground, "Midground" => :midground, diff --git a/Data/Scripts/904_Anim Editor/001_AnimationEditor.rb b/Data/Scripts/904_Anim Editor/001_AnimationEditor.rb index 019af7b48..43abb48a7 100644 --- a/Data/Scripts/904_Anim Editor/001_AnimationEditor.rb +++ b/Data/Scripts/904_Anim Editor/001_AnimationEditor.rb @@ -429,13 +429,21 @@ class AnimationEditor # Set up fake battlers for the animation player user_battler = nil if !@anim[:no_user] - user_battler = AnimationPlayer::FakeBattler.new(@settings[:user_index], @settings[:user_sprite_name]) + idx_user = @settings[:user_index] + if @settings[:user_opposes] || [:opp_move, :opp_common].include?(@anim[:type]) + idx_user += 1 + end + user_battler = AnimationPlayer::FakeBattler.new(idx_user, @settings[:user_sprite_name]) end target_battlers = nil if !@anim[:no_target] target_battlers = [] @settings[:target_indices].each do |idx| - target_battlers.push(AnimationPlayer::FakeBattler.new(idx, @settings[:target_sprite_name])) + idx_target = idx + if @settings[:user_opposes] || [:opp_move, :opp_common].include?(@anim[:type]) + idx_target += (idx_target.even?) ? 1 : -1 + end + target_battlers.push(AnimationPlayer::FakeBattler.new(idx_target, @settings[:target_sprite_name])) end end # Create animation player diff --git a/Data/Scripts/904_Anim Editor/Anim Editor elements/001_Canvas.rb b/Data/Scripts/904_Anim Editor/Anim Editor elements/001_Canvas.rb index 7c3b50dcf..4dd3b9905 100644 --- a/Data/Scripts/904_Anim Editor/Anim Editor elements/001_Canvas.rb +++ b/Data/Scripts/904_Anim Editor/Anim Editor elements/001_Canvas.rb @@ -4,9 +4,11 @@ # -199 = side bases # -198 = battler shadows. # 0 +/-50 = background focus, foe side background. +# 500, 400, 300... = foe trainers. # 900, 800, 700... +/-50 = foe battlers. # 1000 +/-50 = foe side foreground, player side background. # 1100, 1200, 1300... +/-50 = player battlers. +# 1500, 1600, 1700... = player trainers. # 2000 +/-50 = player side foreground, foreground focus. # 9999+ = UI #=============================================================================== @@ -201,26 +203,34 @@ class AnimationEditor::Canvas < Sprite # their x/y/z values so the animation player knows where they start idx = user_index particle_idx = @anim[:particles].index { |particle| particle[:name] == "User" } - @sprites["pokemon_#{idx}"] = @battler_sprites[idx] - @battler_sprites[idx].x = @user_coords[0] - @battler_sprites[idx].y = @user_coords[1] - offset_xy = AnimationPlayer::Helper.get_xy_offset(@anim[:particles][particle_idx], @battler_sprites[idx]) - @battler_sprites[idx].x += offset_xy[0] - @battler_sprites[idx].y += offset_xy[1] - focus_z = AnimationPlayer::Helper.get_z_focus(@anim[:particles][particle_idx], idx, idx) - AnimationPlayer::Helper.apply_z_focus_to_sprite(@battler_sprites[idx], 0, focus_z) - @battler_sprites[idx].z = 0 - particle_idx = @anim[:particles].index { |particle| particle[:name] == "Target" } - target_indices.each do |idx| + if particle_idx @sprites["pokemon_#{idx}"] = @battler_sprites[idx] - @battler_sprites[idx].x = @target_coords[idx][0] - @battler_sprites[idx].y = @target_coords[idx][1] + @battler_sprites[idx].x = @user_coords[0] + @battler_sprites[idx].y = @user_coords[1] offset_xy = AnimationPlayer::Helper.get_xy_offset(@anim[:particles][particle_idx], @battler_sprites[idx]) + focus_z = AnimationPlayer::Helper.get_z_focus(@anim[:particles][particle_idx], idx, idx) @battler_sprites[idx].x += offset_xy[0] @battler_sprites[idx].y += offset_xy[1] - focus_z = AnimationPlayer::Helper.get_z_focus(@anim[:particles][particle_idx], idx, idx) AnimationPlayer::Helper.apply_z_focus_to_sprite(@battler_sprites[idx], 0, focus_z) end + particle_idx = @anim[:particles].index { |particle| particle[:name] == "Target" } + if particle_idx + target_indices.each do |idx| + @sprites["pokemon_#{idx}"] = @battler_sprites[idx] + @battler_sprites[idx].x = @target_coords[idx][0] + @battler_sprites[idx].y = @target_coords[idx][1] + if particle_idx + offset_xy = AnimationPlayer::Helper.get_xy_offset(@anim[:particles][particle_idx], @battler_sprites[idx]) + focus_z = AnimationPlayer::Helper.get_z_focus(@anim[:particles][particle_idx], idx, idx) + else + offset_xy = [0, @battler_sprites[idx].bitmap.height / 2] + focus_z = 1000 + ((100 * ((idx / 2) + 1)) * (idx.even? ? 1 : -1)) + end + @battler_sprites[idx].x += offset_xy[0] + @battler_sprites[idx].y += offset_xy[1] + AnimationPlayer::Helper.apply_z_focus_to_sprite(@battler_sprites[idx], 0, focus_z) + end + end # TODO: Also add background/bases and so on. hide_all_sprites @sel_frame_sprite.visible = false diff --git a/Data/Scripts/904_Anim Editor/Anim Editor elements/002_PlayControls.rb b/Data/Scripts/904_Anim Editor/Anim Editor elements/002_PlayControls.rb index ccd7358b4..5f214a495 100644 --- a/Data/Scripts/904_Anim Editor/Anim Editor elements/002_PlayControls.rb +++ b/Data/Scripts/904_Anim Editor/Anim Editor elements/002_PlayControls.rb @@ -57,7 +57,7 @@ class AnimationEditor::PlayControls < UIControls::ControlsContainer @controls.push([:unloop, unloop_button]) # Slowdown label duration_label = UIControls::Label.new(200, ROW_HEIGHT, self.viewport, _INTL("Slowdown factor")) - duration_label.x = SLOWDOWN_BUTTON_X + (SLOWDOWN_FACTORS.length * (SLOWDOWN_BUTTON_WIDTH - SLOWDOWN_BUTTON_SPACING) / 2) + duration_label.x = SLOWDOWN_BUTTON_X + (SLOWDOWN_FACTORS.length * (SLOWDOWN_BUTTON_WIDTH + SLOWDOWN_BUTTON_SPACING) / 2) duration_label.x -= (duration_label.text_width / 2) + 5 duration_label.y = SLOWDOWN_LABEL_Y @controls.push([:slowdown_label, duration_label]) @@ -65,7 +65,7 @@ class AnimationEditor::PlayControls < UIControls::ControlsContainer SLOWDOWN_FACTORS.each_with_index do |value, i| button = UIControls::Button.new(SLOWDOWN_BUTTON_WIDTH, ROW_HEIGHT, self.viewport, value.to_s) button.set_fixed_size - button.x = SLOWDOWN_BUTTON_X + ((SLOWDOWN_BUTTON_WIDTH - SLOWDOWN_BUTTON_SPACING) * i) + button.x = SLOWDOWN_BUTTON_X + ((SLOWDOWN_BUTTON_WIDTH + SLOWDOWN_BUTTON_SPACING) * i) button.y = SLOWDOWN_BUTTON_Y button.set_interactive_rects button.set_highlighted if value == @slowdown diff --git a/Data/Scripts/905_Anim player/001_Anim player.rb b/Data/Scripts/905_Anim player/001_Anim player.rb index ca0858675..a95a78d10 100644 --- a/Data/Scripts/905_Anim player/001_Anim player.rb +++ b/Data/Scripts/905_Anim player/001_Anim player.rb @@ -101,15 +101,15 @@ class AnimationPlayer particle_sprite.sprite = sprite if sprite # Set sprite's graphic and ox/oy if sprite - AnimationPlayer::Helper.set_bitmap_and_origin(particle, sprite, @user.index, target_idx, - @battler_sprites[@user.index], @battler_sprites[target_idx]) + AnimationPlayer::Helper.set_bitmap_and_origin(particle, sprite, @user&.index, target_idx, + @battler_sprites[@user&.index || -1], @battler_sprites[target_idx]) end # Calculate x/y/z focus values and additional x/y modifier and pass them all # to particle_sprite - focus_xy = AnimationPlayer::Helper.get_xy_focus(particle, @user.index, target_idx, + focus_xy = AnimationPlayer::Helper.get_xy_focus(particle, @user&.index, target_idx, @user_coords, @target_coords[target_idx]) offset_xy = AnimationPlayer::Helper.get_xy_offset(particle, sprite) - focus_z = AnimationPlayer::Helper.get_z_focus(particle, @user.index, target_idx) + focus_z = AnimationPlayer::Helper.get_z_focus(particle, @user&.index, target_idx) particle_sprite.focus_xy = focus_xy particle_sprite.offset_xy = offset_xy particle_sprite.focus_z = focus_z diff --git a/Data/Scripts/905_Anim player/011_Battle z modifiers.rb b/Data/Scripts/905_Anim player/011_Battle z modifiers.rb index e10886741..f82bc946e 100644 --- a/Data/Scripts/905_Anim player/011_Battle z modifiers.rb +++ b/Data/Scripts/905_Anim player/011_Battle z modifiers.rb @@ -13,6 +13,7 @@ class Battle::Scene @sprites["base_#{side}"].z = -199 end @sprites["cmdBar_bg"].z += 9999 + @sprites["messageBox"].z += 9999 @sprites["messageWindow"].z += 9999 @sprites["commandWindow"].z += 9999 @@ -29,6 +30,16 @@ class Battle::Scene @battle.battlers.each_with_index do |b, i| @sprites["dataBox_#{i}"].z += 9999 if b end + + @battle.player.each_with_index do |p, i| + @sprites["player_#{i + 1}"].z = 1500 + (i * 100) + end + if @battle.trainerBattle? + @battle.opponent.each_with_index do |p, i| + @sprites["trainer_#{i + 1}"].z = 500 - (i * 100) + end + end + end end @@ -69,3 +80,512 @@ class Battle::Scene::BattlerShadowSprite < RPG::Sprite @pkmn.species_data.apply_metrics_to_sprite(self, @index, true) end end + +#=============================================================================== +# Mixin module for certain hardcoded battle animations that involve Poké Balls. +#=============================================================================== +module Battle::Scene::Animation::BallAnimationMixin + # The regular Poké Ball burst animation, for when a Pokémon appears from a + # Poké Ball. + def ballBurst(delay, ball, ballX, ballY, poke_ball) + num_particles = 15 + num_rays = 10 + glare_fade_duration = 8 # Lifetimes/durations are in 20ths of a second + particle_lifetime = 15 + particle_fade_duration = 8 + ray_lifetime = 13 + ray_fade_duration = 5 + ray_min_radius = 24 # How far out from the center a ray starts + cherish_ball_ray_tones = [Tone.new(-104, -144, -8), # Indigo + Tone.new(-64, -144, -24), # Purple + Tone.new(-8, -144, -64), # Pink + Tone.new(-8, -48, -152), # Orange + Tone.new(-8, -32, -160)] # Yellow + # Get array of things that vary for each kind of Poké Ball + variances = BALL_BURST_VARIANCES[poke_ball] || BALL_BURST_VARIANCES[:POKEBALL] + # Set up glare particles + glare1 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[11]}", PictureOrigin::CENTER) + glare2 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[8]}", PictureOrigin::CENTER) + [glare1, glare2].each_with_index do |particle, num| + particle.setZ(0, 5105 + num) + particle.setZoom(0, 0) + particle.setTone(0, variances[12 - (3 * num)]) + particle.setVisible(0, false) + end + [glare1, glare2].each_with_index do |particle, num| + particle.moveTone(delay + glare_fade_duration + 3, glare_fade_duration / 2, variances[13 - (3 * num)]) + end + # Animate glare particles + [glare1, glare2].each { |p| p.setVisible(delay, true) } + if poke_ball == :MASTERBALL + glare1.moveAngle(delay, 19, -135) + glare1.moveZoom(delay, glare_fade_duration, 250) + elsif poke_ball == :DUSKBALL + glare1.moveAngle(delay, 19, -270) + elsif ["whirl"].include?(variances[11]) + glare1.moveZoom(delay, glare_fade_duration, 200) + else + glare1.moveZoom(delay, glare_fade_duration, (["dazzle", "ring3", "web"].include?(variances[11])) ? 100 : 250) + end + glare1.moveOpacity(delay + glare_fade_duration + 3, glare_fade_duration, 0) + if poke_ball == :MASTERBALL + glare2.moveAngle(delay, 19, -135) + glare2.moveZoom(delay, glare_fade_duration, 200) + else + glare2.moveZoom(delay, glare_fade_duration, (["dazzle", "ring3", "web"].include?(variances[8])) ? 125 : 200) + end + glare2.moveOpacity(delay + glare_fade_duration + 3, glare_fade_duration - 2, 0) + [glare1, glare2].each { |p| p.setVisible(delay + 19, false) } + # Rays + num_rays.times do |i| + # Set up ray + angle = rand(360) + radian = (angle + 90) * Math::PI / 180 + start_zoom = rand(50...100) + ray = addNewSprite(ballX + (ray_min_radius * Math.cos(radian)), + ballY - (ray_min_radius * Math.sin(radian)), + "Graphics/Battle animations/ballBurst_ray", PictureOrigin::BOTTOM) + ray.setZ(0, 5100) + ray.setZoomXY(0, 200, start_zoom) + ray.setTone(0, variances[0]) if poke_ball != :CHERISHBALL + ray.setOpacity(0, 0) + ray.setVisible(0, false) + ray.setAngle(0, angle) + # Animate ray + start = delay + (i / 2) + ray.setVisible(start, true) + ray.moveZoomXY(start, ray_lifetime, 200, start_zoom * 6) + ray.moveOpacity(start, 2, 255) # Quickly fade in + ray.moveOpacity(start + ray_lifetime - ray_fade_duration, ray_fade_duration, 0) # Fade out + if poke_ball == :CHERISHBALL + ray_lifetime.times do |frame| + ray.setTone(start + frame, cherish_ball_ray_tones[frame % cherish_ball_ray_tones.length]) + end + else + ray.moveTone(start + ray_lifetime - ray_fade_duration, ray_fade_duration, variances[1]) + end + ray.setVisible(start + ray_lifetime, false) + end + # Particles + num_particles.times do |i| + # Set up particles + particle1 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[5]}", PictureOrigin::CENTER) + particle2 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[2]}", PictureOrigin::CENTER) + [particle1, particle2].each_with_index do |particle, num| + particle.setZ(0, 5110 + num) + particle.setZoom(0, (80 - (num * 20)) / (["ring2"].include?(variances[5 - (3 * num)]) ? 2 : 1)) + particle.setTone(0, variances[6 - (3 * num)]) + particle.setVisible(0, false) + end + # Animate particles + start = delay + (i / 4) + max_radius = rand(256...384) + angle = rand(360) + radian = angle * Math::PI / 180 + [particle1, particle2].each_with_index do |particle, num| + particle.setVisible(start, true) + particle.moveDelta(start, particle_lifetime, max_radius * Math.cos(radian), max_radius * Math.sin(radian)) + particle.moveZoom(start, particle_lifetime, 10) + particle.moveTone(start + particle_lifetime - particle_fade_duration, + particle_fade_duration / 2, variances[7 - (3 * num)]) + particle.moveOpacity(start + particle_lifetime - particle_fade_duration, + particle_fade_duration, + 0) # Fade out at end + particle.setVisible(start + particle_lifetime, false) + end + end + end + + # The Poké Ball burst animation used when absorbing a wild Pokémon during a + # capture attempt. + def ballBurstCapture(delay, ball, ballX, ballY, poke_ball) + particle_duration = 10 + ring_duration = 5 + num_particles = 9 + base_angle = 270 + base_radius = (poke_ball == :MASTERBALL) ? 192 : 144 # How far out from the Poké Ball the particles go + # Get array of things that vary for each kind of Poké Ball + variances = BALL_BURST_CAPTURE_VARIANCES[poke_ball] || BALL_BURST_CAPTURE_VARIANCES[:POKEBALL] + # Set up glare particles + glare1 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[6]}", PictureOrigin::CENTER) + glare2 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[3]}", PictureOrigin::CENTER) + glare3 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[0]}", PictureOrigin::CENTER) + [glare1, glare2, glare3].each_with_index do |particle, num| + particle.setZ(0, 5100 + num) + particle.setZoom(0, 0) + particle.setTone(0, variances[7 - (3 * num)]) + particle.setVisible(0, false) + end + glare2.setOpacity(0, 160) + glare3.setOpacity(0, 160) if poke_ball != :DUSKBALL + # Animate glare particles + [glare1, glare2, glare3].each { |p| p.setVisible(delay, true) } + case poke_ball + when :MASTERBALL + glare1.moveZoom(delay, particle_duration, 1200) + when :DUSKBALL + glare1.moveZoom(delay, particle_duration, 350) + else + glare1.moveZoom(delay, particle_duration, 600) + end + glare1.moveOpacity(delay + (particle_duration / 2), particle_duration / 2, 0) + [glare1, glare2, glare3].each_with_index do |particle, num| + particle.moveTone(delay, particle_duration, variances[8 - (3 * num)]) + end + if poke_ball == :DUSKBALL + glare2.moveZoom(delay, particle_duration, 350) + glare3.moveZoom(delay, particle_duration, 500) + [glare2, glare3].each_with_index do |particle, num| + particle.moveOpacity(delay + (particle_duration / 2), particle_duration / 2, 0) + end + else + glare2.moveZoom(delay, particle_duration, (poke_ball == :MASTERBALL) ? 400 : 250) + glare2.moveOpacity(delay + (particle_duration / 2), particle_duration / 3, 0) + glare3.moveZoom(delay, particle_duration, (poke_ball == :MASTERBALL) ? 800 : 500) + glare3.moveOpacity(delay + (particle_duration / 2), particle_duration / 3, 0) + end + [glare1, glare2, glare3].each { |p| p.setVisible(delay + particle_duration, false) } + # Burst particles + num_particles.times do |i| + # Set up particle that keeps moving out + particle1 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_particle", PictureOrigin::CENTER) + particle1.setZ(0, 5105) + particle1.setZoom(0, 150) + particle1.setOpacity(0, 160) + particle1.setVisible(0, false) + # Set up particles that curve back in + particle2 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[12]}", PictureOrigin::CENTER) + particle3 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_#{variances[9]}", PictureOrigin::CENTER) + [particle2, particle3].each_with_index do |particle, num| + particle.setZ(0, 5110 + num) + particle.setZoom(0, (poke_ball == :NESTBALL) ? 50 : 0) + particle.setTone(0, variances[13 - (3 * num)]) + particle.setVisible(0, false) + particle.setAngle(0, rand(360)) if poke_ball == :PREMIERBALL + end + particle3.setOpacity(0, 128) if poke_ball == :DIVEBALL + # Particle animations + [particle1, particle2, particle3].each { |p| p.setVisible(delay, true) } + particle2.setVisible(delay, false) if poke_ball == :NESTBALL + start_angle = base_angle + (i * 360 / num_particles) + p1_x_offset = base_radius * Math.cos(start_angle * Math::PI / 180) + p1_y_offset = base_radius * Math.sin(start_angle * Math::PI / 180) + particle_duration.times do |j| + index = j + 1 + angle = start_angle + (index * (360 / num_particles) / particle_duration) + radian = angle * Math::PI / 180 + radius = base_radius + prop = index.to_f / (particle_duration / 2) + prop = 2 - prop if index > particle_duration / 2 + radius *= prop + particle1.moveXY(delay + j, 1, + ballX + (p1_x_offset * index * 2 / particle_duration), + ballY - (p1_y_offset * index * 2 / particle_duration)) + [particle2, particle3].each do |particle| + particle.moveXY(delay + j, 1, + ballX + (radius * Math.cos(radian)), + ballY - (radius * Math.sin(radian))) + end + end + particle1.moveZoom(delay, particle_duration, 0) + particle1.moveOpacity(delay, particle_duration, 0) + [particle2, particle3].each_with_index do |particle, num| + # Zoom in + if num == 0 && poke_ball == :MASTERBALL + particle.moveZoom(delay, particle_duration / 2, 225) + elsif num == 0 && poke_ball == :DIVEBALL + particle.moveZoom(delay, particle_duration / 2, 125) + elsif ["particle"].include?(variances[12 - (3 * num)]) + particle.moveZoom(delay, particle_duration / 2, (poke_ball == :PREMIERBALL) ? 50 : 80) + elsif ["ring3"].include?(variances[12 - (3 * num)]) + particle.moveZoom(delay, particle_duration / 2, 50) + elsif ["dazzle", "ring4", "diamond"].include?(variances[12 - (3 * num)]) + particle.moveZoom(delay, particle_duration / 2, 60) + else + particle.moveZoom(delay, particle_duration / 2, 100) + end + # Zoom out + if ["particle", "dazzle", "ring3", "ring4", "diamond"].include?(variances[12 - (3 * num)]) + particle.moveZoom(delay + (particle_duration * 2 / 3), particle_duration / 3, 10) + else + particle.moveZoom(delay + (particle_duration * 2 / 3), particle_duration / 3, 25) + end + # Rotate (for Premier Ball) + particle.moveAngle(delay, particle_duration, -180) if poke_ball == :PREMIERBALL + # Change tone, fade out + particle.moveTone(delay + (particle_duration / 3), (particle_duration.to_f / 3).ceil, variances[14 - (3 * num)]) + particle.moveOpacity(delay + particle_duration - 3, 3, 128) # Fade out at end + end + [particle1, particle2, particle3].each { |p| p.setVisible(delay + particle_duration, false) } + end + # Web sprite (for Net Ball) + if poke_ball == :NETBALL + web = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_web", PictureOrigin::CENTER) + web.setZ(0, 5123) + web.setZoom(0, 120) + web.setOpacity(0, 0) + web.setTone(0, Tone.new(-32, -32, -128)) + web.setVisible(0, false) + start = particle_duration / 2 + web.setVisible(delay + start, true) + web.moveOpacity(delay + start, 2, 160) + web_duration = particle_duration + ring_duration - (particle_duration / 2) + (web_duration / 4).times do |i| + web.moveZoom(delay + start + (i * 4), 2, 150) + web.moveZoom(delay + start + (i * 4) + 2, 2, 120) + end + now = start + ((web_duration / 4) * 4) + web.moveZoom(delay + now, particle_duration + ring_duration - now, 150) + web.moveOpacity(delay + particle_duration, ring_duration, 0) + web.setVisible(delay + particle_duration + ring_duration, false) + end + # Ring particle + ring = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_ring1", PictureOrigin::CENTER) + ring.setZ(0, 5110) + ring.setZoom(0, 0) + ring.setTone(0, variances[15]) + ring.setVisible(0, false) + # Ring particle animation + ring.setVisible(delay + particle_duration, true) + ring.moveZoom(delay + particle_duration - 2, ring_duration + 2, 125) # Start slightly early + ring.moveTone(delay + particle_duration, ring_duration, variances[16]) + ring.moveOpacity(delay + particle_duration, ring_duration, 0) + ring.setVisible(delay + particle_duration + ring_duration, false) + # Mark the end of the burst animation + ball.setDelta(delay + particle_duration + ring_duration, 0, 0) + end + + # The animation shown over a thrown Poké Ball when it has successfully caught + # a Pokémon. + def ballCaptureSuccess(ball, delay, ballX, ballY) + ball.setSE(delay, "Battle catch click") + ball.moveTone(delay, 4, Tone.new(-128, -128, -128)) # Ball goes darker + delay = ball.totalDuration + star_duration = 12 # In 20ths of a second + y_offsets = [[0, 74, 52], [0, 62, 28], [0, 74, 48]] + 3.times do |i| # Left, middle, right + # Set up particle + star = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_star", PictureOrigin::CENTER) + star.setZ(0, 5110) + star.setZoom(0, [50, 50, 33][i]) + start_angle = [0, 345, 15][i] + star.setAngle(0, start_angle) + star.setOpacity(0, 0) + star.setVisible(0, false) + # Particle animation + star.setVisible(delay, true) + y_pos = y_offsets[i] + star_duration.times do |j| + index = j + 1 + x = 72 * index / star_duration + proportion = index.to_f / star_duration + a = (2 * y_pos[2]) - (4 * y_pos[1]) + b = y_pos[2] - a + y = ((a * proportion) + b) * proportion + star.moveXY(delay + j, 1, ballX + ([-1, 0, 1][i] * x), ballY - y) + end + star.moveAngle(delay, star_duration, start_angle + [144, 0, 45][i]) if i.even? + star.moveOpacity(delay, 4, 255) # Fade in + star.moveTone(delay + 3, 3, Tone.new(0, 0, -96)) # Light yellow + star.moveTone(delay + 6, 3, Tone.new(0, 0, 0)) # White + star.moveOpacity(delay + 8, 4, 0) # Fade out + end + end + + # The Poké Ball burst animation used when recalling a Pokémon. In HGSS, this + # is the same for all types of Poké Ball except for the color that the battler + # turns - see def getBattlerColorFromPokeBall. + def ballBurstRecall(delay, ball, ballX, ballY, poke_ball) + color_duration = 10 # Change color of battler to a solid shade - see def battlerAbsorb + shrink_duration = 5 # Shrink battler into Poké Ball - see def battlerAbsorb + burst_duration = color_duration + shrink_duration + # Burst particles + num_particles = 5 + base_angle = 55 + base_radius = 64 # How far out from the Poké Ball the particles go + num_particles.times do |i| + # Set up particle + particle = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_particle", PictureOrigin::CENTER) + particle.setZ(0, 5110) + particle.setZoom(0, 150) + particle.setOpacity(0, 0) + particle.setVisible(0, false) + # Particle animation + particle.setVisible(delay, true) + particle.moveOpacity(delay, 2, 255) # Fade in quickly + burst_duration.times do |j| + angle = base_angle + (i * 360 / num_particles) + (135.0 * j / burst_duration) + radian = angle * Math::PI / 180 + radius = base_radius + if j < burst_duration / 5 + prop = j.to_f / (color_duration / 3) + radius *= 0.75 + (prop / 4) + elsif j >= burst_duration / 2 + prop = (j.to_f - (burst_duration / 2)) / (burst_duration / 2) + radius *= 1 - prop + end + if j == 0 + particle.setXY(delay + j, ballX + (radius * Math.cos(radian)), ballY - (radius * Math.sin(radian))) + else + particle.moveXY(delay + j, 1, ballX + (radius * Math.cos(radian)), ballY - (radius * Math.sin(radian))) + end + end + particle.moveZoom(delay, burst_duration, 0) + particle.moveTone(delay + (color_duration / 2), color_duration / 2, Tone.new(0, 0, -192)) # Yellow + particle.moveTone(delay + color_duration, shrink_duration, Tone.new(0, -128, -248)) # Dark orange + particle.moveOpacity(delay + color_duration, shrink_duration, 0) # Fade out at end + particle.setVisible(delay + burst_duration, false) + end + # Ring particles + ring1 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_ring1", PictureOrigin::CENTER) + ring1.setZ(0, 5110) + ring1.setZoom(0, 0) + ring1.setVisible(0, false) + ring2 = addNewSprite(ballX, ballY, "Graphics/Battle animations/ballBurst_ring2", PictureOrigin::CENTER) + ring2.setZ(0, 5110) + ring2.setVisible(0, false) + # Ring particle animations + ring1.setVisible(delay + burst_duration - 2, true) + ring1.moveZoom(delay + burst_duration - 2, 4, 100) + ring1.setVisible(delay + burst_duration + 2, false) + ring2.setVisible(delay + burst_duration + 2, true) + ring2.moveZoom(delay + burst_duration + 2, 4, 200) + ring2.moveOpacity(delay + burst_duration + 2, 4, 0) + end +end + +#=============================================================================== +# Shows the battle scene fading in while elements slide around into place +#=============================================================================== +class Battle::Scene::Animation::Intro < Battle::Scene::Animation + def createProcesses + appearTime = 20 # This is in 1/20 seconds + # Background + if @sprites["battle_bg2"] + makeSlideSprite("battle_bg", 0.5, appearTime) + makeSlideSprite("battle_bg2", 0.5, appearTime) + end + # Bases + makeSlideSprite("base_0", 1, appearTime, PictureOrigin::BOTTOM) + makeSlideSprite("base_1", -1, appearTime, PictureOrigin::CENTER) + # Player sprite, partner trainer sprite + @battle.player.each_with_index do |_p, i| + makeSlideSprite("player_#{i + 1}", 1, appearTime, PictureOrigin::BOTTOM) + end + # Opposing trainer sprite(s) or wild Pokémon sprite(s) + if @battle.trainerBattle? + @battle.opponent.each_with_index do |_p, i| + makeSlideSprite("trainer_#{i + 1}", -1, appearTime, PictureOrigin::BOTTOM) + end + else # Wild battle + @battle.pbParty(1).each_with_index do |_pkmn, i| + idxBattler = (2 * i) + 1 + makeSlideSprite("pokemon_#{idxBattler}", -1, appearTime, PictureOrigin::BOTTOM) + end + end + # Shadows + @battle.battlers.length.times do |i| + makeSlideSprite("shadow_#{i}", (i.even?) ? 1 : -1, appearTime, PictureOrigin::CENTER) + end + # Fading blackness over whole screen + blackScreen = addNewSprite(0, 0, "Graphics/Battle animations/black_screen") + blackScreen.setZ(0, 99999) + blackScreen.moveOpacity(0, 8, 0) + # Fading blackness over command bar + blackBar = addNewSprite(@sprites["cmdBar_bg"].x, @sprites["cmdBar_bg"].y, + "Graphics/Battle animations/black_bar") + blackBar.setZ(0, 99998) + blackBar.moveOpacity(appearTime * 3 / 4, appearTime / 4, 0) + end +end + +#=============================================================================== +# Shows a Pokémon being sent out on the player's side (including by a partner). +# Includes the Poké Ball being thrown. +#=============================================================================== +class Battle::Scene::Animation::PokeballPlayerSendOut < Battle::Scene::Animation + def createProcesses + batSprite = @sprites["pokemon_#{@battler.index}"] + shaSprite = @sprites["shadow_#{@battler.index}"] + traSprite = @sprites["player_#{@idxTrainer}"] + # Calculate the Poké Ball graphic to use + poke_ball = (batSprite.pkmn) ? batSprite.pkmn.poke_ball : nil + # Calculate the color to turn the battler sprite + col = getBattlerColorFromPokeBall(poke_ball) + col.alpha = 255 + # Calculate start and end coordinates for battler sprite movement + ballPos = Battle::Scene.pbBattlerPosition(@battler.index, batSprite.sideSize) + battlerStartX = ballPos[0] # Is also where the Ball needs to end + battlerStartY = ballPos[1] # Is also where the Ball needs to end + 18 + battlerEndX = batSprite.x + battlerEndY = batSprite.y + # Calculate start and end coordinates for Poké Ball sprite movement + ballStartX = -6 + ballStartY = 202 + ballMidX = 0 # Unused in trajectory calculation + ballMidY = battlerStartY - 144 + # Set up Poké Ball sprite + ball = addBallSprite(ballStartX, ballStartY, poke_ball) + ball.setZ(0, 1025) + ball.setVisible(0, false) + # Poké Ball tracking the player's hand animation (if trainer is visible) + if @showingTrainer && traSprite && traSprite.x > 0 + ball.setZ(0, traSprite.z - 1) + ballStartX, ballStartY = ballTracksHand(ball, traSprite) + end + delay = ball.totalDuration # 0 or 7 + # Poké Ball trajectory animation + createBallTrajectory(ball, delay, 12, + ballStartX, ballStartY, ballMidX, ballMidY, battlerStartX, battlerStartY - 18) + ball.setZ(9, batSprite.z - 1) + delay = ball.totalDuration + 4 + delay += 10 * @idxOrder # Stagger appearances if multiple Pokémon are sent out at once + ballOpenUp(ball, delay - 2, poke_ball) + ballBurst(delay, ball, battlerStartX, battlerStartY - 18, poke_ball) + ball.moveOpacity(delay + 2, 2, 0) + # Set up battler sprite + battler = addSprite(batSprite, PictureOrigin::BOTTOM) + battler.setXY(0, battlerStartX, battlerStartY) + battler.setZoom(0, 0) + battler.setColor(0, col) + # Battler animation + battlerAppear(battler, delay, battlerEndX, battlerEndY, batSprite, col) + if @shadowVisible + # Set up shadow sprite + shadow = addSprite(shaSprite, PictureOrigin::CENTER) + shadow.setOpacity(0, 0) + # Shadow animation + shadow.setVisible(delay, @shadowVisible) + shadow.moveOpacity(delay + 5, 10, 255) + end + end +end + +#=============================================================================== +# Shows the player throwing a Poké Ball and it being deflected +#=============================================================================== +class Battle::Scene::Animation::PokeballThrowDeflect < Battle::Scene::Animation + def createProcesses + # Calculate start and end coordinates for battler sprite movement + batSprite = @sprites["pokemon_#{@battler.index}"] + ballPos = Battle::Scene.pbBattlerPosition(@battler.index, batSprite.sideSize) + ballStartX = -6 + ballStartY = 246 + ballMidX = 190 # Unused in arc calculation + ballMidY = 78 + ballEndX = ballPos[0] + ballEndY = 112 + # Set up Poké Ball sprite + ball = addBallSprite(ballStartX, ballStartY, @poke_ball) + ball.setZ(0, 5090) + # Poké Ball arc animation + ball.setSE(0, "Battle throw") + createBallTrajectory(ball, 0, 16, + ballStartX, ballStartY, ballMidX, ballMidY, ballEndX, ballEndY) + # Poké Ball knocked back + delay = ball.totalDuration + ball.setSE(delay, "Battle ball drop") + ball.moveXY(delay, 8, -32, Graphics.height - 96 + 32) # Back to player's corner + createBallTumbling(ball, delay, 8) + end +end diff --git a/PBS/Animations/Example anims/Move/AERIALACE.txt b/PBS/Animations/Example anims/Move/AERIALACE.txt index 952456b1c..b124afb13 100644 --- a/PBS/Animations/Example anims/Move/AERIALACE.txt +++ b/PBS/Animations/Example anims/Move/AERIALACE.txt @@ -273,14 +273,14 @@ Name = Example anim [OppMove,AERIALACE] Name = Example anim - SetOpacity = 1,170 SetOpacity = 2,85 SetOpacity = 3,0 SetOpacity = 5,255 + Graphic = Examples/Aerial Ace - Focus = User + Focus = Target SetX = 0,101 SetY = 0,-56 SetZ = 0,27 @@ -295,8 +295,8 @@ Name = Example anim SetY = 3,24 SetVisible = 4,false - Graphic = TARGET - Focus = Target + Graphic = USER + Focus = User SetX = 1,-51 SetY = 1,18 SetZ = 1,28 @@ -309,8 +309,8 @@ Name = Example anim SetOpacity = 6,85 SetVisible = 7,false - Graphic = TARGET - Focus = Target + Graphic = USER + Focus = User SetX = 2,-16 SetY = 2,44 SetZ = 2,29 @@ -319,8 +319,8 @@ Name = Example anim SetOpacity = 4,170 SetVisible = 5,false - Graphic = TARGET - Focus = Target + Graphic = USER + Focus = User SetX = 3,-16 SetY = 3,44 SetZ = 3,30 @@ -331,7 +331,7 @@ Name = Example anim SetVisible = 6,false Graphic = Examples/Aerial Ace - Focus = User + Focus = Target SetFrame = 5,7 SetX = 5,54 SetY = 5,27 @@ -354,7 +354,7 @@ Name = Example anim SetOpacity = 11,85 Graphic = Examples/Aerial Ace - Focus = User + Focus = Target SetFrame = 5,7 SetX = 5,30 SetY = 5,13 @@ -375,7 +375,7 @@ Name = Example anim SetVisible = 11,false Graphic = Examples/Aerial Ace - Focus = User + Focus = Target SetFrame = 5,7 SetX = 5,-3 SetY = 5,3 @@ -397,7 +397,7 @@ Name = Example anim SetVisible = 11,false Graphic = Examples/Aerial Ace - Focus = User + Focus = Target SetFrame = 5,7 SetX = 5,-27 SetY = 5,26 @@ -420,7 +420,7 @@ Name = Example anim SetOpacity = 11,85 Graphic = Examples/Aerial Ace - Focus = User + Focus = Target SetFrame = 5,7 SetX = 5,19 SetY = 5,50