Anim Editor: polishing, refactoring, ensuring data

This commit is contained in:
Maruno17
2024-03-25 22:08:11 +00:00
parent 8a218ca834
commit 323b62b7d5
7 changed files with 336 additions and 176 deletions

View File

@@ -33,6 +33,14 @@ class UIControls::Scrollbar < UIControls::BaseControl
return (@range - @tray_size) * @slider_top / (@tray_size - @slider_size)
end
def minimum?
return @slider_top <= 0
end
def maximum?
return @slider_top >= @tray_size - @slider_size
end
# Range is the total size of the large area that the scrollbar is able to
# show part of.
def range=(new_val)

View File

@@ -47,7 +47,7 @@ module Compiler
elsif line[/^\s*(\w+)\s*=\s*(.*)$/]
# XXX=YYY lines
if !data_hash
raise _INTL("Expected a section at the beginning of the file.\n{1}", FileLineData.linereport)
raise _INTL("Expected a section at the beginning of the file.") + "\n" + FileLineData.linereport
end
key = $~[1]
if schema[key] # Property of the animation
@@ -62,7 +62,7 @@ module Compiler
end
elsif sub_schema[key] # Property of a particle
if !current_particle
raise _INTL("Particle hasn't been defined yet!\n{1}", FileLineData.linereport)
raise _INTL("Particle hasn't been defined yet!") + "\n" + FileLineData.linereport
end
value = get_csv_record($~[2], sub_schema[key])
if sub_schema[key][1][0] == "^"
@@ -154,20 +154,51 @@ module Compiler
when "Target" then particle[:graphic] = "TARGET"
end
end
# Ensure that particles don't have a focus involving a user if the
# animation itself doesn't involve a user
if hash[:no_user] && GameData::Animation::FOCUS_TYPES_WITH_USER.include?(particle[:focus])
# Ensure that particles don't have a focus involving a user, and the
# animation doesn't play a user's cry, if the animation itself doesn't
# involve a user
if hash[:no_user]
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(particle[:focus])
raise _INTL("Particle \"{1}\" can't have a \"Focus\" that involves a user if property \"NoUser\" is set to true.",
particle[:name]) + "\n" + FileLineData.linereport
end
# Ensure that particles don't have a focus involving a target if the
# animation itself doesn't involve a target
if hash[:no_target] && GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
if particle[:name] == "SE" && particle[:user_cry] && !particle[:user_cry].empty?
raise _INTL("Animation can't play the user's cry if property \"NoUser\" is set to true.") + "\n" + FileLineData.linereport
end
end
# Ensure that particles don't have a focus involving a target, and the
# animation doesn't play a target's cry, if the animation itself doesn't
# involve a target
if hash[:no_target]
if GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
raise _INTL("Particle \"{1}\" can't have a \"Focus\" that involves a target if property \"NoTarget\" is set to true.",
particle[:name]) + "\n" + FileLineData.linereport
end
# TODO: For SE particle, ensure that it doesn't play two instances of the
# same file in the same frame.
if particle[:name] == "SE" && particle[:target_cry] && !particle[:target_cry].empty?
raise _INTL("Animation can't play the target's cry if property \"NoTarget\" is set to true.") + "\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|
next if !particle[property]
files_played = []
particle[property].each do |play|
files_played[play[0]] ||= []
if files_played[play[0]].include?(play[1])
case property
when :se
raise _INTL("SE \"{1}\" should not play twice in the same frame ({2}).", play[1], play[0]) + "\n" + FileLineData.linereport
when :user_cry
raise _INTL("User's cry should not play twice in the same frame ({1}).", play[0]) + "\n" + FileLineData.linereport
when :target_cry
raise _INTL("Target's cry should not play twice in the same frame ({1}).", play[0]) + "\n" + FileLineData.linereport
end
end
files_played[play[0]].push(play[1])
end
end
end
# Convert all "SetXYZ" particle commands to "MoveXYZ" by giving them a
# duration of 0 (even ones that can't have a "MoveXYZ" command)
GameData::Animation::PARTICLE_KEYFRAME_DEFAULT_VALUES.keys.each do |prop|
@@ -293,6 +324,7 @@ module Compiler
rescue SystemCallError
end
raise Reset.new if e.is_a?(Hangup)
raise SystemExit.new if e.is_a?(RuntimeError)
raise "Unknown exception when compiling animations."
end
end

