Anim Editor: added play functionality to battle and editor

This commit is contained in:
Maruno17
2024-04-13 16:28:52 +01:00
parent d0e15a8939
commit 44cc500fdc
15 changed files with 1221 additions and 175 deletions

View File

@@ -0,0 +1,230 @@
#===============================================================================
#
#===============================================================================
class AnimationPlayer
attr_accessor :looping
attr_accessor :slowdown # 1 = normal speed, 2 = half speed, 3 = one third speed, etc.
# animation is either a GameData::Animation or a hash made from one.
# user is a Battler, or nil
# targets is an array of Battlers, or nil
def initialize(animation, user, targets, scene)
@animation = animation
@user = user
@targets = targets
@scene = scene
@viewport = @scene.viewport
@sprites = @scene.sprites
initialize_battler_sprite_names
initialize_battler_coordinates
@looping = false
@slowdown = 1
@timer_start = nil
@anim_sprites = [] # Each is a ParticleSprite
@duration = total_duration
end
# Doesn't actually create any sprites; just gathers them into a more useful array
def initialize_battler_sprite_names
@battler_sprites = []
if @user
pkmn = @user.pokemon
@battler_sprites[@user.index] = []
@battler_sprites[@user.index].push(GameData::Species.front_sprite_filename(
pkmn.species, pkmn.form, pkmn.gender))
@battler_sprites[@user.index].push(GameData::Species.back_sprite_filename(
pkmn.species, pkmn.form, pkmn.gender))
end
if @targets
@targets.each do |target|
pkmn = target.pokemon
@battler_sprites[target.index] = []
@battler_sprites[target.index].push(GameData::Species.front_sprite_filename(
pkmn.species, pkmn.form, pkmn.gender))
@battler_sprites[target.index].push(GameData::Species.back_sprite_filename(
pkmn.species, pkmn.form, pkmn.gender))
end
end
end
def initialize_battler_coordinates
@user_coords = nil
if @user
sprite = @sprites["pokemon_#{@user.index}"]
@user_coords = [sprite.x, sprite.y - (sprite.bitmap.height / 2)]
end
@target_coords = []
if @targets
@targets.each do |target|
sprite = @sprites["pokemon_#{target.index}"]
@target_coords[target.index] = [sprite.x, sprite.y - (sprite.bitmap.height / 2)]
end
end
end
def dispose
@anim_sprites.each { |particle| particle.dispose }
@anim_sprites.clear
end
#-----------------------------------------------------------------------------
def particles
return (@animation.is_a?(GameData::Animation)) ? @animation.particles : @animation[:particles]
end
# Return value is in seconds.
def total_duration
ret = AnimationPlayer::Helper.get_duration(particles) / 20.0
ret *= slowdown
return ret
end
#-----------------------------------------------------------------------------
def set_up_particle(particle, target_idx = -1)
particle_sprite = AnimationPlayer::ParticleSprite.new
# Get/create a sprite
sprite = nil
case particle[:name]
when "User"
sprite = @sprites["pokemon_#{@user.index}"]
particle_sprite.set_as_battler_sprite
when "Target"
sprite = @sprites["pokemon_#{target_idx}"]
particle_sprite.set_as_battler_sprite
when "SE"
# Intentionally no sprite created
else
sprite = Sprite.new(@viewport)
end
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])
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,
@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)
particle_sprite.focus_xy = focus_xy
particle_sprite.offset_xy = offset_xy
particle_sprite.focus_z = focus_z
# Find earliest command and add a "make visible" command then
if sprite && !particle_sprite.battler_sprite?
first_cmd = -1
particle.each_pair do |property, cmds|
next if !cmds.is_a?(Array) || cmds.empty?
cmds.each do |cmd|
first_cmd = cmd[0] if first_cmd < 0 || first_cmd > cmd[0]
end
end
particle_sprite.add_set_process(:visible, first_cmd * slowdown, true) if first_cmd >= 0
end
# Add all commands
particle.each_pair do |property, cmds|
next if !cmds.is_a?(Array) || cmds.empty?
cmds.each do |cmd|
if cmd[1] == 0
if sprite
particle_sprite.add_set_process(property, cmd[0] * slowdown, cmd[2])
else
# SE particle
filename = nil
case property
when :user_cry
filename = GameData::Species.cry_filename_from_pokemon(@user.pokemon) if @user
when :target_cry
# NOTE: If there are multiple targets, only the first one's cry
# will be played.
if @targets && !@targets.empty?
filename = GameData::Species.cry_filename_from_pokemon(@targets.first.pokemon)
end
else
filename = "Anim/" + cmd[2]
end
particle_sprite.add_set_process(property, cmd[0] * slowdown, [filename, cmd[3], cmd[4]]) if filename
end
else
particle_sprite.add_move_process(property, cmd[0] * slowdown, cmd[1] * slowdown, cmd[2], cmd[3] || :linear)
end
end
end
# Finish up
@anim_sprites.push(particle_sprite)
end
# Creates sprites and ParticleSprites, and sets sprite properties that won't
# change during the animation.
def set_up
particles.each do |particle|
if GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus]) && @targets
one_per_side = [:target_side_foreground, :target_side_background].include?(particle[:focus])
sides_covered = []
@targets.each do |target|
next if one_per_side && sides_covered.include?(target.index % 2)
set_up_particle(particle, target.index)
sides_covered.push(target.index % 2)
end
else
set_up_particle(particle)
end
end
reset_anim_sprites
end
# Sets the initial properties of all sprites, and marks all processes as not
# yet started.
def reset_anim_sprites
@anim_sprites.each { |particle| particle.reset_processes }
end
#-----------------------------------------------------------------------------
def start
@timer_start = System.uptime
end
def playing?
return !@timer_start.nil?
end
def finish
@timer_start = nil
@finished = true
end
def finished?
return @finished
end
def can_continue_battle?
return finished?
end
#-----------------------------------------------------------------------------
def update
return if !playing?
if @need_reset
reset_anim_sprites
start
@need_reset = false
end
time_now = System.uptime
elapsed = time_now - @timer_start
# Update all particles/sprites
@anim_sprites.each { |particle| particle.update(elapsed) }
# Finish or loop the animation
if elapsed >= @duration
if looping
@need_reset = true
else
finish
end
end
end
end

