diff --git a/Data/Scripts/801_UI controls/Control elements/001_BaseControl.rb b/Data/Scripts/801_UI controls/Control elements/001_BaseControl.rb index f6587a642..f60962048 100644 --- a/Data/Scripts/801_UI controls/Control elements/001_BaseControl.rb +++ b/Data/Scripts/801_UI controls/Control elements/001_BaseControl.rb @@ -1,6 +1,3 @@ -# TODO: Add indicator of whether the control's value is "lerping" between frames -# (use yellow somehow?). - #=============================================================================== # #=============================================================================== diff --git a/Data/Scripts/801_UI controls/Control elements/004_TextBox.rb b/Data/Scripts/801_UI controls/Control elements/004_TextBox.rb index 940e68cfa..fb2e3a227 100644 --- a/Data/Scripts/801_UI controls/Control elements/004_TextBox.rb +++ b/Data/Scripts/801_UI controls/Control elements/004_TextBox.rb @@ -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 diff --git a/Data/Scripts/801_UI controls/Control elements/006_NumberTextBox.rb b/Data/Scripts/801_UI controls/Control elements/006_NumberTextBox.rb index a4886bd43..de62d92f6 100644 --- a/Data/Scripts/801_UI controls/Control elements/006_NumberTextBox.rb +++ b/Data/Scripts/801_UI controls/Control elements/006_NumberTextBox.rb @@ -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 diff --git a/Data/Scripts/801_UI controls/Control elements/007_Button.rb b/Data/Scripts/801_UI controls/Control elements/007_Button.rb index 938dbbf54..ffdc8dbfc 100644 --- a/Data/Scripts/801_UI controls/Control elements/007_Button.rb +++ b/Data/Scripts/801_UI controls/Control elements/007_Button.rb @@ -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 diff --git a/Data/Scripts/902_Anim GameData/001_Animation.rb b/Data/Scripts/902_Anim GameData/001_Animation.rb index d73daed83..de7e4ec70 100644 --- a/Data/Scripts/902_Anim GameData/001_Animation.rb +++ b/Data/Scripts/902_Anim GameData/001_Animation.rb @@ -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 } # 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, diff --git a/Data/Scripts/903_Anim Compiler/001_Anim compiler.rb b/Data/Scripts/903_Anim Compiler/001_Anim compiler.rb index ab2f6fe5f..e5ba0189b 100644 --- a/Data/Scripts/903_Anim Compiler/001_Anim compiler.rb +++ b/Data/Scripts/903_Anim Compiler/001_Anim compiler.rb @@ -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| diff --git a/Data/Scripts/903_Anim Compiler/100_convert old anims to new.rb b/Data/Scripts/903_Anim Compiler/100_convert old anims to new.rb index 5f319fd4b..66439ef25 100644 --- a/Data/Scripts/903_Anim Compiler/100_convert old anims to new.rb +++ b/Data/Scripts/903_Anim Compiler/100_convert old anims to new.rb @@ -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 } diff --git a/Data/Scripts/904_Anim Editor/001_AnimationEditor.rb b/Data/Scripts/904_Anim Editor/001_AnimationEditor.rb index 43abb48a7..3fd4000b5 100644 --- a/Data/Scripts/904_Anim Editor/001_AnimationEditor.rb +++ b/Data/Scripts/904_Anim Editor/001_AnimationEditor.rb @@ -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| diff --git a/Data/Scripts/904_Anim Editor/002_AnimationEditor_popups.rb b/Data/Scripts/904_Anim Editor/002_AnimationEditor_popups.rb index 903e5ea1a..d94e6be61 100644 --- a/Data/Scripts/904_Anim Editor/002_AnimationEditor_popups.rb +++ b/Data/Scripts/904_Anim Editor/002_AnimationEditor_popups.rb @@ -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 diff --git a/Data/Scripts/904_Anim Editor/003_AnimationEditor_side_panes.rb b/Data/Scripts/904_Anim Editor/003_AnimationEditor_side_panes.rb index 84691d0ce..02cdfb481 100644 --- a/Data/Scripts/904_Anim Editor/003_AnimationEditor_side_panes.rb +++ b/Data/Scripts/904_Anim Editor/003_AnimationEditor_side_panes.rb @@ -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). diff --git a/Data/Scripts/904_Anim Editor/901_ParticleDataHelper.rb b/Data/Scripts/904_Anim Editor/901_ParticleDataHelper.rb index c2f27855e..4867bbe26 100644 --- a/Data/Scripts/904_Anim Editor/901_ParticleDataHelper.rb +++ b/Data/Scripts/904_Anim Editor/901_ParticleDataHelper.rb @@ -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 diff --git a/Data/Scripts/904_Anim Editor/Anim Editor elements/001_Canvas.rb b/Data/Scripts/904_Anim Editor/Anim Editor elements/001_Canvas.rb index 4dd3b9905..70bb97c5f 100644 --- a/Data/Scripts/904_Anim Editor/Anim Editor elements/001_Canvas.rb +++ b/Data/Scripts/904_Anim Editor/Anim Editor elements/001_Canvas.rb @@ -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 diff --git a/Data/Scripts/904_Anim Editor/Anim Editor elements/002_PlayControls.rb b/Data/Scripts/904_Anim Editor/Anim Editor elements/002_PlayControls.rb index 5f214a495..ffef45cd4 100644 --- a/Data/Scripts/904_Anim Editor/Anim Editor elements/002_PlayControls.rb +++ b/Data/Scripts/904_Anim Editor/Anim Editor elements/002_PlayControls.rb @@ -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) diff --git a/Data/Scripts/904_Anim Editor/Anim Editor elements/003_ParticleList.rb b/Data/Scripts/904_Anim Editor/Anim Editor elements/003_ParticleList.rb index ee485ab10..e38ccd6a3 100644 --- a/Data/Scripts/904_Anim Editor/Anim Editor elements/003_ParticleList.rb +++ b/Data/Scripts/904_Anim Editor/Anim Editor elements/003_ParticleList.rb @@ -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 diff --git a/Data/Scripts/905_Anim player/001_Anim player.rb b/Data/Scripts/905_Anim player/001_Anim player.rb index a95a78d10..ae9d7b67e 100644 --- a/Data/Scripts/905_Anim player/001_Anim player.rb +++ b/Data/Scripts/905_Anim player/001_Anim player.rb @@ -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 diff --git a/Data/Scripts/905_Anim player/002_ParticleSprite.rb b/Data/Scripts/905_Anim player/002_ParticleSprite.rb index a1f23377d..90b7b3160 100644 --- a/Data/Scripts/905_Anim player/002_ParticleSprite.rb +++ b/Data/Scripts/905_Anim player/002_ParticleSprite.rb @@ -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) diff --git a/Data/Scripts/905_Anim player/010_Battle code.rb b/Data/Scripts/905_Anim player/010_Battle code.rb index 482dba8bb..bfdd765aa 100644 --- a/Data/Scripts/905_Anim player/010_Battle code.rb +++ b/Data/Scripts/905_Anim player/010_Battle code.rb @@ -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. diff --git a/Data/Scripts/905_Anim player/011_Battle z modifiers.rb b/Data/Scripts/905_Anim player/011_Battle z modifiers.rb index f82bc946e..6e036e782 100644 --- a/Data/Scripts/905_Anim player/011_Battle z modifiers.rb +++ b/Data/Scripts/905_Anim player/011_Battle z modifiers.rb @@ -1,6 +1,3 @@ -# TODO: Hardcoded animations have incorrect z values because of the change to -# other sprites' z values. - #=============================================================================== # #===============================================================================