View File

@@ -711,7 +711,7 @@ class AnimationEditor
# Disable the "move particle up/down" buttons if the selected particle
# can't move that way (or there is no selected particle)
cur_index = particle_index
if cur_index < 1
if cur_index < 1 || @anim[:particles][cur_index][:name] == "SE"
component.get_control(:move_particle_up).disable
else
component.get_control(:move_particle_up).enable
@@ -847,12 +847,14 @@ class AnimationEditor
end
when :duplicate
AnimationEditor::ParticleDataHelper.duplicate_particle(@anim[:particles], particle_index)
@components[:particle_list].add_particle(particle_index + 1)
@components[:particle_list].set_particles(@anim[:particles])
@components[:particle_list].particle_index = particle_index + 1
refresh
when :delete
if confirm_message(_INTL("Are you sure you want to delete this particle?"))
AnimationEditor::ParticleDataHelper.delete_particle(@anim[:particles], particle_index)
@components[:particle_list].delete_particle(particle_index)
@components[:particle_list].set_particles(@anim[:particles])
@components[:particle_list].keyframe = 0 if @anim[:particles][particle_index][:name] == "SE"
refresh
@@ -875,6 +877,7 @@ class AnimationEditor
new_idx = @anim[:particles].length - 1 if new_idx == 0 || new_idx >= @anim[:particles].length
end
AnimationEditor::ParticleDataHelper.add_particle(@anim[:particles], new_idx)
@components[:particle_list].add_particle(new_idx)
@components[:particle_list].set_particles(@anim[:particles])
@components[:particle_list].particle_index = (new_idx >= 0) ? new_idx : @anim[:particles].length - 2
@components[:particle_list].keyframe = -1
@@ -883,6 +886,7 @@ class AnimationEditor
idx1 = particle_index
idx2 = idx1 - 1
AnimationEditor::ParticleDataHelper.swap_particles(@anim[:particles], idx1, idx2)
@components[:particle_list].swap_particles(idx1, idx2)
@components[:particle_list].set_particles(@anim[:particles])
@components[:particle_list].particle_index = idx2
refresh
@@ -890,6 +894,7 @@ class AnimationEditor
idx1 = particle_index
idx2 = idx1 + 1
AnimationEditor::ParticleDataHelper.swap_particles(@anim[:particles], idx1, idx2)
@components[:particle_list].swap_particles(idx1, idx2)
@components[:particle_list].set_particles(@anim[:particles])
@components[:particle_list].particle_index = idx2
refresh
@@ -932,16 +937,48 @@ class AnimationEditor
@anim[property] = txt
when :has_user
@anim[:no_user] = !value
# TODO: Add/delete the "User" particle accordingly, and change the foci
# of any other particle involving a user. Then refresh a lot of
# components.
refresh_component(:canvas)
if @anim[:no_user]
@anim[:particles].delete_if { |particle| particle[:name] == "User" }
@anim[:particles].each do |particle|
if ["USER", "USER_OPP", "USER_FRONT", "USER_BACK"].include?(particle[:graphic])
particle[:graphic] = GameData::Animation::PARTICLE_DEFAULT_VALUES[:graphic]
end
if GameData::Animation::FOCUS_TYPES_WITH_USER.include?(particle[:focus])
particle[:focus] = GameData::Animation::PARTICLE_DEFAULT_VALUES[:focus]
end
particle[:user_cry] = nil if particle[:name] == "SE"
end
@components[:particle_list].delete_particle(0)
elsif @anim[:particles].none? { |particle| particle[:name] == "User" }
@anim[:particles].insert(0, {
:name => "User", :focus => :user, :graphic => "USER"
})
@components[:particle_list].add_particle(0)
end
@components[:particle_list].set_particles(@anim[:particles])
refresh
when :has_target
@anim[:no_target] = !value
# TODO: Add/delete the "Target" particle accordingly, and change the
# foci of any other particle involving a target. Then refresh a
# lot of components.
refresh_component(:canvas)
if @anim[:no_target]
@anim[:particles].delete_if { |particle| particle[:name] == "Target" }
@anim[:particles].each do |particle|
if ["TARGET", "TARGET_OPP", "TARGET_FRONT", "TARGET_BACK"].include?(particle[:graphic])
particle[:graphic] = GameData::Animation::PARTICLE_DEFAULT_VALUES[:graphic]
end
if GameData::Animation::FOCUS_TYPES_WITH_TARGET.include?(particle[:focus])
particle[:focus] = GameData::Animation::PARTICLE_DEFAULT_VALUES[:focus]
end
particle[:target_cry] = nil if particle[:name] == "SE"
end
@components[:particle_list].delete_particle(@anim[:no_user] ? 0 : 1)
elsif @anim[:particles].none? { |particle| particle[:name] == "Target" }
@anim[:particles].insert((@anim[:no_user] ? 0 : 1), {
:name => "Target", :focus => :target, :graphic => "TARGET"
})
@components[:particle_list].add_particle((@anim[:no_user] ? 0 : 1))
end
@components[:particle_list].set_particles(@anim[:particles])
refresh
when :usable
@anim[:ignore] = !value
else