View File

@@ -0,0 +1,141 @@
#===============================================================================
# NOTE: This assumes that processes are added (for a given property) in the
# order they happen.
#===============================================================================
class AnimationPlayer::ParticleSprite
attr_accessor :sprite
attr_accessor :focus_xy, :offset_xy, :focus_z
FRAMES_PER_SECOND = 20.0
def initialize
@processes = []
@sprite = nil
@battler_sprite = false
initialize_values
end
def initialize_values
@values = GameData::Animation::PARTICLE_KEYFRAME_DEFAULT_VALUES.clone
end
def dispose
return if battler_sprite? || !@sprite || @sprite.disposed?
@sprite.bitmap&.dispose
@sprite.dispose
end
#-----------------------------------------------------------------------------
def set_as_battler_sprite
@battler_sprite = true
@values[:visible] = true
end
def battler_sprite?
return @battler_sprite
end
#-----------------------------------------------------------------------------
def add_set_process(property, frame, value)
add_move_process(property, frame, 0, value, :none)
end
def add_move_process(property, start_frame, duration, value, interpolation = :linear)
# First nil is progress (nil = not started, true = running, false = finished)
# Second nil is start value (set when the process starts running)
@processes.push([property, start_frame, duration, value, interpolation, nil, nil])
end
# Sets sprite's initial For looping purposes.
def reset_processes
initialize_values
set_as_battler_sprite if battler_sprite? # Start battler sprites as visible
@values.each_pair { |property, value| update_sprite_property(property, value) }
@processes.each { |process| process[5] = nil }
end
#-----------------------------------------------------------------------------
def start_process(process)
return if !process[5].nil?
process[6] = @values[process[0]]
process[5] = true
end
def update_process_value(process, elapsed_time)
# SetXYZ
if process[2] == 0
@values[process[0]] = process[3]
process[5] = false # Mark process as finished
return
end
# MoveXYZ
@values[process[0]] = AnimationPlayer::Helper.interpolate(
process[4], process[6], process[3], process[2] / FRAMES_PER_SECOND,
process[1] / FRAMES_PER_SECOND, elapsed_time
)
if elapsed_time >= (process[1] + process[2]) / FRAMES_PER_SECOND
process[5] = false # Mark process as finished
end
end
def update_sprite(changed_properties)
changed_properties.uniq!
changed_properties.each do |property|
update_sprite_property(property, @values[property])
end
end
def update_sprite_property(property, value)
if !@sprite
pbSEPlay(*value) if [:se, :user_cry, :target_cry].include?(property) && value
return
end
case property
when :frame then @sprite.src_rect.x = value.floor * @sprite.src_rect.width
when :blending then @sprite.blend_type = value
when :flip then @sprite.mirror = value
when :x
AnimationPlayer::Helper.apply_xy_focus_to_sprite(@sprite, :x, value.round, @focus_xy)
@sprite.x += @offset_xy[0]
when :y
AnimationPlayer::Helper.apply_xy_focus_to_sprite(@sprite, :y, value.round, @focus_xy)
@sprite.y += @offset_xy[1]
when :z
AnimationPlayer::Helper.apply_z_focus_to_sprite(@sprite, value, @focus_z)
when :zoom_x then @sprite.zoom_x = value / 100.0
when :zoom_y then @sprite.zoom_y = value / 100.0
when :angle then @sprite.angle = value
when :visible then @sprite.visible = value
when :opacity then @sprite.opacity = value
when :color_red then @sprite.color.red = value
when :color_green then @sprite.color.green = value
when :color_blue then @sprite.color.blue = value
when :color_alpha then @sprite.color.alpha = value
when :tone_red then @sprite.tone.red = value
when :tone_green then @sprite.tone.green = value
when :tone_blue then @sprite.tone.blue = value
when :tone_gray then @sprite.tone.gray = value
end
end
def update(elapsed_time)
frame = (elapsed_time * FRAMES_PER_SECOND).floor
changed_properties = []
@processes.each do |process|
# Skip processes that aren't due to start yet
next if process[1] > frame
# Skip processes that have already fully happened
next if process[5] == false
# Mark process as running if it isn't already
start_process(process)
# Update process's value
update_process_value(process, elapsed_time)
changed_properties.push(process[0]) # Record property as having changed
end
# Apply changed values to sprite
update_sprite(changed_properties) if !changed_properties.empty?
end
end

