mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
Anim Editor: added play functionality to battle and editor
This commit is contained in:
@@ -20,6 +20,10 @@ class UIControls::Label < UIControls::BaseControl
|
|||||||
refresh
|
refresh
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def text_width
|
||||||
|
return self.bitmap.text_size(@text).width
|
||||||
|
end
|
||||||
|
|
||||||
def refresh
|
def refresh
|
||||||
super
|
super
|
||||||
if @header
|
if @header
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ class UIControls::Button < UIControls::BaseControl
|
|||||||
BUTTON_HEIGHT = 28 # Used when @fixed_size is false
|
BUTTON_HEIGHT = 28 # Used when @fixed_size is false
|
||||||
# TODO: This will also depend on the font size.
|
# TODO: This will also depend on the font size.
|
||||||
TEXT_BASE_OFFSET_Y = 18 # Text is centred vertically in the button
|
TEXT_BASE_OFFSET_Y = 18 # Text is centred vertically in the button
|
||||||
|
HIGHLIGHT_COLOR = Color.green
|
||||||
|
|
||||||
def initialize(width, height, viewport, text = "")
|
def initialize(width, height, viewport, text = "")
|
||||||
super(width, height, viewport)
|
super(width, height, viewport)
|
||||||
@text = text
|
@text = text
|
||||||
@fixed_size = false
|
@fixed_size = false
|
||||||
|
@highlight = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_fixed_size
|
def set_fixed_size
|
||||||
@@ -37,6 +39,10 @@ class UIControls::Button < UIControls::BaseControl
|
|||||||
invalidate
|
invalidate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def disabled?
|
||||||
|
return highlighted? || super
|
||||||
|
end
|
||||||
|
|
||||||
def set_changed
|
def set_changed
|
||||||
@value = true
|
@value = true
|
||||||
super
|
super
|
||||||
@@ -47,12 +53,33 @@ class UIControls::Button < UIControls::BaseControl
|
|||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def highlighted?
|
||||||
|
return @highlight
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_highlighted
|
||||||
|
return if highlighted?
|
||||||
|
@highlight = true
|
||||||
|
invalidate
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_not_highlighted
|
||||||
|
return if !highlighted?
|
||||||
|
@highlight = false
|
||||||
|
invalidate
|
||||||
|
end
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
def refresh
|
def refresh
|
||||||
super
|
super
|
||||||
|
if highlighted?
|
||||||
|
# Draw highligted colour
|
||||||
|
self.bitmap.fill_rect(@button_rect.x, @button_rect.y,
|
||||||
|
@button_rect.width, @button_rect.height,
|
||||||
|
HIGHLIGHT_COLOR)
|
||||||
|
elsif disabled?
|
||||||
# Draw disabled colour
|
# Draw disabled colour
|
||||||
if disabled?
|
|
||||||
self.bitmap.fill_rect(@button_rect.x, @button_rect.y,
|
self.bitmap.fill_rect(@button_rect.x, @button_rect.y,
|
||||||
@button_rect.width, @button_rect.height,
|
@button_rect.width, @button_rect.height,
|
||||||
DISABLED_COLOR)
|
DISABLED_COLOR)
|
||||||
|
|||||||
@@ -275,6 +275,29 @@ module GameData
|
|||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
ret = super.chop + ": "
|
||||||
|
case @type
|
||||||
|
when :move then ret += _INTL("[Move]")
|
||||||
|
when :opp_move then ret += _INTL("[Foe Move]")
|
||||||
|
when :common then ret += _INTL("[Common]")
|
||||||
|
when :opp_common then ret += _INTL("[Foe Common]")
|
||||||
|
else
|
||||||
|
raise _INTL("Unknown animation type.")
|
||||||
|
end
|
||||||
|
case @type
|
||||||
|
when :move, :opp_move
|
||||||
|
move_data = GameData::Move.try_get(@move)
|
||||||
|
move_name = (move_data) ? move_data.name : @move
|
||||||
|
ret += " " + move_name
|
||||||
|
when :common, :opp_common
|
||||||
|
ret += " " + @move
|
||||||
|
end
|
||||||
|
ret += " (" + @version.to_s + ")" if @version > 0
|
||||||
|
ret += " - " + @name if @name
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
def move_animation?
|
def move_animation?
|
||||||
return [:move, :opp_move].include?(@type)
|
return [:move, :opp_move].include?(@type)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ class AnimationEditor
|
|||||||
:canvas_bg => "indoor1",
|
:canvas_bg => "indoor1",
|
||||||
# NOTE: These sprite names are also used in Pokemon.play_cry and so should
|
# NOTE: These sprite names are also used in Pokemon.play_cry and so should
|
||||||
# be a species ID (being a string is fine).
|
# be a species ID (being a string is fine).
|
||||||
:user_sprite_name => "ARCANINE",
|
:user_sprite_name => "DRAGONITE",
|
||||||
:target_sprite_name => "CHARIZARD"
|
:target_sprite_name => "CHARIZARD"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -285,7 +285,7 @@ class AnimationEditor
|
|||||||
].each_with_index do |tab, i|
|
].each_with_index do |tab, i|
|
||||||
btn = UIControls::Button.new(100, 28, pane.viewport, tab[2])
|
btn = UIControls::Button.new(100, 28, pane.viewport, tab[2])
|
||||||
btn.set_fixed_size
|
btn.set_fixed_size
|
||||||
btn.disable if tab[0] == component
|
btn.set_highlighted if tab[0] == component
|
||||||
pane.add_control_at(tab[1], btn, next_pos_x, next_pos_y)
|
pane.add_control_at(tab[1], btn, next_pos_x, next_pos_y)
|
||||||
next_pos_x += btn.width
|
next_pos_x += btn.width
|
||||||
end
|
end
|
||||||
@@ -313,6 +313,7 @@ class AnimationEditor
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_play_controls_contents
|
def set_play_controls_contents
|
||||||
|
@components[:play_controls].add_play_controls
|
||||||
@components[:play_controls].duration = @components[:particle_list].duration
|
@components[:play_controls].duration = @components[:particle_list].duration
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -330,7 +331,6 @@ class AnimationEditor
|
|||||||
move_ctrl.max_rows = 16
|
move_ctrl.max_rows = 16
|
||||||
anim_properties.add_labelled_number_text_box(:version, _INTL("Version"), 0, 99, 0)
|
anim_properties.add_labelled_number_text_box(:version, _INTL("Version"), 0, 99, 0)
|
||||||
anim_properties.add_labelled_text_box(:name, _INTL("Name"), "")
|
anim_properties.add_labelled_text_box(:name, _INTL("Name"), "")
|
||||||
# TODO: Have two TextBoxes, one for folder and one for filename?
|
|
||||||
anim_properties.add_labelled_text_box(:pbs_path, _INTL("PBS filepath"), "")
|
anim_properties.add_labelled_text_box(:pbs_path, _INTL("PBS filepath"), "")
|
||||||
anim_properties.add_labelled_checkbox(:has_user, _INTL("Involves a user?"), true)
|
anim_properties.add_labelled_checkbox(:has_user, _INTL("Involves a user?"), true)
|
||||||
anim_properties.add_labelled_checkbox(:has_target, _INTL("Involves a target?"), true)
|
anim_properties.add_labelled_checkbox(:has_target, _INTL("Involves a target?"), true)
|
||||||
@@ -420,6 +420,53 @@ class AnimationEditor
|
|||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def play_animation
|
||||||
|
# TODO: Grey out the rest of the screen.
|
||||||
|
play_controls = @components[:play_controls]
|
||||||
|
# Set up canvas as a pseudo-battle screen
|
||||||
|
@components[:canvas].prepare_to_play_animation
|
||||||
|
play_controls.prepare_to_play_animation
|
||||||
|
# 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])
|
||||||
|
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]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# Create animation player
|
||||||
|
anim_player = AnimationPlayer.new(@anim, user_battler, target_battlers, @components[:canvas])
|
||||||
|
anim_player.looping = @components[:play_controls].looping
|
||||||
|
anim_player.slowdown = @components[:play_controls].slowdown
|
||||||
|
anim_player.set_up
|
||||||
|
# Play animation
|
||||||
|
anim_player.start
|
||||||
|
loop do
|
||||||
|
Graphics.update
|
||||||
|
Input.update
|
||||||
|
anim_player.update
|
||||||
|
# TODO: Maybe get elapsed time from anim_player and pass it to
|
||||||
|
# play_controls to be drawn?
|
||||||
|
play_controls.update
|
||||||
|
if play_controls.changed?
|
||||||
|
if play_controls.values.keys.include?(:stop)
|
||||||
|
play_controls.clear_changed
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
break if anim_player.finished?
|
||||||
|
end
|
||||||
|
anim_player.dispose
|
||||||
|
@components[:canvas].end_playing_animation
|
||||||
|
play_controls.end_playing_animation
|
||||||
|
end
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
def refresh_component_visibility(component_sym)
|
def refresh_component_visibility(component_sym)
|
||||||
# Panes are all mutually exclusive
|
# Panes are all mutually exclusive
|
||||||
side_pane = AnimationEditor::SidePanes.get_pane(component_sym)
|
side_pane = AnimationEditor::SidePanes.get_pane(component_sym)
|
||||||
@@ -558,8 +605,10 @@ class AnimationEditor
|
|||||||
refresh
|
refresh
|
||||||
end
|
end
|
||||||
when :play_controls
|
when :play_controls
|
||||||
# TODO: Will the play controls ever signal themselves as changed? I don't
|
case property
|
||||||
# think so.
|
when :play
|
||||||
|
@ready_to_play = true
|
||||||
|
end
|
||||||
when :particle_list
|
when :particle_list
|
||||||
case property
|
case property
|
||||||
when :add_particle
|
when :add_particle
|
||||||
@@ -739,7 +788,10 @@ class AnimationEditor
|
|||||||
Graphics.update
|
Graphics.update
|
||||||
Input.update
|
Input.update
|
||||||
update
|
update
|
||||||
if @captured.nil? && @quit
|
if @ready_to_play
|
||||||
|
play_animation
|
||||||
|
@ready_to_play = false
|
||||||
|
elsif @captured.nil? && @quit
|
||||||
case message(_INTL("Do you want to save changes to the animation?"),
|
case message(_INTL("Do you want to save changes to the animation?"),
|
||||||
[:yes, _INTL("Yes")], [:no, _INTL("No")], [:cancel, _INTL("Cancel")])
|
[:yes, _INTL("Yes")], [:no, _INTL("No")], [:cancel, _INTL("Cancel")])
|
||||||
when :yes
|
when :yes
|
||||||
|
|||||||
@@ -298,13 +298,13 @@ class AnimationEditor::AnimationSelector
|
|||||||
# Put the correct list into the moves list
|
# Put the correct list into the moves list
|
||||||
case @animation_type
|
case @animation_type
|
||||||
when 0
|
when 0
|
||||||
@components.get_control(:moves).disable
|
@components.get_control(:moves).set_highlighted
|
||||||
@components.get_control(:commons).enable
|
@components.get_control(:commons).set_not_highlighted
|
||||||
@components.get_control(:moves_list).values = @move_list
|
@components.get_control(:moves_list).values = @move_list
|
||||||
@components.get_control(:moves_label).text = _INTL("Moves")
|
@components.get_control(:moves_label).text = _INTL("Moves")
|
||||||
when 1
|
when 1
|
||||||
@components.get_control(:moves).enable
|
@components.get_control(:moves).set_not_highlighted
|
||||||
@components.get_control(:commons).disable
|
@components.get_control(:commons).set_highlighted
|
||||||
@components.get_control(:moves_list).values = @common_list
|
@components.get_control(:moves_list).values = @common_list
|
||||||
@components.get_control(:moves_label).text = _INTL("Common animations")
|
@components.get_control(:moves_label).text = _INTL("Common animations")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,18 +4,6 @@
|
|||||||
module AnimationEditor::ParticleDataHelper
|
module AnimationEditor::ParticleDataHelper
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
def get_duration(particles)
|
|
||||||
ret = 0
|
|
||||||
particles.each do |particle|
|
|
||||||
particle.each_pair do |property, value|
|
|
||||||
next if !value.is_a?(Array) || value.length == 0
|
|
||||||
max = value.last[0] + value.last[1] # Keyframe + duration
|
|
||||||
ret = max if ret < max
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_keyframe_particle_value(particle, property, frame)
|
def get_keyframe_particle_value(particle, property, frame)
|
||||||
if !GameData::Animation::PARTICLE_KEYFRAME_DEFAULT_VALUES.include?(property)
|
if !GameData::Animation::PARTICLE_KEYFRAME_DEFAULT_VALUES.include?(property)
|
||||||
raise _INTL("Couldn't get default value for property {1} for particle {2}.",
|
raise _INTL("Couldn't get default value for property {1} for particle {2}.",
|
||||||
@@ -34,28 +22,9 @@ module AnimationEditor::ParticleDataHelper
|
|||||||
next
|
next
|
||||||
end
|
end
|
||||||
# In a "MoveXYZ" command; need to interpolate
|
# In a "MoveXYZ" command; need to interpolate
|
||||||
case (cmd[3] || :linear)
|
ret[0] = AnimationPlayer::Helper.interpolate(
|
||||||
when :linear
|
(cmd[3] || :linear), ret[0], cmd[2], cmd[1], cmd[0], frame
|
||||||
ret[0] = lerp(ret[0], cmd[2], cmd[1], cmd[0], frame).to_i
|
)
|
||||||
when :ease_in # Quadratic
|
|
||||||
x = (frame - cmd[0]) / cmd[1].to_f
|
|
||||||
ret[0] += (cmd[2] - ret[0]) * x * x
|
|
||||||
ret[0] = ret[0].round
|
|
||||||
when :ease_out # Quadratic
|
|
||||||
x = (frame - cmd[0]) / cmd[1].to_f
|
|
||||||
ret[0] += (cmd[2] - ret[0]) * (1 - ((1 - x) * (1 - x)))
|
|
||||||
ret[0] = ret[0].round
|
|
||||||
when :ease_both # Quadratic
|
|
||||||
x = (frame - cmd[0]) / cmd[1].to_f
|
|
||||||
if x < 0.5
|
|
||||||
ret[0] += (cmd[2] - ret[0]) * x * x * 2
|
|
||||||
else
|
|
||||||
ret[0] += (cmd[2] - ret[0]) * (1 - (((-2 * x) + 2) * ((-2 * x) + 2) / 2))
|
|
||||||
end
|
|
||||||
ret[0] = ret[0].round
|
|
||||||
else
|
|
||||||
raise _INTL("Unknown interpolation method {1}.", cmd[3])
|
|
||||||
end
|
|
||||||
ret[1] = true # Interpolating
|
ret[1] = true # Interpolating
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@@ -68,7 +37,7 @@ module AnimationEditor::ParticleDataHelper
|
|||||||
first_cmd = (["User", "Target"].include?(particle[:name])) ? 0 : -1
|
first_cmd = (["User", "Target"].include?(particle[:name])) ? 0 : -1
|
||||||
first_visible_cmd = -1
|
first_visible_cmd = -1
|
||||||
particle.each_pair do |prop, value|
|
particle.each_pair do |prop, value|
|
||||||
next if !value.is_a?(Array) || value.length == 0
|
next if !value.is_a?(Array) || value.empty?
|
||||||
first_cmd = value[0][0] if first_cmd < 0 || first_cmd > value[0][0]
|
first_cmd = value[0][0] if first_cmd < 0 || first_cmd > value[0][0]
|
||||||
first_visible_cmd = value[0][0] if prop == :visible && (first_visible_cmd < 0 || first_visible_cmd > value[0][0])
|
first_visible_cmd = value[0][0] if prop == :visible && (first_visible_cmd < 0 || first_visible_cmd > value[0][0])
|
||||||
end
|
end
|
||||||
@@ -111,7 +80,7 @@ module AnimationEditor::ParticleDataHelper
|
|||||||
if !["User", "Target", "SE"].include?(particle[:name])
|
if !["User", "Target", "SE"].include?(particle[:name])
|
||||||
earliest = duration
|
earliest = duration
|
||||||
particle.each_pair do |prop, value|
|
particle.each_pair do |prop, value|
|
||||||
next if !value.is_a?(Array) || value.length == 0
|
next if !value.is_a?(Array) || value.empty?
|
||||||
earliest = value[0][0] if earliest > value[0][0]
|
earliest = value[0][0] if earliest > value[0][0]
|
||||||
end
|
end
|
||||||
ret[earliest] = true
|
ret[earliest] = true
|
||||||
@@ -152,7 +121,7 @@ module AnimationEditor::ParticleDataHelper
|
|||||||
# [+/- duration, interpolation type] --- MoveXYZ (duration's sign is whether
|
# [+/- duration, interpolation type] --- MoveXYZ (duration's sign is whether
|
||||||
# it makes the value higher or lower)
|
# it makes the value higher or lower)
|
||||||
def get_particle_property_commands_timeline(particle, property, commands)
|
def get_particle_property_commands_timeline(particle, property, commands)
|
||||||
return nil if !commands || commands.length == 0
|
return nil if !commands || commands.empty?
|
||||||
if particle[:name] == "SE"
|
if particle[:name] == "SE"
|
||||||
ret = []
|
ret = []
|
||||||
commands.each { |cmd| ret[cmd[0]] = 0 }
|
commands.each { |cmd| ret[cmd[0]] = 0 }
|
||||||
@@ -192,7 +161,7 @@ module AnimationEditor::ParticleDataHelper
|
|||||||
se_particle = particles.select { |particle| particle[:name] == "SE" }[0]
|
se_particle = particles.select { |particle| particle[:name] == "SE" }[0]
|
||||||
if se_particle
|
if se_particle
|
||||||
se_particle.each_pair do |property, values|
|
se_particle.each_pair do |property, values|
|
||||||
next if !values.is_a?(Array) || values.length == 0
|
next if !values.is_a?(Array) || values.empty?
|
||||||
ret = values.any? { |value| value[0] == frame }
|
ret = values.any? { |value| value[0] == frame }
|
||||||
break if ret
|
break if ret
|
||||||
end
|
end
|
||||||
@@ -310,7 +279,7 @@ module AnimationEditor::ParticleDataHelper
|
|||||||
first_cmd = (["User", "Target", "SE"].include?(particle[:name])) ? 0 : -1
|
first_cmd = (["User", "Target", "SE"].include?(particle[:name])) ? 0 : -1
|
||||||
first_non_visible_cmd = -1
|
first_non_visible_cmd = -1
|
||||||
particle.each_pair do |prop, value|
|
particle.each_pair do |prop, value|
|
||||||
next if !value.is_a?(Array) || value.length == 0
|
next if !value.is_a?(Array) || value.empty?
|
||||||
next if prop == property && value[0][0] == frame
|
next if prop == property && value[0][0] == frame
|
||||||
first_cmd = value[0][0] if first_cmd < 0 || first_cmd > value[0][0]
|
first_cmd = value[0][0] if first_cmd < 0 || first_cmd > value[0][0]
|
||||||
next if prop == :visible
|
next if prop == :visible
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
# 9999+ = UI
|
# 9999+ = UI
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
class AnimationEditor::Canvas < Sprite
|
class AnimationEditor::Canvas < Sprite
|
||||||
|
attr_reader :sprites # Only used while playing the animation
|
||||||
attr_reader :values
|
attr_reader :values
|
||||||
|
|
||||||
FRAME_SIZE = 48
|
FRAME_SIZE = 48
|
||||||
@@ -25,7 +26,6 @@ class AnimationEditor::Canvas < Sprite
|
|||||||
@captured = nil
|
@captured = nil
|
||||||
@user_coords = []
|
@user_coords = []
|
||||||
@target_coords = []
|
@target_coords = []
|
||||||
@playing = false # TODO: What should this affect? Is it needed?
|
|
||||||
initialize_background
|
initialize_background
|
||||||
initialize_battlers
|
initialize_battlers
|
||||||
initialize_particle_sprites
|
initialize_particle_sprites
|
||||||
@@ -195,15 +195,40 @@ class AnimationEditor::Canvas < Sprite
|
|||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
def prepare_to_play_animation
|
def prepare_to_play_animation
|
||||||
# TODO: Hide particle sprites, set battler sprites to starting positions so
|
@sprites = {}
|
||||||
# that the animation can play properly. Also need a way to end this
|
# Populate @sprites with sprites that are present during battle, and reset
|
||||||
# override after the animation finishes playing. This method does not
|
# their x/y/z values so the animation player knows where they start
|
||||||
# literally play the animation; the main editor screen or playback
|
idx = user_index
|
||||||
# control does that.
|
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|
|
||||||
|
@sprites["pokemon_#{idx}"] = @battler_sprites[idx]
|
||||||
|
@battler_sprites[idx].x = @target_coords[idx][0]
|
||||||
|
@battler_sprites[idx].y = @target_coords[idx][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)
|
||||||
|
end
|
||||||
|
# TODO: Also add background/bases and so on.
|
||||||
|
hide_all_sprites
|
||||||
|
@sel_frame_sprite.visible = false
|
||||||
@playing = true
|
@playing = true
|
||||||
end
|
end
|
||||||
|
|
||||||
def end_playing_animation
|
def end_playing_animation
|
||||||
|
@sprites.clear
|
||||||
|
@sprites = nil
|
||||||
@playing = false
|
@playing = false
|
||||||
refresh
|
refresh
|
||||||
end
|
end
|
||||||
@@ -298,17 +323,21 @@ class AnimationEditor::Canvas < Sprite
|
|||||||
def refresh_battler_graphics
|
def refresh_battler_graphics
|
||||||
if !@user_sprite_name || !@user_sprite_name || @user_sprite_name != @settings[:user_sprite_name]
|
if !@user_sprite_name || !@user_sprite_name || @user_sprite_name != @settings[:user_sprite_name]
|
||||||
@user_sprite_name = @settings[:user_sprite_name]
|
@user_sprite_name = @settings[:user_sprite_name]
|
||||||
|
@user_bitmap_front_name = GameData::Species.front_sprite_filename(@user_sprite_name)
|
||||||
|
@user_bitmap_back_name = GameData::Species.back_sprite_filename(@user_sprite_name)
|
||||||
@user_bitmap_front&.dispose
|
@user_bitmap_front&.dispose
|
||||||
@user_bitmap_back&.dispose
|
@user_bitmap_back&.dispose
|
||||||
@user_bitmap_front = RPG::Cache.load_bitmap("Graphics/Pokemon/Front/", @user_sprite_name)
|
@user_bitmap_front = RPG::Cache.load_bitmap("", @user_bitmap_front_name)
|
||||||
@user_bitmap_back = RPG::Cache.load_bitmap("Graphics/Pokemon/Back/", @user_sprite_name)
|
@user_bitmap_back = RPG::Cache.load_bitmap("", @user_bitmap_back_name)
|
||||||
end
|
end
|
||||||
if !@target_bitmap_front || !@target_sprite_name || @target_sprite_name != @settings[:target_sprite_name]
|
if !@target_bitmap_front || !@target_sprite_name || @target_sprite_name != @settings[:target_sprite_name]
|
||||||
@target_sprite_name = @settings[:target_sprite_name]
|
@target_sprite_name = @settings[:target_sprite_name]
|
||||||
|
@target_bitmap_front_name = GameData::Species.front_sprite_filename(@target_sprite_name)
|
||||||
|
@target_bitmap_back_name = GameData::Species.back_sprite_filename(@target_sprite_name)
|
||||||
@target_bitmap_front&.dispose
|
@target_bitmap_front&.dispose
|
||||||
@target_bitmap_back&.dispose
|
@target_bitmap_back&.dispose
|
||||||
@target_bitmap_front = RPG::Cache.load_bitmap("Graphics/Pokemon/Front/", @target_sprite_name)
|
@target_bitmap_front = RPG::Cache.load_bitmap("", @target_bitmap_front_name)
|
||||||
@target_bitmap_back = RPG::Cache.load_bitmap("Graphics/Pokemon/Back/", @target_sprite_name)
|
@target_bitmap_back = RPG::Cache.load_bitmap("", @target_bitmap_back_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -403,108 +432,24 @@ class AnimationEditor::Canvas < Sprite
|
|||||||
# Set opacity
|
# Set opacity
|
||||||
spr.opacity = values[:opacity]
|
spr.opacity = values[:opacity]
|
||||||
# Set coordinates
|
# Set coordinates
|
||||||
spr.x = values[:x]
|
focus_xy = AnimationPlayer::Helper.get_xy_focus(particle, user_index, target_idx,
|
||||||
spr.y = values[:y]
|
@user_coords, @target_coords[target_idx])
|
||||||
case particle[:focus]
|
AnimationPlayer::Helper.apply_xy_focus_to_sprite(spr, :x, values[:x], focus_xy)
|
||||||
when :foreground, :midground, :background
|
AnimationPlayer::Helper.apply_xy_focus_to_sprite(spr, :y, values[:y], focus_xy)
|
||||||
when :user
|
|
||||||
spr.x += @user_coords[0]
|
|
||||||
spr.y += @user_coords[1]
|
|
||||||
when :target
|
|
||||||
spr.x += @target_coords[target_idx][0]
|
|
||||||
spr.y += @target_coords[target_idx][1]
|
|
||||||
when :user_and_target
|
|
||||||
user_pos = @user_coords
|
|
||||||
target_pos = @target_coords[target_idx]
|
|
||||||
distance = GameData::Animation::USER_AND_TARGET_SEPARATION
|
|
||||||
spr.x = user_pos[0] + ((values[:x].to_f / distance[0]) * (target_pos[0] - user_pos[0])).to_i
|
|
||||||
spr.y = user_pos[1] + ((values[:y].to_f / distance[1]) * (target_pos[1] - user_pos[1])).to_i
|
|
||||||
when :user_side_foreground, :user_side_background
|
|
||||||
base_coords = Battle::Scene.pbBattlerPosition(user_index)
|
|
||||||
spr.x += base_coords[0]
|
|
||||||
spr.y += base_coords[1]
|
|
||||||
when :target_side_foreground, :target_side_background
|
|
||||||
base_coords = Battle::Scene.pbBattlerPosition(target_idx)
|
|
||||||
spr.x += base_coords[0]
|
|
||||||
spr.y += base_coords[1]
|
|
||||||
end
|
|
||||||
# Set graphic and ox/oy (may also alter y coordinate)
|
# Set graphic and ox/oy (may also alter y coordinate)
|
||||||
case particle[:graphic]
|
AnimationPlayer::Helper.set_bitmap_and_origin(particle, spr, user_index, target_idx,
|
||||||
when "USER", "USER_OPP", "USER_FRONT", "USER_BACK",
|
[@user_bitmap_front_name, @user_bitmap_back_name],
|
||||||
"TARGET", "TARGET_OPP", "TARGET_FRONT", "TARGET_BACK"
|
[@target_bitmap_front_name, @target_bitmap_back_name])
|
||||||
case particle[:graphic]
|
offset_xy = AnimationPlayer::Helper.get_xy_offset(particle, spr)
|
||||||
when "USER"
|
spr.x += offset_xy[0]
|
||||||
spr.bitmap = (user_index.even?) ? @user_bitmap_back : @user_bitmap_front
|
spr.y += offset_xy[1]
|
||||||
when "USER_OPP"
|
# Set frame
|
||||||
spr.bitmap = (user_index.even?) ? @user_bitmap_front : @user_bitmap_back
|
# TODO: Should this always happens or only if the graphic is a spritesheet?
|
||||||
when "USER_FRONT"
|
# I don't think there's harm in it always being set.
|
||||||
spr.bitmap = @user_bitmap_front
|
spr.src_rect.x = values[:frame].floor * spr.src_rect.width
|
||||||
when "USER_BACK"
|
|
||||||
spr.bitmap = @user_bitmap_back
|
|
||||||
when "TARGET"
|
|
||||||
spr.bitmap = (target_idx.even?) ? @target_bitmap_back : @target_bitmap_front
|
|
||||||
when "TARGET_OPP"
|
|
||||||
spr.bitmap = (target_idx.even?) ? @target_bitmap_front : @target_bitmap_back
|
|
||||||
when "TARGET_FRONT"
|
|
||||||
spr.bitmap = @target_bitmap_front
|
|
||||||
when "TARGET_BACK"
|
|
||||||
spr.bitmap = @target_bitmap_back
|
|
||||||
end
|
|
||||||
spr.ox = spr.bitmap.width / 2
|
|
||||||
spr.oy = spr.bitmap.height
|
|
||||||
spr.y += spr.bitmap.height / 2
|
|
||||||
else
|
|
||||||
spr.bitmap = RPG::Cache.load_bitmap("Graphics/Battle animations/", particle[:graphic])
|
|
||||||
if [:foreground, :midground, :background].include?(particle[:focus]) &&
|
|
||||||
spr.bitmap.width == AnimationEditor::CANVAS_WIDTH &&
|
|
||||||
spr.bitmap.height >= AnimationEditor::CANVAS_HEIGHT - @message_bar_sprite.y
|
|
||||||
spr.ox = 0
|
|
||||||
spr.oy = 0
|
|
||||||
elsif spr.bitmap.width > spr.bitmap.height * 2
|
|
||||||
spr.src_rect.set(values[:frame] * spr.bitmap.height, 0, spr.bitmap.height, spr.bitmap.height)
|
|
||||||
spr.ox = spr.bitmap.height / 2
|
|
||||||
spr.oy = spr.bitmap.height / 2
|
|
||||||
else
|
|
||||||
spr.src_rect.set(0, 0, spr.bitmap.width, spr.bitmap.height)
|
|
||||||
spr.ox = spr.bitmap.width / 2
|
|
||||||
spr.oy = spr.bitmap.height / 2
|
|
||||||
end
|
|
||||||
if particle[:graphic][/\[\s*bottom\s*\]\s*$/i] # [bottom] at end of filename
|
|
||||||
spr.oy = spr.bitmap.height
|
|
||||||
end
|
|
||||||
end
|
|
||||||
# Set z (priority)
|
# Set z (priority)
|
||||||
spr.z = values[:z]
|
focus_z = AnimationPlayer::Helper.get_z_focus(particle, user_index, target_idx)
|
||||||
case particle[:focus]
|
AnimationPlayer::Helper.apply_z_focus_to_sprite(spr, values[:z], focus_z)
|
||||||
when :foreground
|
|
||||||
spr.z += 2000
|
|
||||||
when :midground
|
|
||||||
spr.z += 1000
|
|
||||||
when :background
|
|
||||||
# NOTE: No change.
|
|
||||||
when :user
|
|
||||||
spr.z += 1000 + ((100 * ((user_index / 2) + 1)) * (user_index.even? ? 1 : -1))
|
|
||||||
when :target
|
|
||||||
spr.z += 1000 + ((100 * ((target_idx / 2) + 1)) * (target_idx.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_idx / 2) + 1)) * (target_idx.even? ? 1 : -1))
|
|
||||||
distance = GameData::Animation::USER_AND_TARGET_SEPARATION[2]
|
|
||||||
if values[:z] >= 0
|
|
||||||
spr.z += user_pos
|
|
||||||
elsif values[:z] <= distance
|
|
||||||
spr.z += target_pos
|
|
||||||
else
|
|
||||||
spr.z = user_pos + ((values[:z].to_f / distance) * (target_pos - user_pos)).to_i
|
|
||||||
end
|
|
||||||
when :user_side_foreground, :target_side_foreground
|
|
||||||
this_idx = (particle[:focus] == :user_side_foreground) ? user_index : target_idx
|
|
||||||
spr.z += 1000
|
|
||||||
spr.z += 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_idx
|
|
||||||
spr.z += 1000 if this_idx.even? # On player's side
|
|
||||||
end
|
|
||||||
# Set various other properties
|
# Set various other properties
|
||||||
spr.zoom_x = values[:zoom_x] / 100.0
|
spr.zoom_x = values[:zoom_x] / 100.0
|
||||||
spr.zoom_y = values[:zoom_y] / 100.0
|
spr.zoom_y = values[:zoom_y] / 100.0
|
||||||
@@ -544,11 +489,7 @@ class AnimationEditor::Canvas < Sprite
|
|||||||
update_selected_particle_frame
|
update_selected_particle_frame
|
||||||
end
|
end
|
||||||
|
|
||||||
def refresh
|
def hide_all_sprites
|
||||||
refresh_bg_graphics
|
|
||||||
ensure_battler_sprites
|
|
||||||
refresh_battler_graphics
|
|
||||||
refresh_battler_positions
|
|
||||||
[@battler_sprites, @battler_frame_sprites].each do |sprites|
|
[@battler_sprites, @battler_frame_sprites].each do |sprites|
|
||||||
sprites.each { |s| s.visible = false if s && !s.disposed? }
|
sprites.each { |s| s.visible = false if s && !s.disposed? }
|
||||||
end
|
end
|
||||||
@@ -561,6 +502,14 @@ class AnimationEditor::Canvas < Sprite
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def refresh
|
||||||
|
refresh_bg_graphics
|
||||||
|
ensure_battler_sprites
|
||||||
|
refresh_battler_graphics
|
||||||
|
refresh_battler_positions
|
||||||
|
hide_all_sprites
|
||||||
@anim[:particles].each_with_index do |particle, i|
|
@anim[:particles].each_with_index do |particle, i|
|
||||||
if GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
|
if GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
|
||||||
refresh_particle(i) # Because there can be multiple targets
|
refresh_particle(i) # Because there can be multiple targets
|
||||||
|
|||||||
@@ -1,25 +1,193 @@
|
|||||||
#===============================================================================
|
#===============================================================================
|
||||||
# TODO
|
#
|
||||||
#===============================================================================
|
#===============================================================================
|
||||||
class AnimationEditor::PlayControls < UIControls::BaseControl
|
class AnimationEditor::PlayControls < UIControls::ControlsContainer
|
||||||
|
attr_reader :slowdown, :looping
|
||||||
|
|
||||||
|
ROW_HEIGHT = 28
|
||||||
|
PLAY_BUTTON_X = 241
|
||||||
|
PLAY_BUTTON_Y = 13
|
||||||
|
PLAY_BUTTON_SIZE = 22
|
||||||
|
LOOP_BUTTON_X = PLAY_BUTTON_X + PLAY_BUTTON_SIZE + 12
|
||||||
|
LOOP_BUTTON_Y = 16
|
||||||
|
LOOP_BUTTON_SIZE = 16
|
||||||
|
# NOTE: Slowdown label is centered horizontally over the buttons.
|
||||||
|
SLOWDOWN_LABEL_Y = 0
|
||||||
|
SLOWDOWN_BUTTON_X = 1
|
||||||
|
SLOWDOWN_BUTTON_Y = ROW_HEIGHT - 1
|
||||||
|
SLOWDOWN_BUTTON_WIDTH = 32
|
||||||
|
SLOWDOWN_BUTTON_SPACING = -3
|
||||||
|
# NOTE: Duration label and value are centered horizontally on DURATION_TEXT_X.
|
||||||
|
DURATION_TEXT_X = 464
|
||||||
|
DURATION_LABEL_Y = SLOWDOWN_LABEL_Y
|
||||||
|
DURATION_VALUE_Y = ROW_HEIGHT
|
||||||
|
SLOWDOWN_FACTORS = [1, 2, 4, 6, 8]
|
||||||
|
ICON_COLOR = Color.black
|
||||||
|
|
||||||
def initialize(x, y, width, height, viewport)
|
def initialize(x, y, width, height, viewport)
|
||||||
super(width, height, viewport)
|
super(x, y, width, height)
|
||||||
self.x = x
|
@viewport.z = viewport.z + 10
|
||||||
self.y = y
|
generate_button_bitmaps
|
||||||
@duration = 0
|
@duration = 0
|
||||||
|
@slowdown = SLOWDOWN_FACTORS[0]
|
||||||
|
@looping = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def add_play_controls
|
||||||
|
# Play button
|
||||||
|
play_button = UIControls::BitmapButton.new(PLAY_BUTTON_X, PLAY_BUTTON_Y, self.viewport, @play_button_bitmap)
|
||||||
|
play_button.set_interactive_rects
|
||||||
|
play_button.disable
|
||||||
|
@controls.push([:play, play_button])
|
||||||
|
# Stop button
|
||||||
|
stop_button = UIControls::BitmapButton.new(PLAY_BUTTON_X, PLAY_BUTTON_Y, self.viewport, @stop_button_bitmap)
|
||||||
|
stop_button.set_interactive_rects
|
||||||
|
stop_button.visible = false
|
||||||
|
@controls.push([:stop, stop_button])
|
||||||
|
# Loop buttons
|
||||||
|
loop_button = UIControls::BitmapButton.new(LOOP_BUTTON_X, LOOP_BUTTON_Y, self.viewport, @play_once_button_bitmap)
|
||||||
|
loop_button.set_interactive_rects
|
||||||
|
loop_button.visible = false if @looping
|
||||||
|
@controls.push([:loop, loop_button])
|
||||||
|
unloop_button = UIControls::BitmapButton.new(LOOP_BUTTON_X, LOOP_BUTTON_Y, self.viewport, @looping_button_bitmap)
|
||||||
|
unloop_button.set_interactive_rects
|
||||||
|
unloop_button.visible = false if !@looping
|
||||||
|
@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 -= (duration_label.text_width / 2) + 5
|
||||||
|
duration_label.y = SLOWDOWN_LABEL_Y
|
||||||
|
@controls.push([:slowdown_label, duration_label])
|
||||||
|
# Slowdown factor buttons
|
||||||
|
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.y = SLOWDOWN_BUTTON_Y
|
||||||
|
button.set_interactive_rects
|
||||||
|
button.set_highlighted if value == @slowdown
|
||||||
|
@controls.push([("slowdown" + value.to_s).to_sym, button])
|
||||||
|
end
|
||||||
|
# Duration label
|
||||||
|
duration_label = UIControls::Label.new(200, ROW_HEIGHT, self.viewport, _INTL("Duration"))
|
||||||
|
duration_label.x = DURATION_TEXT_X - (duration_label.text_width / 2)
|
||||||
|
duration_label.y = DURATION_LABEL_Y
|
||||||
|
@controls.push([:duration_label, duration_label])
|
||||||
|
# Duration value
|
||||||
|
duration_value = UIControls::Label.new(200, ROW_HEIGHT, self.viewport, _INTL("{1}s", 0.0))
|
||||||
|
duration_value.x = DURATION_TEXT_X - (duration_value.text_width / 2)
|
||||||
|
duration_value.y = DURATION_VALUE_Y
|
||||||
|
@controls.push([:duration_value, duration_value])
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_button_bitmaps
|
||||||
|
@play_button_bitmap = Bitmap.new(PLAY_BUTTON_SIZE, PLAY_BUTTON_SIZE)
|
||||||
|
(PLAY_BUTTON_SIZE - 2).times do |j|
|
||||||
|
@play_button_bitmap.fill_rect(PLAY_BUTTON_SIZE / 4, j + 1, (j >= (PLAY_BUTTON_SIZE - 2) / 2) ? PLAY_BUTTON_SIZE - j : j + 3, 1, ICON_COLOR)
|
||||||
|
end
|
||||||
|
@stop_button_bitmap = Bitmap.new(PLAY_BUTTON_SIZE, PLAY_BUTTON_SIZE)
|
||||||
|
@stop_button_bitmap.fill_rect(4, 4, PLAY_BUTTON_SIZE - 8, PLAY_BUTTON_SIZE - 8, ICON_COLOR)
|
||||||
|
# Loop button
|
||||||
|
@play_once_button_bitmap = Bitmap.new(LOOP_BUTTON_SIZE, LOOP_BUTTON_SIZE)
|
||||||
|
@play_once_button_bitmap.fill_rect(1, 7, 11, 2, ICON_COLOR)
|
||||||
|
@play_once_button_bitmap.fill_rect(8, 5, 2, 6, ICON_COLOR)
|
||||||
|
@play_once_button_bitmap.fill_rect(10, 6, 1, 4, ICON_COLOR)
|
||||||
|
@play_once_button_bitmap.fill_rect(13, 1, 2, 14, ICON_COLOR)
|
||||||
|
@looping_button_bitmap = Bitmap.new(LOOP_BUTTON_SIZE, LOOP_BUTTON_SIZE)
|
||||||
|
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
|
||||||
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||||
|
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1,
|
||||||
|
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||||
|
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||||
|
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||||
|
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||||
|
1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||||
|
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||||
|
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0].each_with_index do |val, i|
|
||||||
|
next if val == 0
|
||||||
|
@looping_button_bitmap.fill_rect(1 + (i % 14), 1 + (i / 14), 1, 1, ICON_COLOR)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def dispose
|
||||||
|
@play_button_bitmap.dispose
|
||||||
|
@stop_button_bitmap.dispose
|
||||||
|
@play_once_button_bitmap.dispose
|
||||||
|
@looping_button_bitmap.dispose
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
def duration=(new_val)
|
def duration=(new_val)
|
||||||
return if @duration == new_val
|
return if @duration == new_val
|
||||||
@duration = new_val
|
@duration = new_val
|
||||||
|
if @duration == 0
|
||||||
|
get_control(:play).disable
|
||||||
|
else
|
||||||
|
get_control(:play).enable
|
||||||
|
end
|
||||||
|
ctrl = get_control(:duration_value)
|
||||||
|
ctrl.text = _INTL("{1}s", @duration / 20.0)
|
||||||
|
ctrl.x = DURATION_TEXT_X - (ctrl.text_width / 2)
|
||||||
refresh
|
refresh
|
||||||
end
|
end
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
def refresh
|
def prepare_to_play_animation
|
||||||
|
get_control(:play).visible = false
|
||||||
|
get_control(:stop).visible = true
|
||||||
|
@controls.each { |ctrl| ctrl[1].disable if ctrl[0] != :stop }
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_playing_animation
|
||||||
|
get_control(:stop).visible = false
|
||||||
|
get_control(:play).visible = true
|
||||||
|
@controls.each { |ctrl| ctrl[1].enable }
|
||||||
|
end
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def update
|
||||||
super
|
super
|
||||||
draw_text(self.bitmap, 12, TEXT_OFFSET_Y + 14, _INTL("Play controls not added yet!"))
|
if @values
|
||||||
draw_text(self.bitmap, width - 134, TEXT_OFFSET_Y, _INTL("Total length: {1}s", @duration / 20.0))
|
@values.keys.each do |key|
|
||||||
|
case key
|
||||||
|
when :loop
|
||||||
|
get_control(:loop).visible = false
|
||||||
|
get_control(:unloop).visible = true
|
||||||
|
@looping = true
|
||||||
|
@values.delete(key)
|
||||||
|
when :unloop
|
||||||
|
get_control(:unloop).visible = false
|
||||||
|
get_control(:loop).visible = true
|
||||||
|
@looping = false
|
||||||
|
@values.delete(key)
|
||||||
|
else
|
||||||
|
if key.to_s[/slowdown/]
|
||||||
|
# A slowdown button was pressed; apply its effect now
|
||||||
|
@slowdown = key.to_s.sub("slowdown", "").to_i
|
||||||
|
@controls.each do |ctrl|
|
||||||
|
next if !ctrl[0].to_s[/slowdown\d+/]
|
||||||
|
if ctrl[0].to_s.sub("slowdown", "").to_i == @slowdown
|
||||||
|
ctrl[1].set_highlighted
|
||||||
|
else
|
||||||
|
ctrl[1].set_not_highlighted
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@values.delete(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@values = nil if @values.empty?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
|
|||||||
@list_viewport.dispose
|
@list_viewport.dispose
|
||||||
@commands_bg_viewport.dispose
|
@commands_bg_viewport.dispose
|
||||||
@commands_viewport.dispose
|
@commands_viewport.dispose
|
||||||
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def dispose_listed_sprites
|
def dispose_listed_sprites
|
||||||
@@ -430,7 +431,7 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
|
|||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
def calculate_duration
|
def calculate_duration
|
||||||
@duration = AnimationEditor::ParticleDataHelper.get_duration(@particles)
|
@duration = AnimationPlayer::Helper.get_duration(@particles)
|
||||||
@duration += DURATION_BUFFER
|
@duration += DURATION_BUFFER
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
230
Data/Scripts/905_Anim player/001_Anim player.rb
Normal file
230
Data/Scripts/905_Anim player/001_Anim player.rb
Normal 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
|
||||||
141
Data/Scripts/905_Anim player/002_ParticleSprite.rb
Normal file
141
Data/Scripts/905_Anim player/002_ParticleSprite.rb
Normal 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
|
||||||
198
Data/Scripts/905_Anim player/003_AnimPlayerHelper.rb
Normal file
198
Data/Scripts/905_Anim player/003_AnimPlayerHelper.rb
Normal 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
|
||||||
187
Data/Scripts/905_Anim player/010_Battle code.rb
Normal file
187
Data/Scripts/905_Anim player/010_Battle code.rb
Normal 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
|
||||||
71
Data/Scripts/905_Anim player/011_Battle z modifiers.rb
Normal file
71
Data/Scripts/905_Anim player/011_Battle z modifiers.rb
Normal 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
|
||||||
26
Data/Scripts/905_Anim player/012_Fake battler.rb
Normal file
26
Data/Scripts/905_Anim player/012_Fake battler.rb
Normal 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
|
||||||
Reference in New Issue
Block a user