Anim Editor: improved NumberTextBox entry, added "FoeInvertX/Y" particle properties, tidied up

This commit is contained in:
Maruno17
2024-04-15 22:42:46 +01:00
parent a548a1ae9d
commit 15033d6114
18 changed files with 271 additions and 279 deletions

View File

@@ -1,6 +1,3 @@
# TODO: Add indicator of whether the control's value is "lerping" between frames
# (use yellow somehow?).
#===============================================================================
#
#===============================================================================

View File

@@ -25,8 +25,8 @@ class UIControls::TextBox < UIControls::BaseControl
end
def value=(new_value)
return if @value == new_value
@value = new_value.dup
return if @value.to_s == new_value.to_s
@value = new_value.to_s.dup
invalidate
end
@@ -39,6 +39,7 @@ class UIControls::TextBox < UIControls::BaseControl
end
def delete_at(index)
@value = @value.to_s
@value.slice!(index)
@cursor_pos -= 1 if @cursor_pos > index
@cursor_timer = System.uptime

View File

@@ -22,46 +22,28 @@ class UIControls::NumberTextBox < UIControls::TextBox
end
def value=(new_value)
old_val = @value
old_val = @value.to_i
@value = new_value.to_i.clamp(self.min_value, self.max_value)
self.invalidate if @value != old_val
invalidate if @value != old_val
end
def min_value=(new_min)
return if new_min == @min_value
@min_value = new_min
@value = @value.clamp(self.min_value, self.max_value)
self.invalidate
@value = @value.to_i.clamp(self.min_value, self.max_value)
invalidate
end
def max_value=(new_max)
return if new_max == @max_value
@max_value = new_max
@value = @value.clamp(self.min_value, self.max_value)
self.invalidate
end
def insert_char(ch, index = -1)
old_val = @value
if @value == 0
@value = ch.to_i
else
self.value = @value.to_s.insert((index >= 0) ? index : @cursor_pos, ch).to_i
end
return if @value == old_val
@cursor_pos += 1
@cursor_pos = @cursor_pos.clamp(0, @value.to_s.length)
@cursor_timer = System.uptime
@cursor_shown = true
@value = @value.to_i.clamp(self.min_value, self.max_value)
invalidate
end
def delete_at(index)
new_val = @value.to_s
new_val.slice!(index)
self.value = new_val.to_i
@cursor_pos -= 1 if @cursor_pos > index
@cursor_pos = @cursor_pos.clamp(0, @value.to_s.length)
def insert_char(ch, index = -1)
@value = @value.to_s.insert((index >= 0) ? index : @cursor_pos, ch)
@cursor_pos += 1
@cursor_timer = System.uptime
@cursor_shown = true
invalidate
@@ -81,6 +63,13 @@ class UIControls::NumberTextBox < UIControls::TextBox
#-----------------------------------------------------------------------------
def reset_interaction
super
self.value = @value # Turn value back into a number and clamp it
end
#-----------------------------------------------------------------------------
def refresh
super
button_color = (disabled?) ? DISABLED_COLOR : self.bitmap.font.color
@@ -104,8 +93,8 @@ class UIControls::NumberTextBox < UIControls::TextBox
elsif @captured_area
@initial_value = @value
else
set_changed if @initial_value && @value != @initial_value
reset_interaction
set_changed if @initial_value && @value != @initial_value
end
end
@@ -114,15 +103,21 @@ class UIControls::NumberTextBox < UIControls::TextBox
Input.gets.each_char do |ch|
case ch
when "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
if (@value.to_s == "-0" && @cursor_pos > 1) ||
(@value.to_s == "0" && @cursor_pos > 0)
@value = @value.to_s.chop
@cursor_pos -= 1
end
insert_char(ch)
ret = true
when "-", "+"
if @value > 0 && @min_value < 0 && ch == "-"
insert_char(ch, 0) # Add a negative sign at the start
ret = true
elsif @value < 0
@value = @value.to_s
if @value[0] == "-"
delete_at(0) # Remove the negative sign
ret = true
elsif ch == "-"
insert_char(ch, 0) # Add a negative sign at the start
ret = true
end
next
end

View File

@@ -6,7 +6,6 @@ class UIControls::Button < UIControls::BaseControl
BUTTON_Y = 2
BUTTON_PADDING = 10 # Used when @fixed_size is false
BUTTON_HEIGHT = 28 # Used when @fixed_size is false
# TODO: This will also depend on the font size.
TEXT_BASE_OFFSET_Y = 18 # Text is centred vertically in the button
HIGHLIGHT_COLOR = Color.new(224, 192, 32) # Dark yellow

View File