View File

@@ -0,0 +1,198 @@
#===============================================================================
# Methods used by both AnimationPlayer and AnimationEditor::Canvas.
#===============================================================================
module AnimationPlayer::Helper
BATTLE_MESSAGE_BAR_HEIGHT = 96 # NOTE: You shouldn't need to change this.
module_function
# Returns the duration of the animation in frames (1/20ths of a second).
def get_duration(particles)
ret = 0
particles.each do |particle|
particle.each_pair do |property, value|
next if !value.is_a?(Array) || value.empty?
max = value.last[0] + value.last[1] # Keyframe + duration
ret = max if ret < max
end
end
return ret
end
#-----------------------------------------------------------------------------
def get_xy_focus(particle, user_index, target_index, user_coords, target_coords)
ret = nil
case particle[:focus]
when :foreground, :midground, :background
when :user
ret = [user_coords.clone]
when :target
ret = [target_coords.clone]
when :user_and_target
ret = [user_coords.clone, target_coords.clone]
when :user_side_foreground, :user_side_background
ret = [Battle::Scene.pbBattlerPosition(user_index)]
when :target_side_foreground, :target_side_background
ret = [Battle::Scene.pbBattlerPosition(target_idx)]
end
return ret
end
def get_xy_offset(particle, sprite)
ret = [0, 0]
case particle[:graphic]
when "USER", "USER_OPP", "USER_FRONT", "USER_BACK",
"TARGET", "TARGET_OPP", "TARGET_FRONT", "TARGET_BACK"
ret[1] += sprite.bitmap.height / 2 if sprite
end
return ret
end
# property is :x or :y.
def apply_xy_focus_to_sprite(sprite, property, value, focus)
result = value
coord_idx = (property == :x) ? 0 : 1
if focus
if focus.length == 2
distance = GameData::Animation::USER_AND_TARGET_SEPARATION
result = focus[0][coord_idx] + ((value.to_f / distance[coord_idx]) * (focus[1][coord_idx] - focus[0][coord_idx])).to_i
else
result = value + focus[0][coord_idx]
end
end
case property
when :x then sprite.x = result
when :y then sprite.y = result
end
end
#-----------------------------------------------------------------------------
# Returns either a number or an array of two numbers.
def get_z_focus(particle, user_index, target_index)
ret = 0
case particle[:focus]
when :foreground
ret = 2000
when :midground
ret = 1000
when :background
# NOTE: No change.
when :user
ret = 1000 + ((100 * ((user_index / 2) + 1)) * (user_index.even? ? 1 : -1))
when :target
ret = 1000 + ((100 * ((target_index / 2) + 1)) * (target_index.even? ? 1 : -1))
when :user_and_target
user_pos = 1000 + ((100 * ((user_index / 2) + 1)) * (user_index.even? ? 1 : -1))
target_pos = 1000 + ((100 * ((target_index / 2) + 1)) * (target_index.even? ? 1 : -1))
ret = [user_pos, target_pos]
when :user_side_foreground, :target_side_foreground
this_idx = (particle[:focus] == :user_side_foreground) ? user_index : target_index
ret = 1000
ret += 1000 if this_idx.even? # On player's side
when :user_side_background, :target_side_background
this_idx = (particle[:focus] == :user_side_background) ? user_index : target_index
ret = 1000 if this_idx.even? # On player's side
end
return ret
end
def apply_z_focus_to_sprite(sprite, z, focus)
if focus.is_a?(Array)
distance = GameData::Animation::USER_AND_TARGET_SEPARATION[2]
if z >= 0
sprite.z = z + focus[0]
elsif z <= distance
sprite.z = z + focus[1]
else
sprite.z = focus[0] + ((z.to_f / distance) * (focus[1] - focus[0])).to_i
end
elsif focus
sprite.z = z + focus
else
sprite.z = z
end
end
#-----------------------------------------------------------------------------
# user_sprites, target_sprites = [front sprite, back sprite]
def set_bitmap_and_origin(particle, sprite, user_index, target_index, user_sprites, target_sprites)
return if sprite&.is_a?(Battle::Scene::BattlerSprite)
case particle[:graphic]
when "USER", "USER_OPP", "USER_FRONT", "USER_BACK",
"TARGET", "TARGET_OPP", "TARGET_FRONT", "TARGET_BACK"
filename = nil
case particle[:graphic]
when "USER"
filename = (user_index.even?) ? user_sprites[1] : user_sprites[0]
when "USER_OPP"
filename = (user_index.even?) ? user_sprites[0] : user_sprites[1]
when "USER_FRONT"
filename = user_sprites[0]
when "USER_BACK"
filename = user_sprites[1]
when "TARGET"
filename = (target_index.even?) ? target_sprites[1] : target_sprites[0]
when "TARGET_OPP"
filename = (target_index.even?) ? target_sprites[0] : target_sprites[1]
when "TARGET_FRONT"
filename = target_sprites[0]
when "TARGET_BACK"
filename = target_sprites[1]
end
sprite.bitmap = RPG::Cache.load_bitmap("", filename)
sprite.ox = sprite.bitmap.width / 2
sprite.oy = sprite.bitmap.height
else
sprite.bitmap = RPG::Cache.load_bitmap("Graphics/Battle animations/", particle[:graphic])
sprite.src_rect.set(0, 0, sprite.bitmap.width, sprite.bitmap.height)
if [:foreground, :midground, :background].include?(particle[:focus]) &&
sprite.bitmap.width == Settings::SCREEN_WIDTH &&
sprite.bitmap.height >= Settings::SCREEN_HEIGHT - BATTLE_MESSAGE_BAR_HEIGHT
sprite.ox = 0
sprite.oy = 0
elsif sprite.bitmap.width > sprite.bitmap.height * 2
sprite.src_rect.set(0, 0, sprite.bitmap.height, sprite.bitmap.height)
sprite.ox = sprite.bitmap.height / 2
sprite.oy = sprite.bitmap.height / 2
else
sprite.ox = sprite.bitmap.width / 2
sprite.oy = sprite.bitmap.height / 2
end
if particle[:graphic][/\[\s*bottom\s*\]\s*$/i] # [bottom] at end of filename
sprite.oy = sprite.bitmap.height
end
end
end
#-----------------------------------------------------------------------------
def interpolate(interpolation, start_val, end_val, duration, start_time, now)
case interpolation
when :linear
return lerp(start_val, end_val, duration, start_time, now).to_i
when :ease_in # Quadratic
ret = start_val
x = (now - start_time) / duration.to_f
ret += (end_val - start_val) * x * x
return ret.round
when :ease_out # Quadratic
ret = start_val
x = (now - start_time) / duration.to_f
ret += (end_val - start_val) * (1 - ((1 - x) * (1 - x)))
return ret.round
when :ease_both # Quadratic
ret = start_val
x = (now - start_time) / duration.to_f
if x < 0.5
ret += (end_val - start_val) * x * x * 2
else
ret += (end_val - start_val) * (1 - (((-2 * x) + 2) * ((-2 * x) + 2) / 2))
end
return ret.round
end
raise _INTL("Unknown interpolation method {1}.", interpolation)
end
end