View File

@@ -321,25 +321,25 @@ class AnimationEditor::Canvas < Sprite
spr.bitmap = @user_bitmap_back
when "TARGET"
if target_idx < 0
raise _INTL("Particle {1} was given a graphic of \"TARGET\" but its focus doesn't include a target.",
raise _INTL("Particle \"{1}\" was given a graphic of \"TARGET\" but its focus doesn't include a target.",
particle[:name])
end
spr.bitmap = (target_idx.even?) ? @target_bitmap_back : @target_bitmap_front
when "TARGET_OPP"
if target_idx < 0
raise _INTL("Particle {1} was given a graphic of \"TARGET_OPP\" but its focus doesn't include a target.",
raise _INTL("Particle \"{1}\" was given a graphic of \"TARGET_OPP\" but its focus doesn't include a target.",
particle[:name])
end
spr.bitmap = (target_idx.even?) ? @target_bitmap_front : @target_bitmap_back
when "TARGET_FRONT"
if target_idx < 0
raise _INTL("Particle {1} was given a graphic of \"TARGET_FRONT\" but its focus doesn't include a target.",
raise _INTL("Particle \"{1}\" was given a graphic of \"TARGET_FRONT\" but its focus doesn't include a target.",
particle[:name])
end
spr.bitmap = @target_bitmap_front
when "TARGET_BACK"
if target_idx < 0
raise _INTL("Particle {1} was given a graphic of \"TARGET_BACK\" but its focus doesn't include a target.",
raise _INTL("Particle \"{1}\" was given a graphic of \"TARGET_BACK\" but its focus doesn't include a target.",
particle[:name])
end
spr.bitmap = @target_bitmap_back

View File

@@ -1,6 +1,5 @@
#===============================================================================
# TODO: The Add/Up/Down buttons don't get captured, and don't prevent anything
# else in this control highlighting when hovered over, and vice versa.
#
#===============================================================================
class AnimationEditor::ParticleList < UIControls::BaseControl
VIEWPORT_SPACING = 1
@@ -48,66 +47,11 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
self.x = x
self.y = y
draw_control_background
# Create viewports
@list_viewport = Viewport.new(
x + LIST_X, y + LIST_Y, LIST_WIDTH, height - LIST_Y - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING
)
@list_viewport.z = self.viewport.z + 1
@commands_bg_viewport = Viewport.new(
x + COMMANDS_X, y + COMMANDS_Y,
width - COMMANDS_X - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING, @list_viewport.rect.height
)
@commands_bg_viewport.z = self.viewport.z + 1
@position_viewport = Viewport.new(@commands_bg_viewport.rect.x, y, @commands_bg_viewport.rect.width, height)
@position_viewport.z = self.viewport.z + 2
@commands_viewport = Viewport.new(@commands_bg_viewport.rect.x, @commands_bg_viewport.rect.y,
@commands_bg_viewport.rect.width, @commands_bg_viewport.rect.height)
@commands_viewport.z = self.viewport.z + 3
# Create scrollbars
@list_scrollbar = UIControls::Scrollbar.new(
x + width - UIControls::Scrollbar::SLIDER_WIDTH, @commands_bg_viewport.rect.y,
@commands_bg_viewport.rect.height, self.viewport, false, true
)
@list_scrollbar.set_interactive_rects
@time_scrollbar = UIControls::Scrollbar.new(
@commands_bg_viewport.rect.x, y + height - UIControls::Scrollbar::SLIDER_WIDTH,
@commands_bg_viewport.rect.width, self.viewport, true, true
)
@time_scrollbar.set_interactive_rects
# Time background bitmap sprite
@time_bg_sprite = BitmapSprite.new(
@commands_viewport.rect.width,
TIMELINE_HEIGHT + VIEWPORT_SPACING + @list_viewport.rect.height, self.viewport
)
@time_bg_sprite.x = @commands_viewport.rect.x
@time_bg_sprite.y = self.y
# Timeline bitmap sprite
@timeline_sprite = BitmapSprite.new(@commands_viewport.rect.width, TIMELINE_HEIGHT, self.viewport)
@timeline_sprite.x = @commands_viewport.rect.x
@timeline_sprite.y = self.y
@timeline_sprite.bitmap.font.color = TEXT_COLOR
@timeline_sprite.bitmap.font.size = TIMELINE_TEXT_SIZE
# Position line sprite
@position_sprite = BitmapSprite.new(3, height - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING, @position_viewport)
@position_sprite.ox = @position_sprite.width / 2
@position_sprite.bitmap.fill_rect(0, 0, @position_sprite.bitmap.width, @position_sprite.bitmap.height, Color.red)
# Selected particle line sprite
@particle_line_sprite = BitmapSprite.new(@position_viewport.rect.width, 3, @commands_viewport)
@particle_line_sprite.z = -10
@particle_line_sprite.oy = @particle_line_sprite.height / 2
@particle_line_sprite.bitmap.fill_rect(0, 0, @particle_line_sprite.bitmap.width, @particle_line_sprite.bitmap.height, Color.red)
# Buttons and button bitmaps
initialize_button_bitmaps
@controls = []
add_particle_button = UIControls::BitmapButton.new(x + 1, y + 1, viewport, @add_button_bitmap)
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.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.set_interactive_rects
@controls.push([:move_particle_down, down_particle_button])
initialize_viewports
initialize_scrollbars
initialize_timeline_bitmaps
initialize_selection_bitmaps
initialize_controls
# List sprites and commands sprites
@list_sprites = []
@commands_bg_sprites = []
@@ -127,7 +71,81 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
@commands = {}
end
def initialize_button_bitmaps
def initialize_viewports
@list_viewport = Viewport.new(
x + LIST_X, y + LIST_Y, LIST_WIDTH, height - LIST_Y - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING
)
@list_viewport.z = self.viewport.z + 1
@commands_bg_viewport = Viewport.new(
x + COMMANDS_X, y + COMMANDS_Y,
width - COMMANDS_X - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING, @list_viewport.rect.height
)
@commands_bg_viewport.z = self.viewport.z + 1
@position_viewport = Viewport.new(@commands_bg_viewport.rect.x, y, @commands_bg_viewport.rect.width, height)
@position_viewport.z = self.viewport.z + 2
@commands_viewport = Viewport.new(@commands_bg_viewport.rect.x, @commands_bg_viewport.rect.y,
@commands_bg_viewport.rect.width, @commands_bg_viewport.rect.height)
@commands_viewport.z = self.viewport.z + 3
end
def initialize_scrollbars
# Vertical scrollbar
@list_scrollbar = UIControls::Scrollbar.new(
x + width - UIControls::Scrollbar::SLIDER_WIDTH, @commands_bg_viewport.rect.y,
@commands_bg_viewport.rect.height, self.viewport, false, true
)
@list_scrollbar.set_interactive_rects
# Horizontal scrollbar
@time_scrollbar = UIControls::Scrollbar.new(
@commands_bg_viewport.rect.x, y + height - UIControls::Scrollbar::SLIDER_WIDTH,
@commands_bg_viewport.rect.width, self.viewport, true, true
)
@time_scrollbar.set_interactive_rects
end
def initialize_timeline_bitmaps
# Time background bitmap sprite
@time_bg_sprite = BitmapSprite.new(
@commands_viewport.rect.width,
TIMELINE_HEIGHT + VIEWPORT_SPACING + @list_viewport.rect.height, self.viewport
)
@time_bg_sprite.x = @commands_viewport.rect.x
@time_bg_sprite.y = self.y
# Timeline bitmap sprite
@timeline_sprite = BitmapSprite.new(@commands_viewport.rect.width, TIMELINE_HEIGHT, self.viewport)
@timeline_sprite.x = @commands_viewport.rect.x
@timeline_sprite.y = self.y
@timeline_sprite.bitmap.font.color = TEXT_COLOR
@timeline_sprite.bitmap.font.size = TIMELINE_TEXT_SIZE
end
def initialize_selection_bitmaps
# Position line sprite
@position_sprite = BitmapSprite.new(3, height - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING, @position_viewport)
@position_sprite.ox = @position_sprite.width / 2
@position_sprite.bitmap.fill_rect(0, 0, @position_sprite.bitmap.width, @position_sprite.bitmap.height, Color.red)
# Selected particle line sprite
@particle_line_sprite = BitmapSprite.new(@position_viewport.rect.width, 3, @commands_viewport)
@particle_line_sprite.z = -10
@particle_line_sprite.oy = @particle_line_sprite.height / 2
@particle_line_sprite.bitmap.fill_rect(0, 0, @particle_line_sprite.bitmap.width, @particle_line_sprite.bitmap.height, Color.red)
end
def initialize_controls
generate_button_bitmaps
@controls = []
add_particle_button = UIControls::BitmapButton.new(x + 1, y + 1, viewport, @add_button_bitmap)
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.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.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)
@@ -143,24 +161,6 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
end
end
def draw_control_background
self.bitmap.clear
# Separator lines
self.bitmap.fill_rect(0, TIMELINE_HEIGHT, width, VIEWPORT_SPACING, Color.black)
self.bitmap.fill_rect(LIST_WIDTH, 0, VIEWPORT_SPACING, height, Color.black)
self.bitmap.fill_rect(0, height - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING, width, VIEWPORT_SPACING, Color.black)
self.bitmap.fill_rect(width - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING, 0, VIEWPORT_SPACING, height, Color.black)
end
def dispose_listed_sprites
@list_sprites.each { |p| p&.dispose }
@list_sprites.clear
@commands_bg_sprites.each { |p| p&.dispose }
@commands_bg_sprites.clear
@commands_sprites.each { |p| p&.dispose }
@commands_sprites.clear
end
def dispose
@list_scrollbar.dispose
@time_scrollbar.dispose
@@ -179,6 +179,17 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
@commands_viewport.dispose
end
def dispose_listed_sprites
@list_sprites.each { |p| p&.dispose }
@list_sprites.clear
@commands_bg_sprites.each { |p| p&.dispose }
@commands_bg_sprites.clear
@commands_sprites.each { |p| p&.dispose }
@commands_sprites.clear
end
#-----------------------------------------------------------------------------
def duration
return [@duration - DURATION_BUFFER, 0].max
end
@@ -236,6 +247,71 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
end
end
def scroll_to_row(new_row)
if new_row * ROW_HEIGHT < @top_pos
# Scroll up
new_pos = new_row * ROW_HEIGHT
loop do
@list_scrollbar.slider_top -= 1
break if @list_scrollbar.position <= new_pos || @list_scrollbar.minimum?
end
elsif new_row * ROW_HEIGHT > @top_pos + @list_viewport.rect.height - ROW_HEIGHT
# Scroll down
new_pos = (new_row * ROW_HEIGHT) - @list_viewport.rect.height + ROW_HEIGHT
loop do
@list_scrollbar.slider_top += 1
break if @list_scrollbar.position >= new_pos || @list_scrollbar.maximum?
end
end
end
def scroll_to_keyframe(new_keyframe)
if TIMELINE_LEFT_BUFFER + (new_keyframe * KEYFRAME_SPACING) - (KEYFRAME_SPACING / 2) < @left_pos
# Scroll left
new_pos = TIMELINE_LEFT_BUFFER + (new_keyframe * KEYFRAME_SPACING) - (KEYFRAME_SPACING / 2)
loop do
@time_scrollbar.slider_top -= 1
break if @time_scrollbar.position <= new_pos || @time_scrollbar.minimum?
end
elsif TIMELINE_LEFT_BUFFER + (new_keyframe * KEYFRAME_SPACING) + (KEYFRAME_SPACING / 2) > @left_pos + @commands_bg_viewport.rect.width
# Scroll right
new_pos = TIMELINE_LEFT_BUFFER + (new_keyframe * KEYFRAME_SPACING) + (KEYFRAME_SPACING / 2) - @commands_bg_viewport.rect.width
loop do
@time_scrollbar.slider_top += 1
break if @time_scrollbar.position >= new_pos || @time_scrollbar.maximum?
end
end
end
# Ensures that the array of which particle rows have been expanded ends up
# with the same particles having expanded rows after adding a particle.
def add_particle(index)
@expanded_particles.each_with_index do |idx, i|
@expanded_particles[i] += 1 if idx >= index
end
end
# Ensures that the array of which particle rows have been expanded ends up
# with the same particles having expanded rows after deleting a particle.
def delete_particle(index)
@expanded_particles.delete(index)
@expanded_particles.each_with_index do |idx, i|
@expanded_particles[i] -= 1 if idx > index
end
end
# Ensures that the array of which particle rows have been expanded ends up
# with the same particles having expanded rows after the swap.
def swap_particles(idx1, idx2)
if @expanded_particles.include?(idx1) && !@expanded_particles.include?(idx2)
@expanded_particles.delete(idx1)
@expanded_particles.push(idx2)
elsif @expanded_particles.include?(idx2) && !@expanded_particles.include?(idx1)
@expanded_particles.delete(idx2)
@expanded_particles.push(idx1)
end
end
def set_particles(particles)
@particles = particles
calculate_all_commands_and_durations
@@ -449,9 +525,6 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
invalidate_rows
end
# TODO: Methods that will show/hide individual property rows for a given
# @particles index.
#-----------------------------------------------------------------------------
def each_visible_keyframe(early_start = false)
@@ -478,6 +551,17 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
#-----------------------------------------------------------------------------
def draw_control_background
self.bitmap.clear
# Separator lines
self.bitmap.fill_rect(0, TIMELINE_HEIGHT, width, VIEWPORT_SPACING, Color.black)
self.bitmap.fill_rect(LIST_WIDTH, 0, VIEWPORT_SPACING, height, Color.black)
self.bitmap.fill_rect(0, height - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING, width, VIEWPORT_SPACING, Color.black)
self.bitmap.fill_rect(width - UIControls::Scrollbar::SLIDER_WIDTH - VIEWPORT_SPACING, 0, VIEWPORT_SPACING, height, Color.black)
end
#-----------------------------------------------------------------------------
def repaint
@list_scrollbar.repaint if @list_scrollbar.invalid?
@time_scrollbar.repaint if @time_scrollbar.invalid?
@@ -850,14 +934,16 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
else
case @captured_row_button
when :expand
particle_index = @particle_list[@captured_row]
particle_index = particle_index[0] if particle_index.is_a?(Array)
if @expanded_particles.include?(particle_index) # Contract
@expanded_particles.delete(particle_index)
old_row_idx_particle = @particle_list[@row_index]
idx_particle = @particle_list[@captured_row]
idx_particle = idx_particle[0] if idx_particle.is_a?(Array)
if @expanded_particles.include?(idx_particle) # Contract
@expanded_particles.delete(idx_particle)
else # Expand
@expanded_particles.push(particle_index)
@expanded_particles.push(idx_particle)
end
set_particles(@particles)
@row_index = @particle_list.index(old_row_idx_particle)
else # :row button or somewhere in the commands area or timeline, just change selection
if @captured_row && @particle_list[@captured_row].is_a?(Array)
@captured_row = @particle_list.index(@particle_list[@captured_row][0])
@@ -877,11 +963,6 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
super # Make this control not busy again
end
def on_right_mouse_release
# TODO: Toggle interpolation line at mouse's position. Should this also have
# a def on_right_mouse_press and @right_captured_whatever?
end
def update_hover_highlight
# Remove the hover highlight if there are no interactions for this control
# or if the mouse is off-screen
@@ -938,62 +1019,42 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
end
end
def update
return if !self.visible
@list_scrollbar.update
@time_scrollbar.update
if !@captured_area
@controls.each { |c| c[1].update }
end
super
# Refresh sprites if a scrollbar has been moved
self.top_pos = @list_scrollbar.position
self.left_pos = @time_scrollbar.position
# Update the current keyframe line's position
refresh_position_line
# Update the selected particle line's position
refresh_particle_line
# Add/move particle buttons
@controls.each do |c|
next if !c[1].changed?
set_changed
@values[c[0]] = true
c[1].clear_changed
end
if Input.release?(Input::MOUSERIGHT)
on_right_mouse_release
end
# TODO: This is testing code, and should be replaced by clicking on the
# timeline or a command sprite. Maybe keep it after all? If so,
# probably change left/right to <>, and also move the scrollbar(s) to
# keep the "cursor" on-screen.
def update_input
# Left/right to change current keyframe
if Input.repeat?(Input::LEFT)
if @keyframe > 0
@keyframe -= 1
scroll_to_keyframe(@keyframe)
set_changed
end
elsif Input.repeat?(Input::RIGHT)
if @keyframe < @duration - 1
@keyframe += 1
scroll_to_keyframe(@keyframe)
set_changed
end
end
# Up/down to change selected particle
if Input.repeat?(Input::UP)
if @row_index > 0
loop do
@row_index -= 1
break if !@particle_list[@row_index].is_a?(Array)
end
scroll_to_row(@row_index)
set_changed
end
elsif Input.repeat?(Input::DOWN)
if @row_index < @particle_list.length - 1
loop do
@row_index += 1
break if !@particle_list[@row_index].is_a?(Array)
end
@keyframe = 0 if @row_index >= @particle_list.length - 1 && @keyframe < 0
scroll_to_row(@row_index)
set_changed
end
# TODO: If this is to be kept, @row_index should be changed by potentially
# more than 1, so that @particle_list[@row_index] is an integer and
# not an array.
# elsif Input.repeat?(Input::UP)
# if @row_index > 0
# @row_index -= 1
# set_changed
# end
# elsif Input.repeat?(Input::DOWN)
# if @row_index < @particles.length - 1
# @row_index += 1
# set_changed
# end
end
# Mouse scroll wheel
mouse_x, mouse_y = mouse_pos
if mouse_x && mouse_y
@@ -1009,6 +1070,30 @@ class AnimationEditor::ParticleList < UIControls::BaseControl
end
end
end
end
def update
return if !self.visible
@list_scrollbar.update
@time_scrollbar.update
if !@captured_area
@controls.each { |c| c[1].update }
end
super
# Refresh sprites if a scrollbar has been moved
self.top_pos = @list_scrollbar.position
self.left_pos = @time_scrollbar.position
# Update the positions of the selected particle/keyframe lines
refresh_position_line
refresh_particle_line
# Add/move particle buttons
@controls.each do |c|
next if !c[1].changed?
set_changed
@values[c[0]] = true
c[1].clear_changed
end
# Up/down/left/right navigation, and mouse scroll wheel
update_input
end
end

View File

@@ -236,7 +236,6 @@ Name = ABSORB
SetY = 12,-50
SetVisible = 13,false
<SE>
Play = 0,Absorb2,80
Play = 0,Absorb2,80
Play = 2,Absorb2,80
Play = 5,Absorb2,80

View File

@@ -166,5 +166,4 @@ Name = MAGICCOAT
SetVisible = 9,false
<SE>
Play = 0,Sword2,80
Play = 0,Sword2,80,101
Play = 4,Sword2,80