@@ -18,8 +18,6 @@ module GameData
# NOTE: All mentions of focus types can be found by searching for
# :user_and_target, plus there's :foreground in PARTICLE_DEFAULT_VALUES
# below.
# TODO: Add :user_ground, :target_ground?
# TODO: Add :opposing_side_foreground and :opposing_side_background?
FOCUS_TYPES = {
"Foreground" => :foreground,
"Midground" => :midground,
@@ -29,8 +27,8 @@ module GameData
"UserAndTarget" => :user_and_target,
"UserSideForeground" => :user_side_foreground,
"UserSideBackground" => :user_side_background,
"TargetSide" => :target_side_foreground,
"TargetSideBackground" => :target_side_background,
"TargetSideForeground" => :target_side_foreground,
"TargetSideBackground" => :target_side_background
}
FOCUS_TYPES_WITH_USER = [
:user, :user_and_target, :user_side_foreground, :user_side_background
@@ -56,84 +54,68 @@ module GameData
"NoUser" => [:no_user, "b"],
"NoTarget" => [:no_target, "b"],
"Ignore" => [:ignore, "b"],
# TODO: Boolean for whether the animation will be played if the target is
# on the same side as the user.
# TODO: DamageFrame (keyframe at which the battle continues, i.e. damage
# animations start playing).
"Flags" => [:flags, "*s"],
"Particle" => [:particles, "s"] # Is a subheader line like <text>
}
# For individual particles. Any property whose schema begins with "^" can
# change during the animation.
# TODO: If more "SetXYZ"/"MoveXYZ" properties are added, ensure the "SetXYZ"
# ones are given a duration of 0 in def validate_compiled_animation.
# Also add display names to def self.property_display_name.
SUB_SCHEMA = {
# These properties cannot be changed partway through the animation.
# NOTE: "Name" isn't a property here, because the particle's name comes
# from the "Particle" property above.
"Graphic" => [:graphic, "s"],
"Focus" => [:focus, "e", FOCUS_TYPES],
# TODO: FlipIfFoe, RotateIfFoe kinds of thing.
"Graphic" => [:graphic, "s"],
"Focus" => [:focus, "e", FOCUS_TYPES],
"FoeInvertX" => [:foe_invert_x, "b"],
"FoeInvertY" => [:foe_invert_y, "b"],
# All properties below are "SetXYZ" or "MoveXYZ". "SetXYZ" has the
# keyframe and the value, and "MoveXYZ" has the keyframe, duration and the
# value. All have "^" in their schema. "SetXYZ" is turned into "MoveXYZ"
# when compiling by inserting a duration (second value) of 0.
"SetFrame" => [:frame, "^uu"], # Frame within the graphic if it's a spritesheet
"MoveFrame" => [:frame, "^uuuE", nil, nil, nil, INTERPOLATION_TYPES],
"SetBlending" => [:blending, "^uu"], # 0, 1 or 2
"SetFlip" => [:flip, "^ub"],
"SetX" => [:x, "^ui"],
"MoveX" => [:x, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetY" => [:y, "^ui"],
"MoveY" => [:y, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetZ" => [:z, "^ui"],
"MoveZ" => [:z, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetZoomX" => [:zoom_x, "^uu"],
"MoveZoomX" => [:zoom_x, "^uuuE", nil, nil, nil, INTERPOLATION_TYPES],
"SetZoomY" => [:zoom_y, "^uu"],
"MoveZoomY" => [:zoom_y, "^uuuE", nil, nil, nil, INTERPOLATION_TYPES],
"SetAngle" => [:angle, "^ui"],
"MoveAngle" => [:angle, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetVisible" => [:visible, "^ub"],
"SetOpacity" => [:opacity, "^uu"],
"MoveOpacity" => [:opacity, "^uuuE", nil, nil, nil, INTERPOLATION_TYPES],
"SetColorRed" => [:color_red, "^ui"],
"MoveColorRed" => [:color_red, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetColorGreen" => [:color_green, "^ui"],
"MoveColorGreen" => [:color_green, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetColorBlue" => [:color_blue, "^ui"],
"MoveColorBlue" => [:color_blue, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetColorAlpha" => [:color_alpha, "^ui"],
"MoveColorAlpha" => [:color_alpha, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetToneRed" => [:tone_red, "^ui"],
"MoveToneRed" => [:tone_red, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetToneGreen" => [:tone_green, "^ui"],
"MoveToneGreen" => [:tone_green, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetToneBlue" => [:tone_blue, "^ui"],
"MoveToneBlue" => [:tone_blue, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetToneGray" => [:tone_gray, "^ui"],
"MoveToneGray" => [:tone_gray, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
# TODO: Add "SetColor"/"SetTone" as shorthand for the above? They'd be
# converted in the Compiler.
# TODO: Bitmap masking.
# TODO: Sprite cropping.
# TODO: Hue? I don't think so; color/tone do the same job.
"SetFrame" => [:frame, "^uu"], # Frame within the graphic if it's a spritesheet
"MoveFrame" => [:frame, "^uuuE", nil, nil, nil, INTERPOLATION_TYPES],
"SetBlending" => [:blending, "^uu"], # 0, 1 or 2
"SetFlip" => [:flip, "^ub"],
"SetX" => [:x, "^ui"],
"MoveX" => [:x, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetY" => [:y, "^ui"],
"MoveY" => [:y, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetZ" => [:z, "^ui"],
"MoveZ" => [:z, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetZoomX" => [:zoom_x, "^uu"],
"MoveZoomX" => [:zoom_x, "^uuuE", nil, nil, nil, INTERPOLATION_TYPES],
"SetZoomY" => [:zoom_y, "^uu"],
"MoveZoomY" => [:zoom_y, "^uuuE", nil, nil, nil, INTERPOLATION_TYPES],
"SetAngle" => [:angle, "^ui"],
"MoveAngle" => [:angle, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetVisible" => [:visible, "^ub"],
"SetOpacity" => [:opacity, "^uu"],
"MoveOpacity" => [:opacity, "^uuuE", nil, nil, nil, INTERPOLATION_TYPES],
"SetColorRed" => [:color_red, "^ui"],
"MoveColorRed" => [:color_red, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetColorGreen" => [:color_green, "^ui"],
"MoveColorGreen" => [:color_green, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetColorBlue" => [:color_blue, "^ui"],
"MoveColorBlue" => [:color_blue, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetColorAlpha" => [:color_alpha, "^ui"],
"MoveColorAlpha" => [:color_alpha, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetToneRed" => [:tone_red, "^ui"],
"MoveToneRed" => [:tone_red, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetToneGreen" => [:tone_green, "^ui"],
"MoveToneGreen" => [:tone_green, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetToneBlue" => [:tone_blue, "^ui"],
"MoveToneBlue" => [:tone_blue, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
"SetToneGray" => [:tone_gray, "^ui"],
"MoveToneGray" => [:tone_gray, "^uuiE", nil, nil, nil, INTERPOLATION_TYPES],
# These properties are specifically for the "SE" particle.
"Play" => [:se, "^usUU"], # Filename, volume, pitch
"PlayUserCry" => [:user_cry, "^uUU"], # Volume, pitch
"PlayTargetCry" => [:target_cry, "^uUU"] # Volume, pitch
# TODO: ScreenShake? Not sure how to work this yet. Edit def
# validate_compiled_animation like the "SE" particle does with the
# "Play"-type commands.
}
PARTICLE_DEFAULT_VALUES = {
:name => "",
:graphic => "",
:focus => :foreground
:name => "",
:graphic => "",
:focus => :foreground,
:foe_invert_x => false,
:foe_invert_y => false
}
# NOTE: Particles are invisible until their first command, and automatically
# become visible then. "User" and "Target" are visible from the start,

View File

@@ -186,6 +186,19 @@ module Compiler
raise _INTL("Animation can't play the target's cry if property \"NoTarget\" is set to true.") + "\n" + FileLineData.linereport
end
end
# Ensure that none of the particle's "alter something if focus is a
# battler on the foe's side" properties are set if the particle doesn't
# have such a focus
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(particle[:focus]) == GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
if particle[:foe_invert_x]
raise _INTL("Particle \"{1}\" can't set \"FoeInvertX\" if its focus isn't exactly 1 thing.",
particle[:name]) + "\n" + FileLineData.linereport
end
if particle[:foe_invert_y]
raise _INTL("Particle \"{1}\" can't set \"FoeInvertY\" if its focus isn't exactly 1 thing.",
particle[:name]) + "\n" + FileLineData.linereport
end
end
# Ensure that the same SE isn't played twice in the same frame
if particle[:name] == "SE"
[:se, :user_cry, :target_cry].each do |property|

View File

@@ -1,6 +1,3 @@
# TODO: OppMove animations have their user and target swapped, and will need
# them swapping back.
module AnimationConverter
NO_USER_COMMON_ANIMATIONS = [
"Hail", "HarshSun", "HeavyRain", "Rain", "Sandstorm", "Sun", "ShadowSky",
@@ -223,8 +220,6 @@ module AnimationConverter
when 2 # :user
val -= Battle::Scene::FOCUSUSER_X
when 3 # :user_and_target
# TODO: What if the animation is an OppMove one? I think this should
# be the other way around.
user_x = Battle::Scene::FOCUSUSER_X
target_x = Battle::Scene::FOCUSTARGET_X
if hash[:type] == :opp_move
@@ -248,8 +243,6 @@ module AnimationConverter
when 2 # :user
val -= Battle::Scene::FOCUSUSER_Y
when 3 # :user_and_target
# TODO: What if the animation is an OppMove one? I think this should
# be the other way around.
user_y = Battle::Scene::FOCUSUSER_Y
target_y = Battle::Scene::FOCUSTARGET_Y
if hash[:type] == :opp_move
@@ -279,10 +272,6 @@ module AnimationConverter
when :frame
next if val < 0 # -1 is user, -2 is target
end
# TODO: Come up with a better way to set a particle's graphic being
# the user or target. Probably can't, due to overlapping cel
# numbers and user/target being the :graphic property which
# doesn't change.
particle[property[1]].push([frame_num, 0, val])
last_frame[property[0]] = cel[property[0]]
changed_particles.push(idx) if !changed_particles.include?(idx)
@@ -305,14 +294,11 @@ module AnimationConverter
lookup_idx = index_lookup.index(idx)
index_lookup[lookup_idx] = -1
end
# Add a dummy command to the user particle in the last frame if that frame
# doesn't have any commands
# Add a dummy command in the last frame if that frame doesn't have any
# commands (this makes all visible particles invisible)
if frame_num == anim.length - 1 && changed_particles.empty?
hash[:particles].each_with_index do |particle, idx|
next if !particle || ["User", "Target"].include?(particle[:name])
# TODO: Making all non-user non-target particles invisible in the last
# frame isn't a perfect solution, but it's good enough to get
# example animation data.
next if last_frame_values[idx][AnimFrame::VISIBLE] == 0
particle[:visible] ||= []
particle[:visible].push([frame_num + 1, 0, false])
@@ -332,7 +318,6 @@ module AnimationConverter
#-----------------------------------------------------------------------------
# TODO: Haven't tested this as no Essentials animations use them.
def add_bg_fg_commands_to_new_anim_hash(anim, new_anim)
bg_particle = { :name => "Background", :focus => :background }
fg_particle = { :name => "Foreground", :focus => :foreground }

View File

@@ -209,14 +209,11 @@ class AnimationEditor
end
def load_settings
# TODO: Load these from a saved file.
@settings = {
:side_sizes => [1, 1],
:user_index => 0,
:target_indices => [1],
:side_sizes => [1, 1], # Player's side, opposing side
:user_index => 0, # 0, 2, 4
:target_indices => [1], # There must be at least one valid target
:user_opposes => false,
# TODO: Ideally be able to independently choose base graphics, which will
# be a separate setting here.
:canvas_bg => "indoor1",
# NOTE: These sprite names are also used in Pokemon.play_cry and so should
# be a species ID (being a string is fine).
@@ -277,11 +274,9 @@ class AnimationEditor
def add_side_pane_tab_buttons(component, pane)
next_pos_x, next_pos_y = pane.next_control_position
# TODO: Add masking tab and properties.
[
[:commands_pane, :general_tab, _INTL("General")],
[:color_tone_pane, :color_tone_tab, _INTL("Color/Tone")],
# [:masking_pane, :masking_tab, _INTL("Masking")]
[:color_tone_pane, :color_tone_tab, _INTL("Color/Tone")]
].each_with_index do |tab, i|
btn = UIControls::Button.new(100, 28, pane.viewport, tab[2])
btn.set_fixed_size
@@ -334,7 +329,6 @@ class AnimationEditor
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_target, _INTL("Involves a target?"), true)
# TODO: Flags control. Includes a List, TextBox and some add/delete Buttons.
anim_properties.add_button(:close, _INTL("Close"))
anim_properties.visible = false
end
@@ -421,7 +415,6 @@ 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
@@ -457,8 +450,6 @@ class AnimationEditor
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)
@@ -487,7 +478,6 @@ class AnimationEditor
ctrl = @components[:animation_properties].get_control(:move)
case @anim[:type]
when :move, :opp_move
# TODO: Cache this list?
move_list = []
GameData::Move.each { |m| move_list.push([m.id.to_s, m.name]) }
move_list.push(["STRUGGLE", _INTL("Struggle")]) if move_list.none? { |val| val[0] == "STRUGGLE" }
@@ -527,7 +517,6 @@ class AnimationEditor
when :common, :opp_common
component.get_control(:move_label).text = _INTL("Common animation")
end
# TODO: Maybe other things as well?
else
# Side panes
if AnimationEditor::SidePanes.is_side_pane?(component_sym)
@@ -543,8 +532,6 @@ class AnimationEditor
component.controls.each do |ctrl|
next if !new_vals.include?(ctrl[0])
ctrl[1].value = new_vals[ctrl[0]][0] if ctrl[1].respond_to?("value=")
# TODO: new_vals[ctrl[0]][1] is whether the value is being interpolated,
# which should be indicated somehow in ctrl[1].
end
end
# Additional refreshing of controls
@@ -591,7 +578,6 @@ class AnimationEditor
when :name
edit_animation_properties
@components[:menu_bar].anim_name = get_animation_display_name
# TODO: May need to refresh other things.
refresh_component(:particle_list)
end
when :canvas
@@ -663,8 +649,6 @@ class AnimationEditor
refresh_component(:canvas)
end
when :animation_properties
# TODO: Will changes here need to refresh any other components (e.g. side
# panes)? Probably.
case property
when :type, :opp_variant
type = @components[component_sym].get_control(:type).value
@@ -770,7 +754,6 @@ class AnimationEditor
refresh if keyframe != old_keyframe || particle_index != old_particle_index
end
if component.respond_to?("values")
# TODO: Make undo/redo snapshot.
values = component.values
if values
values.each_pair do |property, value|

View File

@@ -80,9 +80,6 @@ class AnimationEditor
# Show pop-up window
@pop_up_bg_bitmap.visible = true
bg_bitmap = create_pop_up_window(ANIM_PROPERTIES_WIDTH, ANIM_PROPERTIES_HEIGHT)
# TODO: Draw box around list control(s), i.e. flags. Note that an extra +4
# should be added to its x coordinate because of padding created when
# defining @components[:animation_properties].
anim_properties = @components[:animation_properties]
anim_properties.visible = true
# Set control values
@@ -99,7 +96,6 @@ class AnimationEditor
anim_properties.get_control(:has_user).value = !@anim[:no_user]
anim_properties.get_control(:has_target).value = !@anim[:no_target]
anim_properties.get_control(:usable).value = !(@anim[:ignore] || false)
# TODO: Populate flags.
refresh_component(:animation_properties) # This sets the :move control's value
# Interaction loop
ret = nil
@@ -200,8 +196,6 @@ class AnimationEditor
fname = (chunks[0] == "USER") ? @settings[:user_sprite_name].to_s : @settings[:target_sprite_name].to_s
case chunks[1] || ""
when "", "OPP"
# TODO: "TARGET" and "TARGET_OPP" will not be accurate in cases where
# the target is on the same side as the user.
if (chunks[0] == "USER") ^ (chunks[1] == "OPP") # xor
folder = (@settings[:user_opposes]) ? "Graphics/Pokemon/Front/" : "Graphics/Pokemon/Back/"
else

View File

@@ -132,12 +132,6 @@ AnimationEditor::SidePanes.add_pane(:particle_pane, {
}
})
# AnimationEditor::SidePanes.add_pane(:keyframe_pane, {
# :set_visible => proc { |editor, anim, keyframe, particle_index|
# next keyframe >= 0 && particle_index < 0
# }
# })
#===============================================================================
#
#===============================================================================
@@ -183,12 +177,6 @@ AnimationEditor::SidePanes.add_property(:commands_pane, :z, {
}
})
# TODO: If the graphic is user's sprite/target's sprite, make :frame instead
# a choice of front/back/same as the main sprite/opposite of the main
# sprite. Will need two controls in the same space, which is doable.
# Will also need to change the graphic chooser to only have "user"/
# "target" options rather than all the variants that this control
# would manage.
AnimationEditor::SidePanes.add_property(:commands_pane, :frame, {
:new => proc { |pane, editor|
pane.add_labelled_number_text_box(:frame, _INTL("Frame"), 0, 99, 0)
@@ -196,7 +184,6 @@ AnimationEditor::SidePanes.add_property(:commands_pane, :frame, {
:refresh_value => proc { |control, editor|
# Disable the "Frame" control if the particle's graphic is predefined to be
# the user's or target's sprite
# TODO: Also disable it if the particle's graphic isn't a spritesheet.
graphic = editor.anim[:particles][editor.particle_index][:graphic]
if ["USER", "USER_OPP", "USER_FRONT", "USER_BACK",
"TARGET", "TARGET_OPP", "TARGET_FRONT", "TARGET_BACK"].include?(graphic)
@@ -253,9 +240,6 @@ AnimationEditor::SidePanes.add_property(:commands_pane, :blending, {
}
})
# TODO: Add buttons that shift all commands from the current keyframe and later
# forwards/backwards in time?
#===============================================================================
#
#===============================================================================
@@ -534,8 +518,39 @@ AnimationEditor::SidePanes.add_property(:particle_pane, :focus, {
}
})
# TODO: FlipIfFoe.
# TODO: RotateIfFoe.
AnimationEditor::SidePanes.add_property(:particle_pane, :opposing_label, {
:new => proc { |pane, editor|
pane.add_label(:opposing_label, _INTL("If on opposing side..."))
}
})
AnimationEditor::SidePanes.add_property(:particle_pane, :foe_invert_x, {
:new => proc { |pane, editor|
pane.add_labelled_checkbox(:foe_invert_x, _INTL("Invert X"), false)
},
:refresh_value => proc { |control, editor|
focus = editor.anim[:particles][editor.particle_index][:focus]
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(focus) == GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(focus)
control.disable
else
control.enable
end
}
})
AnimationEditor::SidePanes.add_property(:particle_pane, :foe_invert_y, {
:new => proc { |pane, editor|
pane.add_labelled_checkbox(:foe_invert_y, _INTL("Invert Y"), false)
},
:refresh_value => proc { |control, editor|
focus = editor.anim[:particles][editor.particle_index][:focus]
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(focus) == GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(focus)
control.disable
else
control.enable
end
}
})
AnimationEditor::SidePanes.add_property(:particle_pane, :duplicate, {
:new => proc { |pane, editor|
@@ -580,18 +595,3 @@ AnimationEditor::SidePanes.add_property(:particle_pane, :delete, {
end
}
})
# TODO: Various ways to bulk shift this particle's commands earlier/later.
#===============================================================================
# NOTE: keyframe_pane is currently inaccessible (intentionally). If it will have
# its own commands and should be accessible again, change def
# on_mouse_release in ParticleList.
#===============================================================================
# AnimationEditor::SidePanes.add_property(:keyframe_pane, :header, {
# :new => proc { |pane, editor|
# pane.add_header_label(:header, _INTL("Edit keyframe"))
# }
# })
# TODO: Various command-shifting options (insert/delete keyframe).

View File

@@ -63,7 +63,8 @@ module AnimationEditor::ParticleDataHelper
return ret
end
# TODO: Generalise this to any property?
# Used to determine which keyframes the particle is visible in, which is
# indicated in the timeline by a coloured bar.
# NOTE: Particles are assumed to be not visible at the start of the
# animation, and automatically become visible when the particle has
# its first command. This does not apply to the "User" and "Target"
@@ -460,11 +461,8 @@ module AnimationEditor::ParticleDataHelper
# the new one, the new particle will inherit its focus; otherwise it gets a
# default focus of :foreground.
def add_particle(particles, index)
new_particle = {
:name => _INTL("New particle"),
:graphic => GameData::Animation::PARTICLE_DEFAULT_VALUES[:graphic],
:focus => GameData::Animation::PARTICLE_DEFAULT_VALUES[:focus]
}
new_particle = GameData::Animation::PARTICLE_DEFAULT_VALUES.clone
new_particle[:name] = _INTL("New particle")
if index > 0 && index <= particles.length && particles[index - 1][:name] != "SE"
new_particle[:focus] = particles[index - 1][:focus]
end

View File

@@ -39,7 +39,6 @@ class AnimationEditor::Canvas < Sprite
def initialize_background
self.z = -200
# NOTE: The background graphic is self.bitmap.
# TODO: Add second (flipped) background graphic, for screen shake commands.
player_base_pos = Battle::Scene.pbBattlerPosition(0)
@player_base = IconSprite.new(*player_base_pos, viewport)
@player_base.z = -199
@@ -231,7 +230,6 @@ class AnimationEditor::Canvas < Sprite
AnimationPlayer::Helper.apply_z_focus_to_sprite(@battler_sprites[idx], 0, focus_z)
end
end
# TODO: Also add background/bases and so on.
hide_all_sprites
@sel_frame_sprite.visible = false
@playing = true
@@ -249,9 +247,6 @@ class AnimationEditor::Canvas < Sprite
def refresh_bg_graphics
return if @bg_name && @bg_name == @settings[:canvas_bg]
@bg_name = @settings[:canvas_bg]
# TODO: Make the choice of background graphics match the in-battle one in
# def pbCreateBackdropSprites. Ideally make that method a class method
# so the canvas can use it rather than duplicate it.
self.bitmap = RPG::Cache.load_bitmap("Graphics/Battlebacks/", @bg_name + "_bg")
@player_base.setBitmap("Graphics/Battlebacks/" + @bg_name + "_base0")
@player_base.ox = @player_base.bitmap.width / 2
@@ -292,12 +287,11 @@ class AnimationEditor::Canvas < Sprite
end
end
# TODO: Create shadow sprites?
# TODO: Make this also refresh if the layout of the battle changes (i.e. which
# battlers are the user/target).
def ensure_battler_sprites
if @sides_swapped.nil? || @sides_swapped != sides_swapped? ||
!@side_size0 || @side_size0 != side_size(0)
should_ensure = @sides_swapped.nil? || @sides_swapped != sides_swapped? ||
@settings_user_index.nil? || @settings_user_index != @settings[:user_index] ||
@settings_target_indices.nil? || @settings_target_indices != @settings[:target_indices]
if should_ensure || !@side_size0 || @side_size0 != side_size(0)
@battler_sprites.each_with_index { |s, i| s.dispose if i.even? && s && !s.disposed? }
@battler_frame_sprites.each_with_index { |s, i| s.dispose if i.even? && s && !s.disposed? }
@side_size0 = side_size(0)
@@ -312,8 +306,7 @@ class AnimationEditor::Canvas < Sprite
@battler_frame_sprites[i * 2] = frame_sprite
end
end
if @sides_swapped.nil? || @sides_swapped != sides_swapped? ||
!@side_size1 || @side_size1 != side_size(1)
if should_ensure || !@side_size1 || @side_size1 != side_size(1)
@battler_sprites.each_with_index { |s, i| s.dispose if i.odd? && s && !s.disposed? }
@battler_frame_sprites.each_with_index { |s, i| s.dispose if i.odd? && s && !s.disposed? }
@side_size1 = side_size(1)
@@ -328,7 +321,11 @@ class AnimationEditor::Canvas < Sprite
@battler_frame_sprites[(i * 2) + 1] = frame_sprite
end
end
@sides_swapped = sides_swapped?
if should_ensure
@sides_swapped = sides_swapped?
@settings_user_index = @settings[:user_index]
@settings_target_indices = @settings[:target_indices].clone
end
end
def refresh_battler_graphics
@@ -429,6 +426,14 @@ class AnimationEditor::Canvas < Sprite
def refresh_sprite(index, target_idx = -1)
particle = @anim[:particles][index]
return if !particle || particle[:name] == "SE"
relative_to_index = -1
if particle[:focus] != :user_and_target
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(particle[:focus])
relative_to_index = user_index
elsif GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
relative_to_index = target_idx
end
end
# Get sprite
spr, frame = get_sprite_and_frame(index, target_idx)
# Calculate all values of particle at the current keyframe
@@ -443,10 +448,16 @@ class AnimationEditor::Canvas < Sprite
# Set opacity
spr.opacity = values[:opacity]
# Set coordinates
base_x = values[:x]
base_y = values[:y]
if relative_to_index >= 0 && relative_to_index.odd?
base_x *= -1 if particle[:foe_invert_x]
base_y *= -1 if particle[:foe_invert_y]
end
focus_xy = AnimationPlayer::Helper.get_xy_focus(particle, user_index, target_idx,
@user_coords, @target_coords[target_idx])
AnimationPlayer::Helper.apply_xy_focus_to_sprite(spr, :x, values[:x], focus_xy)
AnimationPlayer::Helper.apply_xy_focus_to_sprite(spr, :y, values[:y], focus_xy)
AnimationPlayer::Helper.apply_xy_focus_to_sprite(spr, :x, base_x, focus_xy)
AnimationPlayer::Helper.apply_xy_focus_to_sprite(spr, :y, base_y, focus_xy)
# Set graphic and ox/oy (may also alter y coordinate)
AnimationPlayer::Helper.set_bitmap_and_origin(particle, spr, user_index, target_idx,
[@user_bitmap_front_name, @user_bitmap_back_name],
@@ -455,8 +466,6 @@ class AnimationEditor::Canvas < Sprite
spr.x += offset_xy[0]
spr.y += offset_xy[1]
# Set frame
# TODO: Should this always happens or only if the graphic is a spritesheet?
# I don't think there's harm in it always being set.
spr.src_rect.x = values[:frame].floor * spr.src_rect.width
# Set z (priority)
focus_z = AnimationPlayer::Helper.get_z_focus(particle, user_index, target_idx)
@@ -627,6 +636,15 @@ class AnimationEditor::Canvas < Sprite
base_coords = Battle::Scene.pbBattlerPosition(first_target_index)
new_pos -= base_coords[0]
end
relative_to_index = -1
if particle[:focus] != :user_and_target
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(particle[:focus])
relative_to_index = user_index
elsif GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
relative_to_index = target_idx
end
end
new_pos *= -1 if relative_to_index >= 0 && relative_to_index.odd? && particle[:foe_invert_x]
@values ||= {}
@values[:x] = new_pos
@captured[0] = new_canvas_x
@@ -655,6 +673,15 @@ class AnimationEditor::Canvas < Sprite
base_coords = Battle::Scene.pbBattlerPosition(first_target_index)
new_pos -= base_coords[1]
end
relative_to_index = -1
if particle[:focus] != :user_and_target
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(particle[:focus])
relative_to_index = user_index
elsif GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
relative_to_index = target_idx
end
end
new_pos *= -1 if relative_to_index >= 0 && relative_to_index.odd? && particle[:foe_invert_y]
@values ||= {}
@values[:y] = new_pos
@captured[1] = new_canvas_y

View File

@@ -33,25 +33,68 @@ class AnimationEditor::PlayControls < UIControls::ControlsContainer
@looping = false
end
def dispose
@bitmaps.each { |b| b&.dispose }
super
end
#-----------------------------------------------------------------------------
def generate_button_bitmaps
@bitmaps = {}
play_button = Bitmap.new(PLAY_BUTTON_SIZE, PLAY_BUTTON_SIZE)
(PLAY_BUTTON_SIZE - 2).times do |j|
play_button.fill_rect(PLAY_BUTTON_SIZE / 4, j + 1, (j >= (PLAY_BUTTON_SIZE - 2) / 2) ? PLAY_BUTTON_SIZE - j : j + 3, 1, ICON_COLOR)
end
@bitmaps[:play_button] = play_button
stop_button = Bitmap.new(PLAY_BUTTON_SIZE, PLAY_BUTTON_SIZE)
stop_button.fill_rect(4, 4, PLAY_BUTTON_SIZE - 8, PLAY_BUTTON_SIZE - 8, ICON_COLOR)
@bitmaps[:stop_button] = stop_button
# Loop button
play_once_button = Bitmap.new(LOOP_BUTTON_SIZE, LOOP_BUTTON_SIZE)
play_once_button.fill_rect(1, 7, 11, 2, ICON_COLOR)
play_once_button.fill_rect(8, 5, 2, 6, ICON_COLOR)
play_once_button.fill_rect(10, 6, 1, 4, ICON_COLOR)
play_once_button.fill_rect(13, 1, 2, 14, ICON_COLOR)
@bitmaps[:play_once_button] = play_once_button
looping_button = 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.fill_rect(1 + (i % 14), 1 + (i / 14), 1, 1, ICON_COLOR)
end
@bitmaps[:looping_button] = looping_button
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 = UIControls::BitmapButton.new(PLAY_BUTTON_X, PLAY_BUTTON_Y, self.viewport, @bitmaps[:play_button])
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 = UIControls::BitmapButton.new(PLAY_BUTTON_X, PLAY_BUTTON_Y, self.viewport, @bitmaps[:stop_button])
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 = UIControls::BitmapButton.new(LOOP_BUTTON_X, LOOP_BUTTON_Y, self.viewport, @bitmaps[:play_once_button])
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 = UIControls::BitmapButton.new(LOOP_BUTTON_X, LOOP_BUTTON_Y, self.viewport, @bitmaps[:looping_button])
unloop_button.set_interactive_rects
unloop_button.visible = false if !@looping
@controls.push([:unloop, unloop_button])
@@ -83,47 +126,6 @@ class AnimationEditor::PlayControls < UIControls::ControlsContainer
@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)

View File

@@ -135,31 +135,35 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
def initialize_controls
generate_button_bitmaps
@controls = []
add_particle_button = UIControls::BitmapButton.new(x + 1, y + 1, viewport, @add_button_bitmap)
add_particle_button = UIControls::BitmapButton.new(x + 1, y + 1, viewport, @bitmaps[:add_button])
add_particle_button.set_interactive_rects
@controls.push([:add_particle, add_particle_button])
up_particle_button = UIControls::BitmapButton.new(x + 22, y + 1, viewport, @up_button_bitmap)
up_particle_button = UIControls::BitmapButton.new(x + 22, y + 1, viewport, @bitmaps[:up_button])
up_particle_button.set_interactive_rects
@controls.push([:move_particle_up, up_particle_button])
down_particle_button = UIControls::BitmapButton.new(x + 43, y + 1, viewport, @down_button_bitmap)
down_particle_button = UIControls::BitmapButton.new(x + 43, y + 1, viewport, @bitmaps[:down_button])
down_particle_button.set_interactive_rects
@controls.push([:move_particle_down, down_particle_button])
end
def generate_button_bitmaps
@add_button_bitmap = Bitmap.new(12, 12)
@add_button_bitmap.fill_rect(1, 5, 10, 2, TEXT_COLOR)
@add_button_bitmap.fill_rect(5, 1, 2, 10, TEXT_COLOR)
@up_button_bitmap = Bitmap.new(12, 12)
@bitmaps = {}
add_button = Bitmap.new(12, 12)
add_button.fill_rect(1, 5, 10, 2, TEXT_COLOR)
add_button.fill_rect(5, 1, 2, 10, TEXT_COLOR)
@bitmaps[:add_button] = add_button
up_button = Bitmap.new(12, 12)
5.times do |i|
@up_button_bitmap.fill_rect(1 + i, 7 - i, 1, (i == 0) ? 2 : 3, TEXT_COLOR)
@up_button_bitmap.fill_rect(10 - i, 7 - i, 1, (i == 0) ? 2 : 3, TEXT_COLOR)
up_button.fill_rect(1 + i, 7 - i, 1, (i == 0) ? 2 : 3, TEXT_COLOR)
up_button.fill_rect(10 - i, 7 - i, 1, (i == 0) ? 2 : 3, TEXT_COLOR)
end
@down_button_bitmap = Bitmap.new(12, 12)
@bitmaps[:up_button] = up_button
down_button = Bitmap.new(12, 12)
5.times do |i|
@down_button_bitmap.fill_rect(1 + i, 2 + i + (i == 0 ? 1 : 0), 1, (i == 0) ? 2 : 3, TEXT_COLOR)
@down_button_bitmap.fill_rect(10 - i, 2 + i + (i == 0 ? 1 : 0), 1, (i == 0) ? 2 : 3, TEXT_COLOR)
down_button.fill_rect(1 + i, 2 + i + (i == 0 ? 1 : 0), 1, (i == 0) ? 2 : 3, TEXT_COLOR)
down_button.fill_rect(10 - i, 2 + i + (i == 0 ? 1 : 0), 1, (i == 0) ? 2 : 3, TEXT_COLOR)
end
@bitmaps[:down_button] = down_button
end
def dispose
@@ -171,9 +175,7 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
@particle_line_sprite.dispose
@controls.each { |c| c[1].dispose }
@controls.clear
@add_button_bitmap.dispose
@up_button_bitmap.dispose
@down_button_bitmap.dispose
@bitmaps.each { |b| b&.dispose }
dispose_listed_sprites
@list_viewport.dispose
@commands_bg_viewport.dispose
@@ -436,9 +438,6 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
@duration += DURATION_BUFFER
end
# TODO: Call this only from set_particles and when changes are made to
# @particles by the main editor scene. If we can be specific about which
# particle was changed, recalculate only that particle's commands.
def calculate_all_commands_and_durations
calculate_duration
calculate_all_commands
@@ -956,8 +955,6 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
end
set_changed if @keyframe != @captured_keyframe || @row_index != @captured_row
@keyframe = @captured_keyframe || -1
# TODO: If :keyframe_pane should be accessible by clicking on the
# timeline, change the below line to = @captured_row || -1.
@row_index = @captured_row if @captured_row
end
end

View File

@@ -113,6 +113,18 @@ class AnimationPlayer
particle_sprite.focus_xy = focus_xy
particle_sprite.offset_xy = offset_xy
particle_sprite.focus_z = focus_z
# Set whether properties should be modified if the particle's target is on
# the opposing side
relative_to_index = -1
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(particle[:focus])
relative_to_index = @user.index
elsif GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
relative_to_index = target_idx
end
if relative_to_index >= 0 && relative_to_index.odd? && particle[:focus] != :user_and_target
particle_sprite.foe_invert_x = particle[:foe_invert_x]
particle_sprite.foe_invert_y = particle[:foe_invert_y]
end
# Find earliest command and add a "make visible" command then
if sprite && !particle_sprite.battler_sprite?
first_cmd = -1

View File

@@ -5,6 +5,7 @@
class AnimationPlayer::ParticleSprite
attr_accessor :sprite
attr_accessor :focus_xy, :offset_xy, :focus_z
attr_accessor :foe_invert_x, :foe_invert_y
FRAMES_PER_SECOND = 20.0
@@ -98,10 +99,14 @@ class AnimationPlayer::ParticleSprite
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)
value = value.round
value *= -1 if @foe_invert_x
AnimationPlayer::Helper.apply_xy_focus_to_sprite(@sprite, :x, value, @focus_xy)
@sprite.x += @offset_xy[0]
when :y
AnimationPlayer::Helper.apply_xy_focus_to_sprite(@sprite, :y, value.round, @focus_xy)
value = value.round
value *= -1 if @foe_invert_y
AnimationPlayer::Helper.apply_xy_focus_to_sprite(@sprite, :y, value, @focus_xy)
@sprite.y += @offset_xy[1]
when :z
AnimationPlayer::Helper.apply_z_focus_to_sprite(@sprite, value, @focus_z)

View File

@@ -2,7 +2,8 @@
#
#===============================================================================
class Battle::Scene
BETTER_ANIMATION_DEFAULTS = {
ANIMATION_DEFAULTS = [:TACKLE, :DEFENSECURL] # With target, without target
ANIMATION_DEFAULTS_FOR_TYPE_CATEGORY = {
:NORMAL => [:TACKLE, :SONICBOOM, :DEFENSECURL, :EXPLOSION, :SWIFT, :TAILWHIP],
:FIGHTING => [:MACHPUNCH, :AURASPHERE, :BULKUP, nil, nil, nil],
:FLYING => [:WINGATTACK, :GUST, :ROOST, nil, :AIRCUTTER, :FEATHERDANCE],
@@ -73,20 +74,24 @@ class Battle::Scene
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
default_idx += 3 if target_data.num_targets > 1 ||
(target_data.num_targets > 0 && move_data.status?) ||
target_data.affects_foe_side
# Check for a default animation
wanted_move = BETTER_ANIMATION_DEFAULTS[move_type][default_idx]
wanted_move = ANIMATION_DEFAULTS_FOR_TYPE_CATEGORY[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]
wanted_move = ANIMATION_DEFAULTS_FOR_TYPE_CATEGORY[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
return nil if ANIMATION_DEFAULTS.include?(wanted_move) # No need to check for these animations twice
end
# Use Tackle's animation
return find_move_animation_for_move(:TACKLE, 0, user_index)
# Use Tackle or Defense Curl's animation
if target_data.num_targets == 0 && target.data.id != :None
return find_move_animation_for_move(ANIMATION_DEFAULTS[1], 0, user_index)
end
return find_move_animation_for_move(ANIMATION_DEFAULTS[0], 0, user_index)
end
# Find an animation(s) for the given move_id.

View File

@@ -1,6 +1,3 @@
# TODO: Hardcoded animations have incorrect z values because of the change to
# other sprites' z values.
#===============================================================================
#
#===============================================================================