View File

@@ -0,0 +1,187 @@
#===============================================================================
#
#===============================================================================
class Battle::Scene
BETTER_ANIMATION_DEFAULTS = {
:NORMAL => [:TACKLE, :SONICBOOM, :DEFENSECURL, :EXPLOSION, :SWIFT, :TAILWHIP],
:FIGHTING => [:MACHPUNCH, :AURASPHERE, :BULKUP, nil, nil, nil],
:FLYING => [:WINGATTACK, :GUST, :ROOST, nil, :AIRCUTTER, :FEATHERDANCE],
:POISON => [:POISONSTING, :SLUDGE, :ACIDARMOR, nil, :ACID, :POISONPOWDER],
:GROUND => [:SANDTOMB, :MUDSLAP, :MUDSPORT, :EARTHQUAKE, :EARTHPOWER, :SANDATTACK],
:ROCK => [:ROCKTHROW, :POWERGEM, :ROCKPOLISH, :ROCKSLIDE, nil, :SANDSTORM],
:BUG => [:TWINEEDLE, :BUGBUZZ, :QUIVERDANCE, nil, :STRUGGLEBUG, :STRINGSHOT],
:GHOST => [:ASTONISH, :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, :MAGICALLEAF, :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 => [:KNOCKOFF, :DARKPULSE, :HONECLAWS, nil, :SNARL, :EMBARGO],
:FAIRY => [:TACKLE, :FAIRYWIND, :MOONLIGHT, nil, :DAZZLINGGLEAM, :SWEETKISS]
}
#-----------------------------------------------------------------------------
def pbAnimation(move_id, user, targets, version = 0)
anims = find_move_animation(move_id, version, user&.index)
return if !anims || anims.empty?
if anims[0].is_a?(GameData::Animation) # New animation
pbSaveShadows do
# NOTE: anims.sample is a random valid animation.
play_better_animation(anims.sample, user, targets)
end
else # Old animation
anim = anims[0]
target = (targets.is_a?(Array)) ? targets[0] : targets
animations = pbLoadBattleAnimations
return if !animations
pbSaveShadows do
if anims[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
end
end
alias __newanims__pbCommonAnimation pbCommonAnimation unless method_defined?(:__newanims__pbCommonAnimation)
def pbCommonAnimation(anim_name, user = nil, target = nil)
return if nil_or_empty?(anim_name)
anims = try_get_better_common_animation(anim_name, user.index)
if anims
# NOTE: anims.sample is a random valid animation.
play_better_animation(anims.sample, user, target)
else
__newanims__pbCommonAnimation(anim_name, user, target)
end
end
#-----------------------------------------------------------------------------
# Returns an array of GameData::Animation if a new animation(s) is found.
# Return [animation index, shouldn't be flipped] if an old animation is found.
def find_move_animation(move_id, version, user_index)
# Get animation
anims = find_move_animation_for_move(move_id, version, user_index)
return anims if anims
# Get information to decide which default animation to try
move_data = GameData::Move.get(move_id)
target_data = GameData::Target.get(move_data.target)
move_type = move_data.type
default_idx = move_data.category
default_idx += 3 if target_data.num_targets > 1 || target_data.affects_foe_side
default_idx += 3 if move_data.status? && target_data.num_targets > 0
# Check for a default animation
wanted_move = BETTER_ANIMATION_DEFAULTS[move_type][default_idx]
anims = find_move_animation_for_move(wanted_move, 0, user_index)
return anims if anims
if default_idx >= 3
wanted_move = BETTER_ANIMATION_DEFAULTS[move_type][default_idx - 3]
anims = find_move_animation_for_move(wanted_move, 0, user_index)
return anims if anims
return nil if wanted_move == :TACKLE # No need to check for Tackle's animation twice
end
# Use Tackle's animation
return find_move_animation_for_move(:TACKLE, 0, user_index)
end
# Find an animation(s) for the given move_id.
def find_move_animation_for_move(move_id, version, user_index)
# Find new animation
anims = try_get_better_move_animation(move_id, version, user_index)
return anims if anims
if version > 0
anims = try_get_better_move_animation(move_id, 0, user_index)
return anims if anims
end
# Find old animation
anim = pbFindMoveAnimDetails(pbLoadMoveToAnim, move_id, user_index, version)
return anim
end
# Finds a new animation for the given move_id and version. Prefers opposing
# animations if the user is opposing. Can return multiple animations.
def try_get_better_move_animation(move_id, version, user_index)
ret = []
backup_ret = []
GameData::Animation.each do |anim|
next if !anim.move_animation? || anim.ignore
next if anim.move != move_id.to_s
next if anim.version != version
if !user_index
ret.push(anim)
next
end
if user_index.even? # User is on player's side
ret.push(anim) if !anim.opposing_animation?
else # User is on opposing side
(anim.opposing_animation?) ? ret.push(anim) : backup_ret.push(anim)
end
end
return ret if !ret.empty?
return backup_ret if !backup_ret.empty?
return nil
end
def try_get_better_common_animation(anim_name, user_index)
ret = []
backup_ret = []
GameData::Animation.each do |anim|
next if !anim.common_animation? || anim.ignore
next if anim.move != anim_name
if !user_index
ret.push(anim)
next
end
if user_index.even? # User is on player's side
ret.push(anim) if !anim.opposing_animation?
else # User is on opposing side
(anim.opposing_animation?) ? ret.push(anim) : backup_ret.push(anim)
end
end
return ret if !ret.empty?
return backup_ret if !backup_ret.empty?
return nil
end
#-----------------------------------------------------------------------------
def play_better_animation(anim_data, user, targets)
return if !anim_data
@briefMessage = false
# Memorize old battler coordinates, to be reset after the animation
old_battler_coords = []
if user
sprite = @sprites["pokemon_#{user.index}"]
old_battler_coords[user.index] = [sprite.x, sprite.y]
end
if targets
targets.each do |target|
sprite = @sprites["pokemon_#{target.index}"]
old_battler_coords[target.index] = [sprite.x, sprite.y]
end
end
# Create animation player
anim_player = AnimationPlayer.new(anim_data, user, targets, self)
anim_player.set_up
# Play animation
anim_player.start
loop do
pbUpdate
anim_player.update
break if anim_player.can_continue_battle?
end
anim_player.dispose
# Restore old battler coordinates
old_battler_coords.each_with_index do |values, i|
next if !values
sprite = @sprites["pokemon_#{i}"]
sprite.x = values[0]
sprite.y = values[1]
end
end
end

View File

@@ -0,0 +1,71 @@
# TODO: Hardcoded animations have incorrect z values because of the change to
# other sprites' z values.
#===============================================================================
#
#===============================================================================
class Battle::Scene
alias __newanims__pbInitSprites pbInitSprites unless method_defined?(:__newanims__pbInitSprites)
def pbInitSprites
__newanims__pbInitSprites
["battle_bg", "battle_bg2"].each { |spr| @sprites[spr].z = -200 }
2.times do |side|
@sprites["base_#{side}"].z = -199
end
@sprites["cmdBar_bg"].z += 9999
@sprites["messageBox"].z += 9999
@sprites["messageWindow"].z += 9999
@sprites["commandWindow"].z += 9999
@sprites["fightWindow"].z += 9999
@sprites["targetWindow"].z += 9999
2.times do |side|
@sprites["partyBar_#{side}"].z += 9999
NUM_BALLS.times do |i|
@sprites["partyBall_#{side}_#{i}"].z += 9999
end
# Ability splash bars
@sprites["abilityBar_#{side}"].z += 9999 if USE_ABILITY_SPLASH
end
@battle.battlers.each_with_index do |b, i|
@sprites["dataBox_#{i}"].z += 9999 if b
end
end
end
#===============================================================================
# Pokémon sprite (used in battle)
#===============================================================================
class Battle::Scene::BattlerSprite < RPG::Sprite
def pbSetPosition
return if !@_iconBitmap
pbSetOrigin
if @index.even?
self.z = 1100 + (100 * @index / 2)
else
self.z = 1000 - (100 * (@index + 1) / 2)
end
# Set original position
p = Battle::Scene.pbBattlerPosition(@index, @sideSize)
@spriteX = p[0]
@spriteY = p[1]
# Apply metrics
@pkmn.species_data.apply_metrics_to_sprite(self, @index)
end
end
#===============================================================================
# Shadow sprite for Pokémon (used in battle)
#===============================================================================
class Battle::Scene::BattlerShadowSprite < RPG::Sprite
def pbSetPosition
return if !@_iconBitmap
pbSetOrigin
self.z = -198
# Set original position
p = Battle::Scene.pbBattlerPosition(@index, @sideSize)
self.x = p[0]
self.y = p[1]
# Apply metrics
@pkmn.species_data.apply_metrics_to_sprite(self, @index, true)
end
end

View File

@@ -0,0 +1,26 @@
#===============================================================================
#
#===============================================================================
class AnimationPlayer::FakeBattler
attr_reader :index
attr_reader :pokemon
def initialize(index, species, form = 0, gender = 0)
@index = index
@pokemon = AnimationPlayer::FakePokemon.new(species, form, gender)
end
end
#===============================================================================
#
#===============================================================================
class AnimationPlayer::FakePokemon
attr_reader :species, :form, :gender
def initialize(species, form = 0, gender = 0)
# NOTE: species will be a string, but it doesn't need to be a symbol.
@species = species
@form = form
@gender = gender
end
end