mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
Anim Editor: improved NumberTextBox entry, added "FoeInvertX/Y" particle properties, tidied up
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
# TODO: Add indicator of whether the control's value is "lerping" between frames
|
||||
# (use yellow somehow?).
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,26 +54,18 @@ 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.
|
||||
|
||||
"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"
|
||||
@@ -115,25 +105,17 @@ module GameData
|
||||
"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.
|
||||
|
||||
# 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
|
||||
: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,
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# TODO: Hardcoded animations have incorrect z values because of the change to
|
||||
# other sprites' z values.
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
Reference in New Issue
Block a user