From 3a9199da1ba9481bfc6f98d422e5d5374a839941 Mon Sep 17 00:00:00 2001 From: Maruno17 Date: Mon, 6 Mar 2023 22:25:45 +0000 Subject: [PATCH] Refactored animation editor code into a single module --- .../001_Technical/002_RubyUtilities.rb | 10 + .../002_PBS data/020_DungeonParameters.rb | 2 +- .../001_AnimEditor_SceneElements.rb | 1858 +++++++------- .../002_AnimEditor_ControlsButtons.rb | 1781 ++++++------- .../003_AnimEditor_Interpolation.rb | 794 +++--- .../004_AnimEditor_ExportImport.rb | 232 +- .../005_AnimEditor_Functions.rb | 2206 +++++++++-------- .../003_Debug_MenuExtraCode.rb | 6 +- 8 files changed, 3454 insertions(+), 3435 deletions(-) diff --git a/Data/Scripts/001_Technical/002_RubyUtilities.rb b/Data/Scripts/001_Technical/002_RubyUtilities.rb index 4570a2ccf..08d54466c 100644 --- a/Data/Scripts/001_Technical/002_RubyUtilities.rb +++ b/Data/Scripts/001_Technical/002_RubyUtilities.rb @@ -127,6 +127,16 @@ module Enumerable end end +#=============================================================================== +# Collision testing +#=============================================================================== +class Rect < Object + def contains?(cx, cy) + return cx >= self.x && cx < self.x + self.width && + cy >= self.y && cy < self.y + self.height + end +end + #=============================================================================== # class File #=============================================================================== diff --git a/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb b/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb index 2da02c2b1..e31525085 100644 --- a/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb +++ b/Data/Scripts/010_Data/002_PBS data/020_DungeonParameters.rb @@ -53,7 +53,7 @@ module GameData extend ClassMethodsSymbols include InstanceMethods - # @param other [Symbol, String, self] + # @param area [Symbol, String, self] # @param version [Integer] # @return [self] def self.try_get(area, version = 0) diff --git a/Data/Scripts/020_Debug/002_Animation editor/001_AnimEditor_SceneElements.rb b/Data/Scripts/020_Debug/002_Animation editor/001_AnimEditor_SceneElements.rb index c11fa61a2..fc67b0a0f 100644 --- a/Data/Scripts/020_Debug/002_Animation editor/001_AnimEditor_SceneElements.rb +++ b/Data/Scripts/020_Debug/002_Animation editor/001_AnimEditor_SceneElements.rb @@ -1,1018 +1,1012 @@ -#=============================================================================== -# Controls -#=============================================================================== -class Window_Menu < Window_CommandPokemon - def initialize(commands, x, y) - tempbitmap = Bitmap.new(32, 32) - w = 0 - commands.each do |i| - width = tempbitmap.text_size(i).width - w = width if w < width +module BattleAnimationEditor + module_function + + #=============================================================================== + # Controls + #=============================================================================== + class Window_Menu < Window_CommandPokemon + def initialize(commands, x, y) + tempbitmap = Bitmap.new(32, 32) + w = 0 + commands.each do |i| + width = tempbitmap.text_size(i).width + w = width if w < width + end + w += 16 + self.borderX + super(commands, w) + h = [commands.length * 32, 480].min + h += self.borderY + right = [x + w, 640].min + bottom = [y + h, 480].min + left = right - w + top = bottom - h + self.x = left + self.y = top + self.width = w + self.height = h + tempbitmap.dispose + end + + def hittest + mousepos = Mouse.getMousePos + return -1 if !mousepos + toprow = self.top_row + (toprow...toprow + @item_max).each do |i| + rc = Rect.new(0, 32 * (i - toprow), self.contents.width, 32) + rc.x += self.x + self.leftEdge + rc.y += self.y + self.topEdge + return i if rc.contains?(mousepos[0], mousepos[1]) + end + return -1 end - w += 16 + self.borderX - super(commands, w) - h = [commands.length * 32, 480].min - h += self.borderY - right = [x + w, 640].min - bottom = [y + h, 480].min - left = right - w - top = bottom - h - self.x = left - self.y = top - self.width = w - self.height = h - tempbitmap.dispose end - def hittest + #=============================================================================== + # Clipboard + #=============================================================================== + module Clipboard + @data = nil + @typekey = "" + + def self.data + return nil if !@data + return Marshal.load(@data) + end + + def self.typekey + return @typekey + end + + def self.setData(data, key) + @data = Marshal.dump(data) + @typekey = key + end + end + + #=============================================================================== + # + #=============================================================================== + def pbTrackPopupMenu(commands) mousepos = Mouse.getMousePos return -1 if !mousepos - toprow = self.top_row - (toprow...toprow + @item_max).each do |i| - rc = Rect.new(0, 32 * (i - toprow), self.contents.width, 32) - rc.x += self.x + self.leftEdge - rc.y += self.y + self.topEdge - return i if rc.contains(mousepos[0], mousepos[1]) + menuwindow = Window_Menu.new(commands, mousepos[0], mousepos[1]) + menuwindow.z = 99999 + loop do + Graphics.update + Input.update + menuwindow.update + hit = menuwindow.hittest + menuwindow.index = hit if hit >= 0 + if Input.trigger?(Input::MOUSELEFT) || Input.trigger?(Input::MOUSERIGHT) # Left or right button + menuwindow.dispose + return hit + end + if Input.trigger?(Input::USE) + hit = menuwindow.index + menuwindow.dispose + return hit + end + if Input.trigger?(Input::BACK) # Escape + break + end end + menuwindow.dispose return -1 end -end -#=============================================================================== -# Clipboard -#=============================================================================== -module Clipboard - @data = nil - @typekey = "" + #=============================================================================== + # Sprite sheet scrolling bar + #=============================================================================== + class AnimationWindow < Sprite + attr_reader :animbitmap + attr_reader :start + attr_reader :selected - def self.data - return nil if !@data - return Marshal.load(@data) - end + NUMFRAMES = 5 - def self.typekey - return @typekey - end - - def self.setData(data, key) - @data = Marshal.dump(data) - @typekey = key - end -end - -#=============================================================================== -# Collision testing -#=============================================================================== -class Rect < Object - def contains(x, y) - return x >= self.x && x < self.x + self.width && - y >= self.y && y < self.y + self.height - end -end - -#=============================================================================== -# -#=============================================================================== -def pbSpriteHitTest(sprite, x, y, usealpha = true, wholecanvas = false) - return false if !sprite || sprite.disposed? - return false if !sprite.bitmap - return false if !sprite.visible - return false if sprite.bitmap.disposed? - width = sprite.src_rect.width - height = sprite.src_rect.height - if wholecanvas - xwidth = 0 - xheight = 0 - else - xwidth = width - 64 - xheight = height - 64 - width = 64 if width > 64 && !usealpha - height = 64 if height > 64 && !usealpha - end - width = sprite.bitmap.width if width > sprite.bitmap.width - height = sprite.bitmap.height if height > sprite.bitmap.height - if usealpha - spritex = sprite.x - (sprite.ox * sprite.zoom_x) - spritey = sprite.y - (sprite.oy * sprite.zoom_y) - width *= sprite.zoom_x - height *= sprite.zoom_y - else - spritex = sprite.x - sprite.ox - spritey = sprite.y - sprite.oy - spritex += xwidth / 2 - spritey += xheight / 2 - end - if !(x >= spritex && x <= spritex + width && y >= spritey && y <= spritey + height) - return false - end - if usealpha - # TODO: This should account for sprite.angle as well - bitmapX = sprite.src_rect.x - bitmapY = sprite.src_rect.y - bitmapX += sprite.ox - bitmapY += sprite.oy - bitmapX += (x - sprite.x) / sprite.zoom_x if sprite.zoom_x > 0 - bitmapY += (y - sprite.y) / sprite.zoom_y if sprite.zoom_y > 0 - bitmapX = bitmapX.round - bitmapY = bitmapY.round - if sprite.mirror - xmirror = bitmapX - sprite.src_rect.x - bitmapX = sprite.src_rect.x + 192 - xmirror + def initialize(x, y, width, height, viewport = nil) + super(viewport) + @animbitmap = nil + @arrows = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_arrows") + self.x = x + self.y = y + @start = 0 + @selected = 0 + @contents = Bitmap.new(width, height) + self.bitmap = @contents + refresh end - color = sprite.bitmap.get_pixel(bitmapX, bitmapY) - return false if color.alpha == 0 - end - return true -end -def pbTrackPopupMenu(commands) - mousepos = Mouse.getMousePos - return -1 if !mousepos - menuwindow = Window_Menu.new(commands, mousepos[0], mousepos[1]) - menuwindow.z = 99999 - loop do - Graphics.update - Input.update - menuwindow.update - hit = menuwindow.hittest - menuwindow.index = hit if hit >= 0 - if Input.trigger?(Input::MOUSELEFT) || Input.trigger?(Input::MOUSERIGHT) # Left or right button - menuwindow.dispose - return hit + def animbitmap=(val) + @animbitmap = val + @start = 0 + refresh end - if Input.trigger?(Input::USE) - hit = menuwindow.index - menuwindow.dispose - return hit + + def selected=(val) + @selected = val + refresh end - if Input.trigger?(Input::BACK) # Escape - break + + def dispose + @contents.dispose + @arrows.dispose + @start = 0 + @selected = 0 + @changed = false + super end - end - menuwindow.dispose - return -1 -end -#=============================================================================== -# Sprite sheet scrolling bar -#=============================================================================== -class AnimationWindow < Sprite - attr_reader :animbitmap - attr_reader :start - attr_reader :selected + def drawrect(bm, x, y, width, height, color) + bm.fill_rect(x, y, width, 1, color) + bm.fill_rect(x, y + height - 1, width, 1, color) + bm.fill_rect(x, y, 1, height, color) + bm.fill_rect(x + width - 1, y, 1, height, color) + end - NUMFRAMES = 5 + def drawborder(bm, x, y, width, height, color) + bm.fill_rect(x, y, width, 2, color) + bm.fill_rect(x, y + height - 2, width, 2, color) + bm.fill_rect(x, y, 2, height, color) + bm.fill_rect(x + width - 2, y, 2, height, color) + end - def initialize(x, y, width, height, viewport = nil) - super(viewport) - @animbitmap = nil - @arrows = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_arrows") - self.x = x - self.y = y - @start = 0 - @selected = 0 - @contents = Bitmap.new(width, height) - self.bitmap = @contents - refresh - end - - def animbitmap=(val) - @animbitmap = val - @start = 0 - refresh - end - - def selected=(val) - @selected = val - refresh - end - - def dispose - @contents.dispose - @arrows.dispose - @start = 0 - @selected = 0 - @changed = false - super - end - - def drawrect(bm, x, y, width, height, color) - bm.fill_rect(x, y, width, 1, color) - bm.fill_rect(x, y + height - 1, width, 1, color) - bm.fill_rect(x, y, 1, height, color) - bm.fill_rect(x + width - 1, y, 1, height, color) - end - - def drawborder(bm, x, y, width, height, color) - bm.fill_rect(x, y, width, 2, color) - bm.fill_rect(x, y + height - 2, width, 2, color) - bm.fill_rect(x, y, 2, height, color) - bm.fill_rect(x + width - 2, y, 2, height, color) - end - - def refresh - arrowwidth = @arrows.bitmap.width / 2 - @contents.clear - @contents.fill_rect(0, 0, @contents.width, @contents.height, Color.new(180, 180, 180)) - @contents.blt(0, 0, @arrows.bitmap, Rect.new(0, 0, arrowwidth, 96)) - @contents.blt(arrowwidth + (NUMFRAMES * 96), 0, @arrows.bitmap, - Rect.new(arrowwidth, 0, arrowwidth, 96)) - havebitmap = (self.animbitmap && !self.animbitmap.disposed?) - if havebitmap - rect = Rect.new(0, 0, 0, 0) - rectdst = Rect.new(0, 0, 0, 0) - x = arrowwidth + def refresh + arrowwidth = @arrows.bitmap.width / 2 + @contents.clear + @contents.fill_rect(0, 0, @contents.width, @contents.height, Color.new(180, 180, 180)) + @contents.blt(0, 0, @arrows.bitmap, Rect.new(0, 0, arrowwidth, 96)) + @contents.blt(arrowwidth + (NUMFRAMES * 96), 0, @arrows.bitmap, + Rect.new(arrowwidth, 0, arrowwidth, 96)) + havebitmap = (self.animbitmap && !self.animbitmap.disposed?) + if havebitmap + rect = Rect.new(0, 0, 0, 0) + rectdst = Rect.new(0, 0, 0, 0) + x = arrowwidth + NUMFRAMES.times do |i| + j = i + @start + rect.set((j % 5) * 192, (j / 5) * 192, 192, 192) + rectdst.set(x, 0, 96, 96) + @contents.stretch_blt(rectdst, self.animbitmap, rect) + x += 96 + end + end NUMFRAMES.times do |i| - j = i + @start - rect.set((j % 5) * 192, (j / 5) * 192, 192, 192) - rectdst.set(x, 0, 96, 96) - @contents.stretch_blt(rectdst, self.animbitmap, rect) - x += 96 + drawrect(@contents, arrowwidth + (i * 96), 0, 96, 96, Color.new(100, 100, 100)) + if @start + i == @selected && havebitmap + drawborder(@contents, arrowwidth + (i * 96), 0, 96, 96, Color.new(255, 0, 0)) + end end end - NUMFRAMES.times do |i| - drawrect(@contents, arrowwidth + (i * 96), 0, 96, 96, Color.new(100, 100, 100)) - if @start + i == @selected && havebitmap - drawborder(@contents, arrowwidth + (i * 96), 0, 96, 96, Color.new(255, 0, 0)) + + def changed? + return @changed + end + + def update + mousepos = Mouse.getMousePos + @changed = false + return if !Input.repeat?(Input::MOUSELEFT) + return if !mousepos + return if !self.animbitmap + arrowwidth = @arrows.bitmap.width / 2 + maxindex = (self.animbitmap.height / 192) * 5 + left = Rect.new(0, 0, arrowwidth, 96) + right = Rect.new(arrowwidth + (NUMFRAMES * 96), 0, arrowwidth, 96) + left.x += self.x + left.y += self.y + right.x += self.x + right.y += self.y + swatchrects = [] + repeattime = Input.time?(Input::MOUSELEFT) / 1000 + NUMFRAMES.times do |i| + swatchrects.push(Rect.new(arrowwidth + (i * 96) + self.x, self.y, 96, 96)) + end + NUMFRAMES.times do |i| + next if !swatchrects[i].contains?(mousepos[0], mousepos[1]) + @selected = @start + i + @changed = true + refresh + return + end + # Left arrow + if left.contains?(mousepos[0], mousepos[1]) + if repeattime > 750 + @start -= 3 + else + @start -= 1 + end + @start = 0 if @start < 0 + refresh + end + # Right arrow + if right.contains?(mousepos[0], mousepos[1]) + if repeattime > 750 + @start += 3 + else + @start += 1 + end + @start = maxindex if @start >= maxindex + refresh end end end - def changed? - return @changed + #=============================================================================== + # + #=============================================================================== + class CanvasAnimationWindow < AnimationWindow + def animbitmap + return @canvas.animbitmap + end + + def initialize(canvas, x, y, width, height, viewport = nil) + @canvas = canvas + super(x, y, width, height, viewport) + end end - def update - mousepos = Mouse.getMousePos - @changed = false - return if !Input.repeat?(Input::MOUSELEFT) - return if !mousepos - return if !self.animbitmap - arrowwidth = @arrows.bitmap.width / 2 - maxindex = (self.animbitmap.height / 192) * 5 - left = Rect.new(0, 0, arrowwidth, 96) - right = Rect.new(arrowwidth + (NUMFRAMES * 96), 0, arrowwidth, 96) - left.x += self.x - left.y += self.y - right.x += self.x - right.y += self.y - swatchrects = [] - repeattime = Input.time?(Input::MOUSELEFT) / 1000 - NUMFRAMES.times do |i| - swatchrects.push(Rect.new(arrowwidth + (i * 96) + self.x, self.y, 96, 96)) + #=============================================================================== + # Cel sprite + #=============================================================================== + class InvalidatableSprite < Sprite + def initialize(viewport = nil) + super(viewport) + @invalid = false end - NUMFRAMES.times do |i| - next if !swatchrects[i].contains(mousepos[0], mousepos[1]) - @selected = @start + i - @changed = true - refresh - return + + # Marks that the control must be redrawn to reflect current logic. + def invalidate + @invalid = true end - # Left arrow - if left.contains(mousepos[0], mousepos[1]) - if repeattime > 750 - @start -= 3 + + # Determines whether the control is invalid + def invalid? + return @invalid + end + + # Marks that the control is valid. Normally called only by repaint. + def validate + @invalid = false + end + + # Redraws the sprite only if it is invalid, and then revalidates the sprite + def repaint + if self.invalid? + refresh + validate + end + end + + # Redraws the sprite. This method should not check whether + # the sprite is invalid, to allow it to be explicitly called. + def refresh; end + end + + #=============================================================================== + # + #=============================================================================== + class SpriteFrame < InvalidatableSprite + attr_reader :id + attr_reader :locked + attr_reader :selected + attr_reader :sprite + + NUM_ROWS = (PBAnimation::MAX_SPRITES.to_f / 10).ceil # 10 frame number icons in each row + + def initialize(id, sprite, viewport, previous = false) + super(viewport) + @id = id + @sprite = sprite + @previous = previous + @locked = false + @selected = false + @selcolor = Color.black + @unselcolor = Color.new(220, 220, 220) + @prevcolor = Color.new(64, 128, 192) + @contents = Bitmap.new(64, 64) + self.z = (@previous) ? 49 : 50 + @iconbitmap = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_frame_icons") + self.bitmap = @contents + self.invalidate + end + + def dispose + @contents.dispose + super + end + + def sprite=(value) + @sprite = value + self.invalidate + end + + def locked=(value) + @locked = value + self.invalidate + end + + def selected=(value) + @selected = value + self.invalidate + end + + def refresh + @contents.clear + self.z = (@previous) ? 49 : (@selected) ? 51 : 50 + # Draw frame + color = (@previous) ? @prevcolor : (@selected) ? @selcolor : @unselcolor + @contents.fill_rect(0, 0, 64, 1, color) + @contents.fill_rect(0, 63, 64, 1, color) + @contents.fill_rect(0, 0, 1, 64, color) + @contents.fill_rect(63, 0, 1, 64, color) + # Determine frame number graphic to use from @iconbitmap + yoffset = (@previous) ? (NUM_ROWS + 1) * 16 : 0 # 1 is for padlock icon + bmrect = Rect.new((@id % 10) * 16, yoffset + ((@id / 10) * 16), 16, 16) + @contents.blt(0, 0, @iconbitmap.bitmap, bmrect) + # Draw padlock if frame is locked + if @locked && !@previous + bmrect = Rect.new(0, NUM_ROWS * 16, 16, 16) + @contents.blt(16, 0, @iconbitmap.bitmap, bmrect) + end + end + end + + #=============================================================================== + # Canvas + #=============================================================================== + class AnimationCanvas < Sprite + attr_reader :viewport + attr_reader :sprites + attr_reader :currentframe # Currently active frame + attr_reader :currentcel + attr_reader :animation # Currently selected animation + attr_reader :animbitmap # Currently selected animation bitmap + attr_accessor :pattern # Currently selected pattern + + BORDERSIZE = 64 + + def initialize(animation, viewport = nil) + super(viewport) + @currentframe = 0 + @currentcel = -1 + @pattern = 0 + @sprites = {} + @celsprites = [] + @framesprites = [] + @lastframesprites = [] + @dirty = [] + @viewport = viewport + @selecting = false + @selectOffsetX = 0 + @selectOffsetY = 0 + @playing = false + @playingframe = 0 + @player = nil + @battle = MiniBattle.new + @user = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_battler_back").deanimate + @target = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_battler_front").deanimate + @testscreen = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_battle_bg") + self.bitmap = @testscreen.bitmap + PBAnimation::MAX_SPRITES.times do |i| + @lastframesprites[i] = SpriteFrame.new(i, @celsprites[i], viewport, true) + @lastframesprites[i].selected = false + @lastframesprites[i].visible = false + end + PBAnimation::MAX_SPRITES.times do |i| + @celsprites[i] = Sprite.new(viewport) + @celsprites[i].visible = false + @celsprites[i].src_rect = Rect.new(0, 0, 0, 0) + @celsprites[i].bitmap = nil + @framesprites[i] = SpriteFrame.new(i, @celsprites[i], viewport) + @framesprites[i].selected = false + @framesprites[i].visible = false + @dirty[i] = true + end + loadAnimation(animation) + end + + def loadAnimation(anim) + @animation = anim + @animbitmap&.dispose + if @animation.graphic == "" + @animbitmap = nil else - @start -= 1 + begin + @animbitmap = AnimatedBitmap.new("Graphics/Animations/" + @animation.graphic, + @animation.hue).deanimate + rescue + @animbitmap = nil + end end - @start = 0 if @start < 0 - refresh + @currentcel = -1 + self.currentframe = 0 + @selecting = false + @pattern = 0 + self.invalidate end - # Right arrow - if right.contains(mousepos[0], mousepos[1]) - if repeattime > 750 - @start += 3 - else - @start += 1 + + def animbitmap=(value) + @animbitmap&.dispose + @animbitmap = value + (2...PBAnimation::MAX_SPRITES).each do |i| + @celsprites[i].bitmap = @animbitmap if @celsprites[i] end - @start = maxindex if @start >= maxindex - refresh + self.invalidate end - end -end -#=============================================================================== -# -#=============================================================================== -class CanvasAnimationWindow < AnimationWindow - def animbitmap - return @canvas.animbitmap - end - - def initialize(canvas, x, y, width, height, viewport = nil) - @canvas = canvas - super(x, y, width, height, viewport) - end -end - -#=============================================================================== -# Cel sprite -#=============================================================================== -class InvalidatableSprite < Sprite - def initialize(viewport = nil) - super(viewport) - @invalid = false - end - - # Marks that the control must be redrawn to reflect current logic. - def invalidate - @invalid = true - end - - # Determines whether the control is invalid - def invalid? - return @invalid - end - - # Marks that the control is valid. Normally called only by repaint. - def validate - @invalid = false - end - - # Redraws the sprite only if it is invalid, and then revalidates the sprite - def repaint - if self.invalid? - refresh - validate + def dispose + @user.dispose + @target.dispose + @animbitmap&.dispose + @selectedbitmap&.dispose + @celbitmap&.dispose + self.bitmap&.dispose + PBAnimation::MAX_SPRITES.times do |i| + @celsprites[i]&.dispose + end + super end - end - # Redraws the sprite. This method should not check whether - # the sprite is invalid, to allow it to be explicitly called. - def refresh; end -end - -#=============================================================================== -# -#=============================================================================== -class SpriteFrame < InvalidatableSprite - attr_reader :id - attr_reader :locked - attr_reader :selected - attr_reader :sprite - - NUM_ROWS = (PBAnimation::MAX_SPRITES.to_f / 10).ceil # 10 frame number icons in each row - - def initialize(id, sprite, viewport, previous = false) - super(viewport) - @id = id - @sprite = sprite - @previous = previous - @locked = false - @selected = false - @selcolor = Color.black - @unselcolor = Color.new(220, 220, 220) - @prevcolor = Color.new(64, 128, 192) - @contents = Bitmap.new(64, 64) - self.z = (@previous) ? 49 : 50 - @iconbitmap = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_frame_icons") - self.bitmap = @contents - self.invalidate - end - - def dispose - @contents.dispose - super - end - - def sprite=(value) - @sprite = value - self.invalidate - end - - def locked=(value) - @locked = value - self.invalidate - end - - def selected=(value) - @selected = value - self.invalidate - end - - def refresh - @contents.clear - self.z = (@previous) ? 49 : (@selected) ? 51 : 50 - # Draw frame - color = (@previous) ? @prevcolor : (@selected) ? @selcolor : @unselcolor - @contents.fill_rect(0, 0, 64, 1, color) - @contents.fill_rect(0, 63, 64, 1, color) - @contents.fill_rect(0, 0, 1, 64, color) - @contents.fill_rect(63, 0, 1, 64, color) - # Determine frame number graphic to use from @iconbitmap - yoffset = (@previous) ? (NUM_ROWS + 1) * 16 : 0 # 1 is for padlock icon - bmrect = Rect.new((@id % 10) * 16, yoffset + ((@id / 10) * 16), 16, 16) - @contents.blt(0, 0, @iconbitmap.bitmap, bmrect) - # Draw padlock if frame is locked - if @locked && !@previous - bmrect = Rect.new(0, NUM_ROWS * 16, 16, 16) - @contents.blt(16, 0, @iconbitmap.bitmap, bmrect) + def play(oppmove = false) + if !@playing + @sprites["pokemon_0"] = Sprite.new(@viewport) + @sprites["pokemon_0"].bitmap = @user + @sprites["pokemon_0"].z = 21 + @sprites["pokemon_1"] = Sprite.new(@viewport) + @sprites["pokemon_1"].bitmap = @target + @sprites["pokemon_1"].z = 16 + pbSpriteSetAnimFrame(@sprites["pokemon_0"], + pbCreateCel(Battle::Scene::FOCUSUSER_X, + Battle::Scene::FOCUSUSER_Y, -1, 2), + @sprites["pokemon_0"], @sprites["pokemon_1"]) + pbSpriteSetAnimFrame(@sprites["pokemon_1"], + pbCreateCel(Battle::Scene::FOCUSTARGET_X, + Battle::Scene::FOCUSTARGET_Y, -2, 1), + @sprites["pokemon_0"], @sprites["pokemon_1"]) + usersprite = @sprites["pokemon_#{oppmove ? 1 : 0}"] + targetsprite = @sprites["pokemon_#{oppmove ? 0 : 1}"] + olduserx = usersprite ? usersprite.x : 0 + oldusery = usersprite ? usersprite.y : 0 + oldtargetx = targetsprite ? targetsprite.x : 0 + oldtargety = targetsprite ? targetsprite.y : 0 + @player = PBAnimationPlayerX.new(@animation, + @battle.battlers[oppmove ? 1 : 0], + @battle.battlers[oppmove ? 0 : 1], + self, oppmove, true) + @player.setLineTransform( + Battle::Scene::FOCUSUSER_X, Battle::Scene::FOCUSUSER_Y, + Battle::Scene::FOCUSTARGET_X, Battle::Scene::FOCUSTARGET_Y, + olduserx, oldusery, + oldtargetx, oldtargety + ) + @player.start + @playing = true + @sprites["pokemon_0"].x += BORDERSIZE + @sprites["pokemon_0"].y += BORDERSIZE + @sprites["pokemon_1"].x += BORDERSIZE + @sprites["pokemon_1"].y += BORDERSIZE + oldstate = [] + PBAnimation::MAX_SPRITES.times do |i| + oldstate.push([@celsprites[i].visible, @framesprites[i].visible, @lastframesprites[i].visible]) + @celsprites[i].visible = false + @framesprites[i].visible = false + @lastframesprites[i].visible = false + end + loop do + Graphics.update + self.update + break if !@playing + end + PBAnimation::MAX_SPRITES.times do |i| + @celsprites[i].visible = oldstate[i][0] + @framesprites[i].visible = oldstate[i][1] + @lastframesprites[i].visible = oldstate[i][2] + end + @sprites["pokemon_0"].dispose + @sprites["pokemon_1"].dispose + @player.dispose + @player = nil + end end - end -end -#=============================================================================== -# Canvas -#=============================================================================== -class AnimationCanvas < Sprite - attr_reader :viewport - attr_reader :sprites - attr_reader :currentframe # Currently active frame - attr_reader :currentcel - attr_reader :animation # Currently selected animation - attr_reader :animbitmap # Currently selected animation bitmap - attr_accessor :pattern # Currently selected pattern - - BORDERSIZE = 64 - - def initialize(animation, viewport = nil) - super(viewport) - @currentframe = 0 - @currentcel = -1 - @pattern = 0 - @sprites = {} - @celsprites = [] - @framesprites = [] - @lastframesprites = [] - @dirty = [] - @viewport = viewport - @selecting = false - @selectOffsetX = 0 - @selectOffsetY = 0 - @playing = false - @playingframe = 0 - @player = nil - @battle = MiniBattle.new - @user = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_battler_back").deanimate - @target = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_battler_front").deanimate - @testscreen = AnimatedBitmap.new("Graphics/UI/Debug/anim_editor_battle_bg") - self.bitmap = @testscreen.bitmap - PBAnimation::MAX_SPRITES.times do |i| - @lastframesprites[i] = SpriteFrame.new(i, @celsprites[i], viewport, true) - @lastframesprites[i].selected = false - @lastframesprites[i].visible = false + def invalidate + PBAnimation::MAX_SPRITES.times do |i| + invalidateCel(i) + end end - PBAnimation::MAX_SPRITES.times do |i| - @celsprites[i] = Sprite.new(viewport) - @celsprites[i].visible = false - @celsprites[i].src_rect = Rect.new(0, 0, 0, 0) - @celsprites[i].bitmap = nil - @framesprites[i] = SpriteFrame.new(i, @celsprites[i], viewport) - @framesprites[i].selected = false - @framesprites[i].visible = false + + def invalidateCel(i) @dirty[i] = true end - loadAnimation(animation) - end - def loadAnimation(anim) - @animation = anim - @animbitmap&.dispose - if @animation.graphic == "" - @animbitmap = nil - else - begin - @animbitmap = AnimatedBitmap.new("Graphics/Animations/" + @animation.graphic, - @animation.hue).deanimate - rescue - @animbitmap = nil + def currentframe=(value) + @currentframe = value + invalidate + end + + def getCurrentFrame + return nil if @currentframe >= @animation.length + return @animation[@currentframe] + end + + def setFrame(i) + if @celsprites[i] + @framesprites[i].ox = 32 + @framesprites[i].oy = 32 + @framesprites[i].selected = (i == @currentcel) + @framesprites[i].locked = self.locked?(i) + @framesprites[i].x = @celsprites[i].x + @framesprites[i].y = @celsprites[i].y + @framesprites[i].visible = @celsprites[i].visible + @framesprites[i].repaint end end - @currentcel = -1 - self.currentframe = 0 - @selecting = false - @pattern = 0 - self.invalidate - end - def animbitmap=(value) - @animbitmap&.dispose - @animbitmap = value - (2...PBAnimation::MAX_SPRITES).each do |i| - @celsprites[i].bitmap = @animbitmap if @celsprites[i] - end - self.invalidate - end - - def dispose - @user.dispose - @target.dispose - @animbitmap&.dispose - @selectedbitmap&.dispose - @celbitmap&.dispose - self.bitmap&.dispose - PBAnimation::MAX_SPRITES.times do |i| - @celsprites[i]&.dispose - end - super - end - - def play(oppmove = false) - if !@playing - @sprites["pokemon_0"] = Sprite.new(@viewport) - @sprites["pokemon_0"].bitmap = @user - @sprites["pokemon_0"].z = 21 - @sprites["pokemon_1"] = Sprite.new(@viewport) - @sprites["pokemon_1"].bitmap = @target - @sprites["pokemon_1"].z = 16 - pbSpriteSetAnimFrame(@sprites["pokemon_0"], - pbCreateCel(Battle::Scene::FOCUSUSER_X, - Battle::Scene::FOCUSUSER_Y, -1, 2), - @sprites["pokemon_0"], @sprites["pokemon_1"]) - pbSpriteSetAnimFrame(@sprites["pokemon_1"], - pbCreateCel(Battle::Scene::FOCUSTARGET_X, - Battle::Scene::FOCUSTARGET_Y, -2, 1), - @sprites["pokemon_0"], @sprites["pokemon_1"]) - usersprite = @sprites["pokemon_#{oppmove ? 1 : 0}"] - targetsprite = @sprites["pokemon_#{oppmove ? 0 : 1}"] - olduserx = usersprite ? usersprite.x : 0 - oldusery = usersprite ? usersprite.y : 0 - oldtargetx = targetsprite ? targetsprite.x : 0 - oldtargety = targetsprite ? targetsprite.y : 0 - @player = PBAnimationPlayerX.new(@animation, - @battle.battlers[oppmove ? 1 : 0], - @battle.battlers[oppmove ? 0 : 1], - self, oppmove, true) - @player.setLineTransform( - Battle::Scene::FOCUSUSER_X, Battle::Scene::FOCUSUSER_Y, - Battle::Scene::FOCUSTARGET_X, Battle::Scene::FOCUSTARGET_Y, - olduserx, oldusery, - oldtargetx, oldtargety - ) - @player.start - @playing = true - @sprites["pokemon_0"].x += BORDERSIZE - @sprites["pokemon_0"].y += BORDERSIZE - @sprites["pokemon_1"].x += BORDERSIZE - @sprites["pokemon_1"].y += BORDERSIZE - oldstate = [] - PBAnimation::MAX_SPRITES.times do |i| - oldstate.push([@celsprites[i].visible, @framesprites[i].visible, @lastframesprites[i].visible]) - @celsprites[i].visible = false - @framesprites[i].visible = false - @lastframesprites[i].visible = false - end - loop do - Graphics.update - self.update - break if !@playing - end - PBAnimation::MAX_SPRITES.times do |i| - @celsprites[i].visible = oldstate[i][0] - @framesprites[i].visible = oldstate[i][1] - @lastframesprites[i].visible = oldstate[i][2] - end - @sprites["pokemon_0"].dispose - @sprites["pokemon_1"].dispose - @player.dispose - @player = nil - end - end - - def invalidate - PBAnimation::MAX_SPRITES.times do |i| - invalidateCel(i) - end - end - - def invalidateCel(i) - @dirty[i] = true - end - - def currentframe=(value) - @currentframe = value - invalidate - end - - def getCurrentFrame - return nil if @currentframe >= @animation.length - return @animation[@currentframe] - end - - def setFrame(i) - if @celsprites[i] - @framesprites[i].ox = 32 - @framesprites[i].oy = 32 - @framesprites[i].selected = (i == @currentcel) - @framesprites[i].locked = self.locked?(i) - @framesprites[i].x = @celsprites[i].x - @framesprites[i].y = @celsprites[i].y - @framesprites[i].visible = @celsprites[i].visible - @framesprites[i].repaint - end - end - - def setPreviousFrame(i) - if @currentframe > 0 - cel = @animation[@currentframe - 1][i] - if cel.nil? - @lastframesprites[i].visible = false - else - @lastframesprites[i].ox = 32 - @lastframesprites[i].oy = 32 - @lastframesprites[i].selected = false - @lastframesprites[i].locked = false - @lastframesprites[i].x = cel[AnimFrame::X] + 64 - @lastframesprites[i].y = cel[AnimFrame::Y] + 64 - @lastframesprites[i].visible = true - @lastframesprites[i].repaint - end - else - @lastframesprites[i].visible = false - end - end - - def offsetFrame(frame, ox, oy) - if frame >= 0 && frame < @animation.length - PBAnimation::MAX_SPRITES.times do |i| - if !self.locked?(i) && @animation[frame][i] - @animation[frame][i][AnimFrame::X] += ox - @animation[frame][i][AnimFrame::Y] += oy - end - @dirty[i] = true if frame == @currentframe - end - end - end - - # Clears all items in the frame except locked items - def clearFrame(frame) - if frame >= 0 && frame < @animation.length - PBAnimation::MAX_SPRITES.times do |i| - if self.deletable?(i) - @animation[frame][i] = nil + def setPreviousFrame(i) + if @currentframe > 0 + cel = @animation[@currentframe - 1][i] + if cel.nil? + @lastframesprites[i].visible = false else - pbResetCel(@animation[frame][i]) + @lastframesprites[i].ox = 32 + @lastframesprites[i].oy = 32 + @lastframesprites[i].selected = false + @lastframesprites[i].locked = false + @lastframesprites[i].x = cel[AnimFrame::X] + 64 + @lastframesprites[i].y = cel[AnimFrame::Y] + 64 + @lastframesprites[i].visible = true + @lastframesprites[i].repaint end - @dirty[i] = true if frame == @currentframe + else + @lastframesprites[i].visible = false end end - end - def insertFrame(frame) - return if frame >= @animation.length - @animation.insert(frame, @animation[frame].clone) - self.invalidate - end - - def copyFrame(src, dst) - return if dst >= @animation.length - PBAnimation::MAX_SPRITES.times do |i| - clonedframe = @animation[src][i] - clonedframe = clonedframe.clone if clonedframe && clonedframe != true - @animation[dst][i] = clonedframe + def offsetFrame(frame, ox, oy) + if frame >= 0 && frame < @animation.length + PBAnimation::MAX_SPRITES.times do |i| + if !self.locked?(i) && @animation[frame][i] + @animation[frame][i][AnimFrame::X] += ox + @animation[frame][i][AnimFrame::Y] += oy + end + @dirty[i] = true if frame == @currentframe + end + end end - self.invalidate if dst == @currentframe - end - def pasteFrame(frame) - return if frame < 0 || frame >= @animation.length - return if Clipboard.typekey != "PBAnimFrame" - @animation[frame] = Clipboard.data - self.invalidate if frame == @currentframe - end - - def deleteFrame(frame) - return if frame < 0 || frame >= @animation.length || @animation.length <= 1 - self.currentframe -= 1 if frame == @animation.length - 1 - @animation.delete_at(frame) - @currentcel = -1 - self.invalidate - end - - # This frame becomes a copy of the previous frame - def pasteLast - copyFrame(@currentframe - 1, @currentframe) if @currentframe > 0 - end - - def currentCel - return nil if @currentcel < 0 - return nil if @currentframe >= @animation.length - return @animation[@currentframe][@currentcel] - end - - def pasteCel(x, y) - return if @currentframe >= @animation.length - return if Clipboard.typekey != "PBAnimCel" - PBAnimation::MAX_SPRITES.times do |i| - next if @animation[@currentframe][i] - @animation[@currentframe][i] = Clipboard.data - cel = @animation[@currentframe][i] - cel[AnimFrame::X] = x - cel[AnimFrame::Y] = y - cel[AnimFrame::LOCKED] = 0 - @celsprites[i].bitmap = @user if cel[AnimFrame::PATTERN] == -1 - @celsprites[i].bitmap = @target if cel[AnimFrame::PATTERN] == -2 - @currentcel = i - break + # Clears all items in the frame except locked items + def clearFrame(frame) + if frame >= 0 && frame < @animation.length + PBAnimation::MAX_SPRITES.times do |i| + if self.deletable?(i) + @animation[frame][i] = nil + else + pbResetCel(@animation[frame][i]) + end + @dirty[i] = true if frame == @currentframe + end + end end - invalidate - end - def deleteCel(cel) - return if cel < 0 - return if @currentframe < 0 || @currentframe >= @animation.length - return if !deletable?(cel) - @animation[@currentframe][cel] = nil - @dirty[cel] = true - end + def insertFrame(frame) + return if frame >= @animation.length + @animation.insert(frame, @animation[frame].clone) + self.invalidate + end - def swapCels(cel1, cel2) - return if cel1 < 0 || cel2 < 0 - return if @currentframe < 0 || @currentframe >= @animation.length - t = @animation[@currentframe][cel1] - @animation[@currentframe][cel1] = @animation[@currentframe][cel2] - @animation[@currentframe][cel2] = t - @currentcel = cel2 - @dirty[cel1] = true - @dirty[cel2] = true - end - - def locked?(celindex) - cel = @animation[self.currentframe] - return false if !cel - cel = cel[celindex] - return cel ? (cel[AnimFrame::LOCKED] != 0) : false - end - - def deletable?(celindex) - cel = @animation[self.currentframe] - return true if !cel - cel = cel[celindex] - return true if !cel - return false if cel[AnimFrame::LOCKED] != 0 - if cel[AnimFrame::PATTERN] < 0 - count = 0 - pattern = cel[AnimFrame::PATTERN] + def copyFrame(src, dst) + return if dst >= @animation.length PBAnimation::MAX_SPRITES.times do |i| - othercel = @animation[self.currentframe][i] - count += 1 if othercel && othercel[AnimFrame::PATTERN] == pattern + clonedframe = @animation[src][i] + clonedframe = clonedframe.clone if clonedframe && clonedframe != true + @animation[dst][i] = clonedframe end - return false if count <= 1 + self.invalidate if dst == @currentframe end - return true - end - def setBitmap(i, frame) - if @celsprites[i] - cel = @animation[frame][i] - @celsprites[i].bitmap = @animbitmap - if cel + def pasteFrame(frame) + return if frame < 0 || frame >= @animation.length + return if Clipboard.typekey != "PBAnimFrame" + @animation[frame] = Clipboard.data + self.invalidate if frame == @currentframe + end + + def deleteFrame(frame) + return if frame < 0 || frame >= @animation.length || @animation.length <= 1 + self.currentframe -= 1 if frame == @animation.length - 1 + @animation.delete_at(frame) + @currentcel = -1 + self.invalidate + end + + # This frame becomes a copy of the previous frame + def pasteLast + copyFrame(@currentframe - 1, @currentframe) if @currentframe > 0 + end + + def currentCel + return nil if @currentcel < 0 + return nil if @currentframe >= @animation.length + return @animation[@currentframe][@currentcel] + end + + def pasteCel(x, y) + return if @currentframe >= @animation.length + return if Clipboard.typekey != "PBAnimCel" + PBAnimation::MAX_SPRITES.times do |i| + next if @animation[@currentframe][i] + @animation[@currentframe][i] = Clipboard.data + cel = @animation[@currentframe][i] + cel[AnimFrame::X] = x + cel[AnimFrame::Y] = y + cel[AnimFrame::LOCKED] = 0 @celsprites[i].bitmap = @user if cel[AnimFrame::PATTERN] == -1 @celsprites[i].bitmap = @target if cel[AnimFrame::PATTERN] == -2 - end - end - end - - def setSpriteBitmap(sprite, cel) - if sprite && !sprite.disposed? - sprite.bitmap = @animbitmap - if cel - sprite.bitmap = @user if cel[AnimFrame::PATTERN] == -1 - sprite.bitmap = @target if cel[AnimFrame::PATTERN] == -2 - end - end - end - - def addSprite(x, y) - return false if @currentframe >= @animation.length - PBAnimation::MAX_SPRITES.times do |i| - next if @animation[@currentframe][i] - @animation[@currentframe][i] = pbCreateCel(x, y, @pattern, @animation.position) - @dirty[i] = true - @currentcel = i - return true - end - return false - end - - def updateInput - cel = currentCel - mousepos = Mouse.getMousePos - if Input.trigger?(Input::MOUSELEFT) && mousepos && - pbSpriteHitTest(self, mousepos[0], mousepos[1], false, true) - selectedcel = -1 - usealpha = Input.press?(Input::ALT) - PBAnimation::MAX_SPRITES.times do |j| - if pbSpriteHitTest(@celsprites[j], mousepos[0], mousepos[1], usealpha, false) - selectedcel = j - end - end - if selectedcel < 0 - if @animbitmap && addSprite(mousepos[0] - BORDERSIZE, mousepos[1] - BORDERSIZE) - @selecting = true if !self.locked?(@currentcel) - @selectOffsetX = 0 - @selectOffsetY = 0 - cel = currentCel - invalidate - end - else - @currentcel = selectedcel - @selecting = true if !self.locked?(@currentcel) - cel = currentCel - @selectOffsetX = cel[AnimFrame::X] - mousepos[0] + BORDERSIZE - @selectOffsetY = cel[AnimFrame::Y] - mousepos[1] + BORDERSIZE - invalidate - end - end - currentFrame = getCurrentFrame - if currentFrame && !@selecting && - (Input.triggerex?(:TAB) || Input.repeatex?(:TAB)) - currentFrame.length.times do - @currentcel += 1 - @currentcel = 0 if @currentcel >= currentFrame.length - break if currentFrame[@currentcel] + @currentcel = i + break end invalidate - return end - if cel && @selecting && mousepos - cel[AnimFrame::X] = mousepos[0] - BORDERSIZE + @selectOffsetX - cel[AnimFrame::Y] = mousepos[1] - BORDERSIZE + @selectOffsetY - @dirty[@currentcel] = true - end - if !Input.press?(Input::MOUSELEFT) && @selecting - @selecting = false - end - if cel - if (Input.triggerex?(:DELETE) || Input.repeatex?(:DELETE)) && self.deletable?(@currentcel) - @animation[@currentframe][@currentcel] = nil - @dirty[@currentcel] = true - return - end - if Input.triggerex?(:P) || Input.repeatex?(:P) # Properties - pbCellProperties(self) - @dirty[@currentcel] = true - return - end - if Input.triggerex?(:L) || Input.repeatex?(:L) # Lock - cel[AnimFrame::LOCKED] = (cel[AnimFrame::LOCKED] == 0) ? 1 : 0 - @dirty[@currentcel] = true - end - if Input.triggerex?(:R) || Input.repeatex?(:R) # Rotate right - cel[AnimFrame::ANGLE] += 10 - cel[AnimFrame::ANGLE] %= 360 - @dirty[@currentcel] = true - end - if Input.triggerex?(:E) || Input.repeatex?(:E) # Rotate left - cel[AnimFrame::ANGLE] -= 10 - cel[AnimFrame::ANGLE] %= 360 - @dirty[@currentcel] = true - end - if Input.triggerex?(:KP_PLUS) || Input.repeatex?(:KP_PLUS) # Zoom in - cel[AnimFrame::ZOOMX] += 10 - cel[AnimFrame::ZOOMX] = 1000 if cel[AnimFrame::ZOOMX] > 1000 - cel[AnimFrame::ZOOMY] += 10 - cel[AnimFrame::ZOOMY] = 1000 if cel[AnimFrame::ZOOMY] > 1000 - @dirty[@currentcel] = true - end - if Input.triggerex?(:KP_MINUS) || Input.repeatex?(:KP_MINUS) # Zoom out - cel[AnimFrame::ZOOMX] -= 10 - cel[AnimFrame::ZOOMX] = 10 if cel[AnimFrame::ZOOMX] < 10 - cel[AnimFrame::ZOOMY] -= 10 - cel[AnimFrame::ZOOMY] = 10 if cel[AnimFrame::ZOOMY] < 10 - @dirty[@currentcel] = true - end - if !self.locked?(@currentcel) - if Input.trigger?(Input::UP) || Input.repeat?(Input::UP) - increment = (Input.press?(Input::ALT)) ? 1 : 8 - cel[AnimFrame::Y] -= increment - @dirty[@currentcel] = true - end - if Input.trigger?(Input::DOWN) || Input.repeat?(Input::DOWN) - increment = (Input.press?(Input::ALT)) ? 1 : 8 - cel[AnimFrame::Y] += increment - @dirty[@currentcel] = true - end - if Input.trigger?(Input::LEFT) || Input.repeat?(Input::LEFT) - increment = (Input.press?(Input::ALT)) ? 1 : 8 - cel[AnimFrame::X] -= increment - @dirty[@currentcel] = true - end - if Input.trigger?(Input::RIGHT) || Input.repeat?(Input::RIGHT) - increment = (Input.press?(Input::ALT)) ? 1 : 8 - cel[AnimFrame::X] += increment - @dirty[@currentcel] = true - end - end - end - end - def update - super - if @playing - if @player.animDone? - @playing = false - invalidate - else - @player.update - end - return + def deleteCel(cel) + return if cel < 0 + return if @currentframe < 0 || @currentframe >= @animation.length + return if !deletable?(cel) + @animation[@currentframe][cel] = nil + @dirty[cel] = true end - updateInput -# @testscreen.update -# self.bitmap=@testscreen.bitmap - if @currentframe < @animation.length + + def swapCels(cel1, cel2) + return if cel1 < 0 || cel2 < 0 + return if @currentframe < 0 || @currentframe >= @animation.length + t = @animation[@currentframe][cel1] + @animation[@currentframe][cel1] = @animation[@currentframe][cel2] + @animation[@currentframe][cel2] = t + @currentcel = cel2 + @dirty[cel1] = true + @dirty[cel2] = true + end + + def locked?(celindex) + cel = @animation[self.currentframe] + return false if !cel + cel = cel[celindex] + return cel ? (cel[AnimFrame::LOCKED] != 0) : false + end + + def deletable?(celindex) + cel = @animation[self.currentframe] + return true if !cel + cel = cel[celindex] + return true if !cel + return false if cel[AnimFrame::LOCKED] != 0 + if cel[AnimFrame::PATTERN] < 0 + count = 0 + pattern = cel[AnimFrame::PATTERN] + PBAnimation::MAX_SPRITES.times do |i| + othercel = @animation[self.currentframe][i] + count += 1 if othercel && othercel[AnimFrame::PATTERN] == pattern + end + return false if count <= 1 + end + return true + end + + def setBitmap(i, frame) + if @celsprites[i] + cel = @animation[frame][i] + @celsprites[i].bitmap = @animbitmap + if cel + @celsprites[i].bitmap = @user if cel[AnimFrame::PATTERN] == -1 + @celsprites[i].bitmap = @target if cel[AnimFrame::PATTERN] == -2 + end + end + end + + def setSpriteBitmap(sprite, cel) + if sprite && !sprite.disposed? + sprite.bitmap = @animbitmap + if cel + sprite.bitmap = @user if cel[AnimFrame::PATTERN] == -1 + sprite.bitmap = @target if cel[AnimFrame::PATTERN] == -2 + end + end + end + + def addSprite(x, y) + return false if @currentframe >= @animation.length PBAnimation::MAX_SPRITES.times do |i| - next if !@dirty[i] - if @celsprites[i] - setBitmap(i, @currentframe) - pbSpriteSetAnimFrame(@celsprites[i], @animation[@currentframe][i], @celsprites[0], @celsprites[1], true) + next if @animation[@currentframe][i] + @animation[@currentframe][i] = pbCreateCel(x, y, @pattern, @animation.position) + @dirty[i] = true + @currentcel = i + return true + end + return false + end + + def pbSpriteHitTest(sprite, x, y, usealpha = true, wholecanvas = false) + return false if !sprite || sprite.disposed? + return false if !sprite.bitmap + return false if !sprite.visible + return false if sprite.bitmap.disposed? + width = sprite.src_rect.width + height = sprite.src_rect.height + if wholecanvas + xwidth = 0 + xheight = 0 + else + xwidth = width - 64 + xheight = height - 64 + width = 64 if width > 64 && !usealpha + height = 64 if height > 64 && !usealpha + end + width = sprite.bitmap.width if width > sprite.bitmap.width + height = sprite.bitmap.height if height > sprite.bitmap.height + if usealpha + spritex = sprite.x - (sprite.ox * sprite.zoom_x) + spritey = sprite.y - (sprite.oy * sprite.zoom_y) + width *= sprite.zoom_x + height *= sprite.zoom_y + else + spritex = sprite.x - sprite.ox + spritey = sprite.y - sprite.oy + spritex += xwidth / 2 + spritey += xheight / 2 + end + if !(x >= spritex && x <= spritex + width && y >= spritey && y <= spritey + height) + return false + end + if usealpha + # TODO: This should account for sprite.angle as well + bitmapX = sprite.src_rect.x + bitmapY = sprite.src_rect.y + bitmapX += sprite.ox + bitmapY += sprite.oy + bitmapX += (x - sprite.x) / sprite.zoom_x if sprite.zoom_x > 0 + bitmapY += (y - sprite.y) / sprite.zoom_y if sprite.zoom_y > 0 + bitmapX = bitmapX.round + bitmapY = bitmapY.round + if sprite.mirror + xmirror = bitmapX - sprite.src_rect.x + bitmapX = sprite.src_rect.x + 192 - xmirror + end + color = sprite.bitmap.get_pixel(bitmapX, bitmapY) + return false if color.alpha == 0 + end + return true + end + + def updateInput + cel = currentCel + mousepos = Mouse.getMousePos + if Input.trigger?(Input::MOUSELEFT) && mousepos && + pbSpriteHitTest(self, mousepos[0], mousepos[1], false, true) + selectedcel = -1 + usealpha = Input.press?(Input::ALT) + PBAnimation::MAX_SPRITES.times do |j| + if pbSpriteHitTest(@celsprites[j], mousepos[0], mousepos[1], usealpha, false) + selectedcel = j + end + end + if selectedcel < 0 + if @animbitmap && addSprite(mousepos[0] - BORDERSIZE, mousepos[1] - BORDERSIZE) + @selecting = true if !self.locked?(@currentcel) + @selectOffsetX = 0 + @selectOffsetY = 0 + cel = currentCel + invalidate + end + else + @currentcel = selectedcel + @selecting = true if !self.locked?(@currentcel) + cel = currentCel + @selectOffsetX = cel[AnimFrame::X] - mousepos[0] + BORDERSIZE + @selectOffsetY = cel[AnimFrame::Y] - mousepos[1] + BORDERSIZE + invalidate + end + end + currentFrame = getCurrentFrame + if currentFrame && !@selecting && + (Input.triggerex?(:TAB) || Input.repeatex?(:TAB)) + currentFrame.length.times do + @currentcel += 1 + @currentcel = 0 if @currentcel >= currentFrame.length + break if currentFrame[@currentcel] + end + invalidate + return + end + if cel && @selecting && mousepos + cel[AnimFrame::X] = mousepos[0] - BORDERSIZE + @selectOffsetX + cel[AnimFrame::Y] = mousepos[1] - BORDERSIZE + @selectOffsetY + @dirty[@currentcel] = true + end + if !Input.press?(Input::MOUSELEFT) && @selecting + @selecting = false + end + if cel + if (Input.triggerex?(:DELETE) || Input.repeatex?(:DELETE)) && self.deletable?(@currentcel) + @animation[@currentframe][@currentcel] = nil + @dirty[@currentcel] = true + return + end + if Input.triggerex?(:P) || Input.repeatex?(:P) # Properties + BattleAnimationEditor.pbCellProperties(self) + @dirty[@currentcel] = true + return + end + if Input.triggerex?(:L) || Input.repeatex?(:L) # Lock + cel[AnimFrame::LOCKED] = (cel[AnimFrame::LOCKED] == 0) ? 1 : 0 + @dirty[@currentcel] = true + end + if Input.triggerex?(:R) || Input.repeatex?(:R) # Rotate right + cel[AnimFrame::ANGLE] += 10 + cel[AnimFrame::ANGLE] %= 360 + @dirty[@currentcel] = true + end + if Input.triggerex?(:E) || Input.repeatex?(:E) # Rotate left + cel[AnimFrame::ANGLE] -= 10 + cel[AnimFrame::ANGLE] %= 360 + @dirty[@currentcel] = true + end + if Input.triggerex?(:KP_PLUS) || Input.repeatex?(:KP_PLUS) # Zoom in + cel[AnimFrame::ZOOMX] += 10 + cel[AnimFrame::ZOOMX] = 1000 if cel[AnimFrame::ZOOMX] > 1000 + cel[AnimFrame::ZOOMY] += 10 + cel[AnimFrame::ZOOMY] = 1000 if cel[AnimFrame::ZOOMY] > 1000 + @dirty[@currentcel] = true + end + if Input.triggerex?(:KP_MINUS) || Input.repeatex?(:KP_MINUS) # Zoom out + cel[AnimFrame::ZOOMX] -= 10 + cel[AnimFrame::ZOOMX] = 10 if cel[AnimFrame::ZOOMX] < 10 + cel[AnimFrame::ZOOMY] -= 10 + cel[AnimFrame::ZOOMY] = 10 if cel[AnimFrame::ZOOMY] < 10 + @dirty[@currentcel] = true + end + if !self.locked?(@currentcel) + if Input.trigger?(Input::UP) || Input.repeat?(Input::UP) + increment = (Input.press?(Input::ALT)) ? 1 : 8 + cel[AnimFrame::Y] -= increment + @dirty[@currentcel] = true + end + if Input.trigger?(Input::DOWN) || Input.repeat?(Input::DOWN) + increment = (Input.press?(Input::ALT)) ? 1 : 8 + cel[AnimFrame::Y] += increment + @dirty[@currentcel] = true + end + if Input.trigger?(Input::LEFT) || Input.repeat?(Input::LEFT) + increment = (Input.press?(Input::ALT)) ? 1 : 8 + cel[AnimFrame::X] -= increment + @dirty[@currentcel] = true + end + if Input.trigger?(Input::RIGHT) || Input.repeat?(Input::RIGHT) + increment = (Input.press?(Input::ALT)) ? 1 : 8 + cel[AnimFrame::X] += increment + @dirty[@currentcel] = true + end + end + end + end + + def update + super + if @playing + if @player.animDone? + @playing = false + invalidate + else + @player.update + end + return + end + updateInput + # @testscreen.update + # self.bitmap=@testscreen.bitmap + if @currentframe < @animation.length + PBAnimation::MAX_SPRITES.times do |i| + next if !@dirty[i] + if @celsprites[i] + setBitmap(i, @currentframe) + pbSpriteSetAnimFrame(@celsprites[i], @animation[@currentframe][i], @celsprites[0], @celsprites[1], true) + @celsprites[i].x += BORDERSIZE + @celsprites[i].y += BORDERSIZE + end + setPreviousFrame(i) + setFrame(i) + @dirty[i] = false + end + else + PBAnimation::MAX_SPRITES.times do |i| + pbSpriteSetAnimFrame(@celsprites[i], nil, @celsprites[0], @celsprites[1], true) @celsprites[i].x += BORDERSIZE @celsprites[i].y += BORDERSIZE + setPreviousFrame(i) + setFrame(i) + @dirty[i] = false end - setPreviousFrame(i) - setFrame(i) - @dirty[i] = false - end - else - PBAnimation::MAX_SPRITES.times do |i| - pbSpriteSetAnimFrame(@celsprites[i], nil, @celsprites[0], @celsprites[1], true) - @celsprites[i].x += BORDERSIZE - @celsprites[i].y += BORDERSIZE - setPreviousFrame(i) - setFrame(i) - @dirty[i] = false end end end -end -#=============================================================================== -# Window classes -#=============================================================================== -class BitmapDisplayWindow < SpriteWindow_Base - attr_reader :bitmapname - attr_reader :hue + #=============================================================================== + # Window classes + #=============================================================================== + class BitmapDisplayWindow < SpriteWindow_Base + attr_reader :bitmapname + attr_reader :hue - def initialize(x, y, width, height) - super(x, y, width, height) - @bitmapname = "" - @hue = 0 - self.contents = Bitmap.new(width - 32, height - 32) - end + def initialize(x, y, width, height) + super(x, y, width, height) + @bitmapname = "" + @hue = 0 + self.contents = Bitmap.new(width - 32, height - 32) + end - def bitmapname=(value) - if @bitmapname != value - @bitmapname = value - refresh + def bitmapname=(value) + if @bitmapname != value + @bitmapname = value + refresh + end + end + + def hue=(value) + if @hue != value + @hue = value + refresh + end + end + + def refresh + self.contents.clear + bmap = AnimatedBitmap.new("Graphics/Animations/" + @bitmapname, @hue).deanimate + return if !bmap + ww = bmap.width + wh = bmap.height + sx = self.contents.width / ww.to_f + sy = self.contents.height / wh.to_f + if sx > sy + ww = sy * ww + wh = self.contents.height + else + wh = sx * wh + ww = self.contents.width + end + dest = Rect.new((self.contents.width - ww) / 2, + (self.contents.height - wh) / 2, + ww, wh) + src = Rect.new(0, 0, bmap.width, bmap.height) + self.contents.stretch_blt(dest, bmap, src) + bmap.dispose end end - def hue=(value) - if @hue != value - @hue = value - refresh + #=============================================================================== + # + #=============================================================================== + class AnimationNameWindow + def initialize(canvas, x, y, width, height, viewport = nil) + @canvas = canvas + @oldname = nil + @window = Window_UnformattedTextPokemon.newWithSize( + _INTL("Name: {1}", @canvas.animation.name), x, y, width, height, viewport + ) end - end - def refresh - self.contents.clear - bmap = AnimatedBitmap.new("Graphics/Animations/" + @bitmapname, @hue).deanimate - return if !bmap - ww = bmap.width - wh = bmap.height - sx = self.contents.width / ww.to_f - sy = self.contents.height / wh.to_f - if sx > sy - ww = sy * ww - wh = self.contents.height - else - wh = sx * wh - ww = self.contents.width + def viewport=(value); @window.viewport = value; end + + def update + newtext = _INTL("Name: {1}", @canvas.animation.name) + if @oldname != newtext + @window.text = newtext + @oldname = newtext + end + @window.update end - dest = Rect.new((self.contents.width - ww) / 2, - (self.contents.height - wh) / 2, - ww, wh) - src = Rect.new(0, 0, bmap.width, bmap.height) - self.contents.stretch_blt(dest, bmap, src) - bmap.dispose + + def refresh; @window.refresh; end + def dispose; @window.dispose; end + def disposed; @window.disposed?; end end end - -#=============================================================================== -# -#=============================================================================== -class AnimationNameWindow - def initialize(canvas, x, y, width, height, viewport = nil) - @canvas = canvas - @oldname = nil - @window = Window_UnformattedTextPokemon.newWithSize( - _INTL("Name: {1}", @canvas.animation.name), x, y, width, height, viewport - ) - end - - def viewport=(value); @window.viewport = value; end - - def update - newtext = _INTL("Name: {1}", @canvas.animation.name) - if @oldname != newtext - @window.text = newtext - @oldname = newtext - end - @window.update - end - - def refresh; @window.refresh; end - def dispose; @window.dispose; end - def disposed; @window.disposed?; end -end diff --git a/Data/Scripts/020_Debug/002_Animation editor/002_AnimEditor_ControlsButtons.rb b/Data/Scripts/020_Debug/002_Animation editor/002_AnimEditor_ControlsButtons.rb index 362155902..f14572f92 100644 --- a/Data/Scripts/020_Debug/002_Animation editor/002_AnimEditor_ControlsButtons.rb +++ b/Data/Scripts/020_Debug/002_Animation editor/002_AnimEditor_ControlsButtons.rb @@ -1,929 +1,932 @@ -#=============================================================================== -# -#=============================================================================== -module ShadowText - def shadowtext(bitmap, x, y, w, h, t, disabled = false, align = 0) - width = bitmap.text_size(t).width - case align - when 2 - x += (w - width) - when 1 - x += (w / 2) - (width / 2) - end - pbDrawShadowText(bitmap, x, y + 6, w, h, t, - disabled ? Color.new(208, 208, 200) : Color.new(96, 96, 96), - Color.new(208, 208, 200)) - end -end +module BattleAnimationEditor + module_function -#=============================================================================== -# -#=============================================================================== -class UIControl - include ShadowText - attr_accessor :bitmap - attr_accessor :label - attr_accessor :x - attr_accessor :y - attr_accessor :width - attr_accessor :height - attr_accessor :changed - attr_accessor :parent - attr_accessor :disabled - - def text - return self.label - end - - def text=(value) - self.label = value - end - - def initialize(label) - @label = label - @x = 0 - @y = 0 - @width = 0 - @height = 0 - @changed = false - @disabled = false - @invalid = true - end - - def toAbsoluteRect(rc) - return Rect.new(rc.x + self.parentX, rc.y + self.parentY, rc.width, rc.height) - end - - def parentX - return 0 if !self.parent - return self.parent.x + self.parent.leftEdge if self.parent.is_a?(SpriteWindow) - return self.parent.x + 16 if self.parent.is_a?(Window) - return self.parent.x - end - - def parentY - return 0 if !self.parent - return self.parent.y + self.parent.topEdge if self.parent.is_a?(SpriteWindow) - return self.parent.y + 16 if self.parent.is_a?(Window) - return self.parent.y - end - - def invalid? - return @invalid - end - - def invalidate # Marks that the control must be redrawn to reflect current logic - @invalid = true - end - - def update; end # Updates the logic on the control, invalidating it if necessary - - def refresh; end # Redraws the control - - def validate # Makes the control no longer invalid - @invalid = false - end - - def repaint # Redraws the control only if it is invalid - if self.invalid? - self.refresh - self.validate + #=============================================================================== + # + #=============================================================================== + module ShadowText + def shadowtext(bitmap, x, y, w, h, t, disabled = false, align = 0) + width = bitmap.text_size(t).width + case align + when 2 + x += (w - width) + when 1 + x += (w / 2) - (width / 2) + end + pbDrawShadowText(bitmap, x, y + 6, w, h, t, + disabled ? Color.new(208, 208, 200) : Color.new(96, 96, 96), + Color.new(208, 208, 200)) end end -end -#=============================================================================== -# -#=============================================================================== -class Label < UIControl - def text=(value) - self.label = value - refresh - end + #=============================================================================== + # + #=============================================================================== + class UIControl + include ShadowText + attr_accessor :bitmap + attr_accessor :label + attr_accessor :x + attr_accessor :y + attr_accessor :width + attr_accessor :height + attr_accessor :changed + attr_accessor :parent + attr_accessor :disabled - def refresh - bitmap = self.bitmap - bitmap.fill_rect(self.x, self.y, self.width, self.height, Color.new(0, 0, 0, 0)) - size = bitmap.text_size(self.label).width - shadowtext(bitmap, self.x + 4, self.y, size, self.height, self.label, @disabled) - end -end - -#=============================================================================== -# -#=============================================================================== -class Button < UIControl - attr_accessor :label - - def initialize(label) - super - @captured = false - @label = label - end - - def update - mousepos = Mouse.getMousePos - self.changed = false - return if !mousepos - rect = Rect.new(self.x + 1, self.y + 1, self.width - 2, self.height - 2) - rect = toAbsoluteRect(rect) - if Input.trigger?(Input::MOUSELEFT) && - rect.contains(mousepos[0], mousepos[1]) && !@captured - @captured = true - self.invalidate + def text + return self.label end - if Input.release?(Input::MOUSELEFT) && @captured - self.changed = true if rect.contains(mousepos[0], mousepos[1]) + + def text=(value) + self.label = value + end + + def initialize(label) + @label = label + @x = 0 + @y = 0 + @width = 0 + @height = 0 + @changed = false + @disabled = false + @invalid = true + end + + def toAbsoluteRect(rc) + return Rect.new(rc.x + self.parentX, rc.y + self.parentY, rc.width, rc.height) + end + + def parentX + return 0 if !self.parent + return self.parent.x + self.parent.leftEdge if self.parent.is_a?(SpriteWindow) + return self.parent.x + 16 if self.parent.is_a?(Window) + return self.parent.x + end + + def parentY + return 0 if !self.parent + return self.parent.y + self.parent.topEdge if self.parent.is_a?(SpriteWindow) + return self.parent.y + 16 if self.parent.is_a?(Window) + return self.parent.y + end + + def invalid? + return @invalid + end + + def invalidate # Marks that the control must be redrawn to reflect current logic + @invalid = true + end + + def update; end # Updates the logic on the control, invalidating it if necessary + + def refresh; end # Redraws the control + + def validate # Makes the control no longer invalid + @invalid = false + end + + def repaint # Redraws the control only if it is invalid + if self.invalid? + self.refresh + self.validate + end + end + end + + #=============================================================================== + # + #=============================================================================== + class Label < UIControl + def text=(value) + self.label = value + refresh + end + + def refresh + bitmap = self.bitmap + bitmap.fill_rect(self.x, self.y, self.width, self.height, Color.new(0, 0, 0, 0)) + size = bitmap.text_size(self.label).width + shadowtext(bitmap, self.x + 4, self.y, size, self.height, self.label, @disabled) + end + end + + #=============================================================================== + # + #=============================================================================== + class Button < UIControl + attr_accessor :label + + def initialize(label) + super @captured = false - self.invalidate + @label = label end - end - def refresh - bitmap = self.bitmap - x = self.x - y = self.y - width = self.width - height = self.height - # Draw background - if @captured - bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(120, 120, 120, 80)) - else - bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(0, 0, 0, 0)) - end - # Draw text - size = bitmap.text_size(self.label).width - shadowtext(bitmap, x + 4, y, size, height, self.label, @disabled) - # Draw outline - color = Color.new(120, 120, 120) - bitmap.fill_rect(x + 1, y + 1, width - 2, 1, color) - bitmap.fill_rect(x + 1, y + 1, 1, height - 2, color) - bitmap.fill_rect(x + 1, y + height - 2, width - 2, 1, color) - bitmap.fill_rect(x + width - 2, y + 1, 1, height - 2, color) - # Return the control's clickable area - ret = Rect.new(x + 1, y + 1, width - 2, height - 2) - return ret - end -end - -#=============================================================================== -# -#=============================================================================== -class Checkbox < Button - attr_reader :checked - - def curvalue - return self.checked - end - - def curvalue=(value) - self.checked = value - end - - def checked=(value) - @checked = value - invalidate - end - - def initialize(label) - super - @checked = false - end - - def update - super - if self.changed - @checked = !@checked - self.invalidate - end - end - - def refresh - bitmap = self.bitmap - x = self.x - y = self.y - width = [self.width, 32].min - height = [self.height, 32].min - # Draw background - bitmap.fill_rect(x + 2, y + 2, self.width - 4, self.height - 4, Color.new(0, 0, 0, 0)) - if @captured - bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(120, 120, 120, 80)) - else - bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(0, 0, 0, 0)) - end - # Draw text - shadowtext(bitmap, x, y, 32, 32, "X", @disabled, 1) if self.checked - size = bitmap.text_size(self.label).width - shadowtext(bitmap, x + 36, y, size, height, self.label, @disabled) - # Draw outline - color = Color.new(120, 120, 120) - bitmap.fill_rect(x + 1, y + 1, width - 2, height - 2, color) - bitmap.fill_rect(x + 1, y + 1, width - 2, 1, color) - bitmap.fill_rect(x + 1, y + 1, 1, height - 2, color) - bitmap.fill_rect(x + 1, y + height - 2, width - 2, 1, color) - bitmap.fill_rect(x + width - 2, y + 1, 1, height - 2, color) - # Return the control's clickable area - ret = Rect.new(x + 1, y + 1, width - 2, height - 2) - return ret - end -end - -#=============================================================================== -# -#=============================================================================== -class TextField < UIControl - attr_accessor :label - attr_reader :text - - def text=(value) - @text = value - self.invalidate - end - - def initialize(label, text) - super(label) - @frame = 0 - @label = label - @text = text - @cursor = text.scan(/./m).length - end - - def insert(ch) - chars = self.text.scan(/./m) - chars.insert(@cursor, ch) - @text = "" - chars.each { |char| @text += char } - @cursor += 1 - @frame = 0 - self.changed = true - self.invalidate - end - - def delete - chars = self.text.scan(/./m) - chars.delete_at(@cursor - 1) - @text = "" - chars.each { |char| @text += char } - @cursor -= 1 - @frame = 0 - self.changed = true - self.invalidate - end - - def update - @frame += 1 - @frame %= 20 - self.changed = false - self.invalidate if (@frame % 10) == 0 - # Moving cursor - if Input.triggerex?(:LEFT) || Input.repeatex?(:LEFT) - if @cursor > 0 - @cursor -= 1 - @frame = 0 + def update + mousepos = Mouse.getMousePos + self.changed = false + return if !mousepos + rect = Rect.new(self.x + 1, self.y + 1, self.width - 2, self.height - 2) + rect = toAbsoluteRect(rect) + if Input.trigger?(Input::MOUSELEFT) && + rect.contains?(mousepos[0], mousepos[1]) && !@captured + @captured = true self.invalidate end - return - end - if Input.triggerex?(:RIGHT) || Input.repeatex?(:RIGHT) - if @cursor < self.text.scan(/./m).length - @cursor += 1 - @frame = 0 + if Input.release?(Input::MOUSELEFT) && @captured + self.changed = true if rect.contains?(mousepos[0], mousepos[1]) + @captured = false self.invalidate end - return end - # Backspace - if Input.triggerex?(:BACKSPACE) || Input.repeatex?(:BACKSPACE) || - Input.triggerex?(:DELETE) || Input.repeatex?(:DELETE) - self.delete if @cursor > 0 - return - end - # Letter & Number keys - Input.gets.each_char { |c| insert(c) } - end - def refresh - bitmap = self.bitmap - x = self.x - y = self.y - width = self.width - height = self.height - color = Color.new(120, 120, 120) - bitmap.font.color = color - bitmap.fill_rect(x, y, width, height, Color.new(0, 0, 0, 0)) - size = bitmap.text_size(self.label).width - shadowtext(bitmap, x, y, size, height, self.label) - x += size - width -= size - outline_x = x - outline_y = y - # Draw background - if @captured - bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(120, 120, 120, 80)) - else - bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(0, 0, 0, 0)) - end - # Draw text - x += 4 - textscan = self.text.scan(/./m) - scanlength = textscan.length - @cursor = scanlength if @cursor > scanlength - @cursor = 0 if @cursor < 0 - startpos = @cursor - fromcursor = 0 - while startpos > 0 - c = textscan[startpos - 1] - fromcursor += bitmap.text_size(c).width - break if fromcursor > width - 4 - startpos -= 1 - end - (startpos...scanlength).each do |i| - c = textscan[i] - textwidth = bitmap.text_size(c).width - next if c == "\n" + def refresh + bitmap = self.bitmap + x = self.x + y = self.y + width = self.width + height = self.height + # Draw background + if @captured + bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(120, 120, 120, 80)) + else + bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(0, 0, 0, 0)) + end # Draw text - shadowtext(bitmap, x, y, textwidth + 4, 32, c) - # Draw cursor if necessary - if ((@frame / 10) & 1) == 0 && i == @cursor + size = bitmap.text_size(self.label).width + shadowtext(bitmap, x + 4, y, size, height, self.label, @disabled) + # Draw outline + color = Color.new(120, 120, 120) + bitmap.fill_rect(x + 1, y + 1, width - 2, 1, color) + bitmap.fill_rect(x + 1, y + 1, 1, height - 2, color) + bitmap.fill_rect(x + 1, y + height - 2, width - 2, 1, color) + bitmap.fill_rect(x + width - 2, y + 1, 1, height - 2, color) + # Return the control's clickable area + ret = Rect.new(x + 1, y + 1, width - 2, height - 2) + return ret + end + end + + #=============================================================================== + # + #=============================================================================== + class Checkbox < Button + attr_reader :checked + + def curvalue + return self.checked + end + + def curvalue=(value) + self.checked = value + end + + def checked=(value) + @checked = value + invalidate + end + + def initialize(label) + super + @checked = false + end + + def update + super + if self.changed + @checked = !@checked + self.invalidate + end + end + + def refresh + bitmap = self.bitmap + x = self.x + y = self.y + width = [self.width, 32].min + height = [self.height, 32].min + # Draw background + bitmap.fill_rect(x + 2, y + 2, self.width - 4, self.height - 4, Color.new(0, 0, 0, 0)) + if @captured + bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(120, 120, 120, 80)) + else + bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(0, 0, 0, 0)) + end + # Draw text + shadowtext(bitmap, x, y, 32, 32, "X", @disabled, 1) if self.checked + size = bitmap.text_size(self.label).width + shadowtext(bitmap, x + 36, y, size, height, self.label, @disabled) + # Draw outline + color = Color.new(120, 120, 120) + bitmap.fill_rect(x + 1, y + 1, width - 2, 1, color) + bitmap.fill_rect(x + 1, y + 1, 1, height - 2, color) + bitmap.fill_rect(x + 1, y + height - 2, width - 2, 1, color) + bitmap.fill_rect(x + width - 2, y + 1, 1, height - 2, color) + # Return the control's clickable area + ret = Rect.new(x + 1, y + 1, width - 2, height - 2) + return ret + end + end + + #=============================================================================== + # + #=============================================================================== + class TextField < UIControl + attr_accessor :label + attr_reader :text + + def text=(value) + @text = value + self.invalidate + end + + def initialize(label, text) + super(label) + @frame = 0 + @label = label + @text = text + @cursor = text.scan(/./m).length + end + + def insert(ch) + chars = self.text.scan(/./m) + chars.insert(@cursor, ch) + @text = "" + chars.each { |char| @text += char } + @cursor += 1 + @frame = 0 + self.changed = true + self.invalidate + end + + def delete + chars = self.text.scan(/./m) + chars.delete_at(@cursor - 1) + @text = "" + chars.each { |char| @text += char } + @cursor -= 1 + @frame = 0 + self.changed = true + self.invalidate + end + + def update + @frame += 1 + @frame %= 20 + self.changed = false + self.invalidate if (@frame % 10) == 0 + # Moving cursor + if Input.triggerex?(:LEFT) || Input.repeatex?(:LEFT) + if @cursor > 0 + @cursor -= 1 + @frame = 0 + self.invalidate + end + return + end + if Input.triggerex?(:RIGHT) || Input.repeatex?(:RIGHT) + if @cursor < self.text.scan(/./m).length + @cursor += 1 + @frame = 0 + self.invalidate + end + return + end + # Backspace + if Input.triggerex?(:BACKSPACE) || Input.repeatex?(:BACKSPACE) || + Input.triggerex?(:DELETE) || Input.repeatex?(:DELETE) + self.delete if @cursor > 0 + return + end + # Letter & Number keys + Input.gets.each_char { |c| insert(c) } + end + + def refresh + bitmap = self.bitmap + x = self.x + y = self.y + width = self.width + height = self.height + color = Color.new(120, 120, 120) + bitmap.font.color = color + bitmap.fill_rect(x, y, width, height, Color.new(0, 0, 0, 0)) + size = bitmap.text_size(self.label).width + shadowtext(bitmap, x, y, size, height, self.label) + x += size + width -= size + outline_x = x + outline_y = y + # Draw background + if @captured + bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(120, 120, 120, 80)) + else + bitmap.fill_rect(x + 2, y + 2, width - 4, height - 4, Color.new(0, 0, 0, 0)) + end + # Draw text + x += 4 + textscan = self.text.scan(/./m) + scanlength = textscan.length + @cursor = scanlength if @cursor > scanlength + @cursor = 0 if @cursor < 0 + startpos = @cursor + fromcursor = 0 + while startpos > 0 + c = textscan[startpos - 1] + fromcursor += bitmap.text_size(c).width + break if fromcursor > width - 4 + startpos -= 1 + end + (startpos...scanlength).each do |i| + c = textscan[i] + textwidth = bitmap.text_size(c).width + next if c == "\n" + # Draw text + shadowtext(bitmap, x, y, textwidth + 4, 32, c) + # Draw cursor if necessary + if ((@frame / 10) & 1) == 0 && i == @cursor + bitmap.fill_rect(x, y + 4, 2, 24, Color.new(120, 120, 120)) + end + # Add x to drawn text width + x += textwidth + end + if ((@frame / 10) & 1) == 0 && textscan.length == @cursor bitmap.fill_rect(x, y + 4, 2, 24, Color.new(120, 120, 120)) end - # Add x to drawn text width - x += textwidth + # Draw outline + bitmap.fill_rect(outline_x + 1, outline_y + 1, width - 2, 1, color) + bitmap.fill_rect(outline_x + 1, outline_y + 1, 1, height - 2, color) + bitmap.fill_rect(outline_x + 1, outline_y + height - 2, width - 2, 1, color) + bitmap.fill_rect(outline_x + width - 2, outline_y + 1, 1, height - 2, color) + # Return the control's clickable area + ret = Rect.new(x + 1, y + 1, width - 2, height - 2) + return ret end - if ((@frame / 10) & 1) == 0 && textscan.length == @cursor - bitmap.fill_rect(x, y + 4, 2, 24, Color.new(120, 120, 120)) - end - # Draw outline - bitmap.fill_rect(outline_x + 1, outline_y + 1, width - 2, 1, color) - bitmap.fill_rect(outline_x + 1, outline_y + 1, 1, height - 2, color) - bitmap.fill_rect(outline_x + 1, outline_y + height - 2, width - 2, 1, color) - bitmap.fill_rect(outline_x + width - 2, outline_y + 1, 1, height - 2, color) - # Return the control's clickable area - ret = Rect.new(x + 1, y + 1, width - 2, height - 2) - return ret - end -end - -#=============================================================================== -# -#=============================================================================== -class Slider < UIControl - attr_reader :minvalue - attr_reader :maxvalue - attr_reader :curvalue - attr_accessor :label - - def curvalue=(value) - @curvalue = value - @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue - @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue - self.invalidate end - def minvalue=(value) - @minvalue = value - @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue - @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue - self.invalidate - end + #=============================================================================== + # + #=============================================================================== + class Slider < UIControl + attr_reader :minvalue + attr_reader :maxvalue + attr_reader :curvalue + attr_accessor :label - def maxvalue=(value) - @maxvalue = value - @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue - @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue - self.invalidate - end - - def initialize(label, minvalue, maxvalue, curval) - super(label) - @minvalue = minvalue - @maxvalue = maxvalue - @curvalue = curval - @label = label - @leftarrow = Rect.new(0, 0, 0, 0) - @rightarrow = Rect.new(0, 0, 0, 0) - self.minvalue = minvalue - self.maxvalue = maxvalue - self.curvalue = curval - end - - def update - mousepos = Mouse.getMousePos - self.changed = false - if self.minvalue < self.maxvalue && self.curvalue < self.minvalue - self.curvalue = self.minvalue - end - return false if self.disabled - return false if !Input.repeat?(Input::MOUSELEFT) - return false if !mousepos - left = toAbsoluteRect(@leftarrow) - right = toAbsoluteRect(@rightarrow) - oldvalue = self.curvalue - repeattime = Input.time?(Input::MOUSELEFT) / 1000 - # Left arrow - if left.contains(mousepos[0], mousepos[1]) - if repeattime > 3000 - self.curvalue -= 10 - elsif repeattime > 1500 - self.curvalue -= 5 - else - self.curvalue -= 1 - end - self.curvalue = self.curvalue.floor - self.changed = (self.curvalue != oldvalue) + def curvalue=(value) + @curvalue = value + @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue + @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue self.invalidate end - # Right arrow - if right.contains(mousepos[0], mousepos[1]) - if repeattime > 3000 - self.curvalue += 10 - elsif repeattime > 1500 - self.curvalue += 5 - else - self.curvalue += 1 - end - self.curvalue = self.curvalue.floor - self.changed = (self.curvalue != oldvalue) + + def minvalue=(value) + @minvalue = value + @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue + @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue self.invalidate end - end - def refresh - bitmap = self.bitmap - x = self.x - y = self.y - width = self.width - height = self.height - color = Color.new(120, 120, 120) - bitmap.fill_rect(x, y, width, height, Color.new(0, 0, 0, 0)) - size = bitmap.text_size(self.label).width - leftarrows = bitmap.text_size(" <<") - numbers = bitmap.text_size(" XXXX ").width - rightarrows = bitmap.text_size(">> ") - bitmap.font.color = color - shadowtext(bitmap, x, y, size, height, self.label) - x += size - shadowtext(bitmap, x, y, leftarrows.width, height, " <<", - self.disabled || self.curvalue == self.minvalue) - @leftarrow = Rect.new(x, y, leftarrows.width, height) - x += leftarrows.width - if !self.disabled + def maxvalue=(value) + @maxvalue = value + @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue + @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue + self.invalidate + end + + def initialize(label, minvalue, maxvalue, curval) + super(label) + @minvalue = minvalue + @maxvalue = maxvalue + @curvalue = curval + @label = label + @leftarrow = Rect.new(0, 0, 0, 0) + @rightarrow = Rect.new(0, 0, 0, 0) + self.minvalue = minvalue + self.maxvalue = maxvalue + self.curvalue = curval + end + + def update + mousepos = Mouse.getMousePos + self.changed = false + if self.minvalue < self.maxvalue && self.curvalue < self.minvalue + self.curvalue = self.minvalue + end + return false if self.disabled + return false if !Input.repeat?(Input::MOUSELEFT) + return false if !mousepos + left = toAbsoluteRect(@leftarrow) + right = toAbsoluteRect(@rightarrow) + oldvalue = self.curvalue + repeattime = Input.time?(Input::MOUSELEFT) / 1000 + # Left arrow + if left.contains?(mousepos[0], mousepos[1]) + if repeattime > 3000 + self.curvalue -= 10 + elsif repeattime > 1500 + self.curvalue -= 5 + else + self.curvalue -= 1 + end + self.curvalue = self.curvalue.floor + self.changed = (self.curvalue != oldvalue) + self.invalidate + end + # Right arrow + if right.contains?(mousepos[0], mousepos[1]) + if repeattime > 3000 + self.curvalue += 10 + elsif repeattime > 1500 + self.curvalue += 5 + else + self.curvalue += 1 + end + self.curvalue = self.curvalue.floor + self.changed = (self.curvalue != oldvalue) + self.invalidate + end + end + + def refresh + bitmap = self.bitmap + x = self.x + y = self.y + width = self.width + height = self.height + color = Color.new(120, 120, 120) + bitmap.fill_rect(x, y, width, height, Color.new(0, 0, 0, 0)) + size = bitmap.text_size(self.label).width + leftarrows = bitmap.text_size(" <<") + numbers = bitmap.text_size(" XXXX ").width + rightarrows = bitmap.text_size(">> ") bitmap.font.color = color - shadowtext(bitmap, x, y, numbers, height, " #{self.curvalue} ", false, 1) - end - x += numbers - shadowtext(bitmap, x, y, rightarrows.width, height, ">> ", - self.disabled || self.curvalue == self.maxvalue) - @rightarrow = Rect.new(x, y, rightarrows.width, height) - end -end - -#=============================================================================== -# -#=============================================================================== -class OptionalSlider < Slider - def initialize(label, minvalue, maxvalue, curvalue) - @slider = Slider.new(label, minvalue, maxvalue, curvalue) - @checkbox = Checkbox.new("") - end - - def curvalue - return @checkbox.checked ? @slider.curvalue : nil - end - - def curvalue=(value) - slider.curvalue = value - end - - def checked - return @checkbox.checked - end - - def checked=(value) - @checkbox.checked = value - end - - def invalid? - return @slider.invalid? || @checkbox.invalid? - end - - def invalidate - @slider.invalidate - @checkbox.invalidate - end - - def validate? - @slider.validate - @checkbox.validate - end - - def changed - return @slider.changed || @checkbox.changed - end - - def minvalue - return @slider.minvalue - end - - def minvalue=(value) - slider.minvalue = value - end - - def maxvalue - return @slider.maxvalue - end - - def maxvalue=(value) - slider.maxvalue = value - end - - def update - updatedefs - @slider.update - @checkbox.update - end - - def refresh - updatedefs - @slider.refresh - @checkbox.refresh - end - - #----------------------------------------------------------------------------- - - private - - def updatedefs - checkboxwidth = 32 - @slider.bitmap = self.bitmap - @slider.parent = self.parent - @checkbox.x = self.x - @checkbox.y = self.y - @checkbox.width = checkboxwidth - @checkbox.height = self.height - @checkbox.bitmap = self.bitmap - @checkbox.parent = self.parent - @slider.x = self.x + checkboxwidth + 4 - @slider.y = self.y - @slider.width = self.width - checkboxwidth - @slider.height = self.height - @slider.disabled = !@checkbox.checked - end -end - -#=============================================================================== -# -#=============================================================================== -class ArrayCountSlider < Slider - def maxvalue - return @array.length - 1 - end - - def initialize(array, label) - @array = array - super(label, 0, canvas.animation.length - 1, 0) - end -end - -#=============================================================================== -# -#=============================================================================== -class FrameCountSlider < Slider - def maxvalue - return @canvas.animation.length - end - - def initialize(canvas) - @canvas = canvas - super(_INTL("Frame:"), 1, canvas.animation.length, 0) - end -end - -#=============================================================================== -# -#=============================================================================== -class FrameCountButton < Button - def label - return _INTL("Total Frames: {1}", @canvas.animation.length) - end - - def initialize(canvas) - @canvas = canvas - super(self.label) - end -end - -#=============================================================================== -# -#=============================================================================== -class TextSlider < UIControl - attr_reader :minvalue - attr_reader :maxvalue - attr_reader :curvalue - attr_accessor :label - attr_accessor :options - attr_accessor :maxoptionwidth - - def curvalue=(value) - @curvalue = value - @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue - @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue - self.invalidate - end - - def minvalue=(value) - @minvalue = value - @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue - @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue - self.invalidate - end - - def maxvalue=(value) - @maxvalue = value - @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue - @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue - self.invalidate - end - - def initialize(label, options, curval) - super(label) - @label = label - @options = options - @minvalue = 0 - @maxvalue = options.length - 1 - @curvalue = curval - @leftarrow = Rect.new(0, 0, 0, 0) - @rightarrow = Rect.new(0, 0, 0, 0) - self.minvalue = @minvalue - self.maxvalue = @maxvalue - self.curvalue = @curvalue - end - - def update - mousepos = Mouse.getMousePos - self.changed = false - if self.minvalue < self.maxvalue && self.curvalue < self.minvalue - self.curvalue = self.minvalue - end - return false if self.disabled - return false if !Input.repeat?(Input::MOUSELEFT) - return false if !mousepos - left = toAbsoluteRect(@leftarrow) - right = toAbsoluteRect(@rightarrow) - oldvalue = self.curvalue - repeattime = Input.time?(Input::MOUSELEFT) / 1000 - # Left arrow - if left.contains(mousepos[0], mousepos[1]) - if repeattime > 3000 - self.curvalue -= 10 - elsif repeattime > 1500 - self.curvalue -= 5 - else - self.curvalue -= 1 + shadowtext(bitmap, x, y, size, height, self.label) + x += size + shadowtext(bitmap, x, y, leftarrows.width, height, " <<", + self.disabled || self.curvalue == self.minvalue) + @leftarrow = Rect.new(x, y, leftarrows.width, height) + x += leftarrows.width + if !self.disabled + bitmap.font.color = color + shadowtext(bitmap, x, y, numbers, height, " #{self.curvalue} ", false, 1) end - self.changed = (self.curvalue != oldvalue) + x += numbers + shadowtext(bitmap, x, y, rightarrows.width, height, ">> ", + self.disabled || self.curvalue == self.maxvalue) + @rightarrow = Rect.new(x, y, rightarrows.width, height) + end + end + + #=============================================================================== + # + #=============================================================================== + class OptionalSlider < Slider + def initialize(label, minvalue, maxvalue, curvalue) + @slider = Slider.new(label, minvalue, maxvalue, curvalue) + @checkbox = Checkbox.new("") + end + + def curvalue + return @checkbox.checked ? @slider.curvalue : nil + end + + def curvalue=(value) + slider.curvalue = value + end + + def checked + return @checkbox.checked + end + + def checked=(value) + @checkbox.checked = value + end + + def invalid? + return @slider.invalid? || @checkbox.invalid? + end + + def invalidate + @slider.invalidate + @checkbox.invalidate + end + + def validate? + @slider.validate + @checkbox.validate + end + + def changed + return @slider.changed || @checkbox.changed + end + + def minvalue + return @slider.minvalue + end + + def minvalue=(value) + slider.minvalue = value + end + + def maxvalue + return @slider.maxvalue + end + + def maxvalue=(value) + slider.maxvalue = value + end + + def update + updatedefs + @slider.update + @checkbox.update + end + + def refresh + updatedefs + @slider.refresh + @checkbox.refresh + end + + #----------------------------------------------------------------------------- + + private + + def updatedefs + checkboxwidth = 32 + @slider.bitmap = self.bitmap + @slider.parent = self.parent + @checkbox.x = self.x + @checkbox.y = self.y + @checkbox.width = checkboxwidth + @checkbox.height = self.height + @checkbox.bitmap = self.bitmap + @checkbox.parent = self.parent + @slider.x = self.x + checkboxwidth + 4 + @slider.y = self.y + @slider.width = self.width - checkboxwidth + @slider.height = self.height + @slider.disabled = !@checkbox.checked + end + end + + #=============================================================================== + # + #=============================================================================== + class ArrayCountSlider < Slider + def maxvalue + return @array.length - 1 + end + + def initialize(array, label) + @array = array + super(label, 0, canvas.animation.length - 1, 0) + end + end + + #=============================================================================== + # + #=============================================================================== + class FrameCountSlider < Slider + def maxvalue + return @canvas.animation.length + end + + def initialize(canvas) + @canvas = canvas + super(_INTL("Frame:"), 1, canvas.animation.length, 0) + end + end + + #=============================================================================== + # + #=============================================================================== + class FrameCountButton < Button + def label + return _INTL("Total Frames: {1}", @canvas.animation.length) + end + + def initialize(canvas) + @canvas = canvas + super(self.label) + end + end + + #=============================================================================== + # + #=============================================================================== + class TextSlider < UIControl + attr_reader :minvalue + attr_reader :maxvalue + attr_reader :curvalue + attr_accessor :label + attr_accessor :options + attr_accessor :maxoptionwidth + + def curvalue=(value) + @curvalue = value + @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue + @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue self.invalidate end - # Right arrow - if right.contains(mousepos[0], mousepos[1]) - if repeattime > 3000 - self.curvalue += 10 - elsif repeattime > 1500 - self.curvalue += 5 - else - self.curvalue += 1 - end - self.changed = (self.curvalue != oldvalue) + + def minvalue=(value) + @minvalue = value + @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue + @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue self.invalidate end - end - def refresh - bitmap = self.bitmap - if @maxoptionwidth.nil? - @options.length.times do |i| - w = self.bitmap.text_size(" " + @options[i] + " ").width - @maxoptionwidth = w if !@maxoptionwidth || @maxoptionwidth < w + def maxvalue=(value) + @maxvalue = value + @curvalue = self.minvalue if self.minvalue && @curvalue < self.minvalue + @curvalue = self.maxvalue if self.maxvalue && @curvalue > self.maxvalue + self.invalidate + end + + def initialize(label, options, curval) + super(label) + @label = label + @options = options + @minvalue = 0 + @maxvalue = options.length - 1 + @curvalue = curval + @leftarrow = Rect.new(0, 0, 0, 0) + @rightarrow = Rect.new(0, 0, 0, 0) + self.minvalue = @minvalue + self.maxvalue = @maxvalue + self.curvalue = @curvalue + end + + def update + mousepos = Mouse.getMousePos + self.changed = false + if self.minvalue < self.maxvalue && self.curvalue < self.minvalue + self.curvalue = self.minvalue + end + return false if self.disabled + return false if !Input.repeat?(Input::MOUSELEFT) + return false if !mousepos + left = toAbsoluteRect(@leftarrow) + right = toAbsoluteRect(@rightarrow) + oldvalue = self.curvalue + repeattime = Input.time?(Input::MOUSELEFT) / 1000 + # Left arrow + if left.contains?(mousepos[0], mousepos[1]) + if repeattime > 3000 + self.curvalue -= 10 + elsif repeattime > 1500 + self.curvalue -= 5 + else + self.curvalue -= 1 + end + self.changed = (self.curvalue != oldvalue) + self.invalidate + end + # Right arrow + if right.contains?(mousepos[0], mousepos[1]) + if repeattime > 3000 + self.curvalue += 10 + elsif repeattime > 1500 + self.curvalue += 5 + else + self.curvalue += 1 + end + self.changed = (self.curvalue != oldvalue) + self.invalidate end end - x = self.x - y = self.y - width = self.width - height = self.height - color = Color.new(120, 120, 120) - bitmap.fill_rect(x, y, width, height, Color.new(0, 0, 0, 0)) - size = bitmap.text_size(self.label).width - leftarrows = bitmap.text_size(" <<") - rightarrows = bitmap.text_size(">> ") - bitmap.font.color = color - shadowtext(bitmap, x, y, size, height, self.label) - x += size - shadowtext(bitmap, x, y, leftarrows.width, height, " <<", - self.disabled || self.curvalue == self.minvalue) - @leftarrow = Rect.new(x, y, leftarrows.width, height) - x += leftarrows.width - if !self.disabled + + def refresh + bitmap = self.bitmap + if @maxoptionwidth.nil? + @options.length.times do |i| + w = self.bitmap.text_size(" " + @options[i] + " ").width + @maxoptionwidth = w if !@maxoptionwidth || @maxoptionwidth < w + end + end + x = self.x + y = self.y + width = self.width + height = self.height + color = Color.new(120, 120, 120) + bitmap.fill_rect(x, y, width, height, Color.new(0, 0, 0, 0)) + size = bitmap.text_size(self.label).width + leftarrows = bitmap.text_size(" <<") + rightarrows = bitmap.text_size(">> ") bitmap.font.color = color - shadowtext(bitmap, x, y, @maxoptionwidth, height, " #{@options[self.curvalue]} ", false, 1) + shadowtext(bitmap, x, y, size, height, self.label) + x += size + shadowtext(bitmap, x, y, leftarrows.width, height, " <<", + self.disabled || self.curvalue == self.minvalue) + @leftarrow = Rect.new(x, y, leftarrows.width, height) + x += leftarrows.width + if !self.disabled + bitmap.font.color = color + shadowtext(bitmap, x, y, @maxoptionwidth, height, " #{@options[self.curvalue]} ", false, 1) + end + x += @maxoptionwidth + shadowtext(bitmap, x, y, rightarrows.width, height, ">> ", + self.disabled || self.curvalue == self.maxvalue) + @rightarrow = Rect.new(x, y, rightarrows.width, height) + end + end + + #=============================================================================== + # + #=============================================================================== + class OptionalTextSlider < TextSlider + def initialize(label, options, curval) + @slider = TextSlider.new(label, options, curval) + @checkbox = Checkbox.new("") + end + + def curvalue + return @checkbox.checked ? @slider.curvalue : nil + end + + def curvalue=(value) + slider.curvalue = value + end + + def checked + return @checkbox.checked + end + + def checked=(value) + @checkbox.checked = value + end + + def invalid? + return @slider.invalid? || @checkbox.invalid? + end + + def invalidate + @slider.invalidate + @checkbox.invalidate + end + + def validate? + @slider.validate + @checkbox.validate + end + + def changed + return @slider.changed || @checkbox.changed + end + + def minvalue + return @slider.minvalue + end + + def minvalue=(value) + slider.minvalue = value + end + + def maxvalue + return @slider.maxvalue + end + + def maxvalue=(value) + slider.maxvalue = value + end + + def update + updatedefs + @slider.update + @checkbox.update + end + + def refresh + updatedefs + @slider.refresh + @checkbox.refresh + end + + #----------------------------------------------------------------------------- + + private + + def updatedefs + checkboxwidth = 32 + @slider.bitmap = self.bitmap + @slider.parent = self.parent + @checkbox.x = self.x + @checkbox.y = self.y + @checkbox.width = checkboxwidth + @checkbox.height = self.height + @checkbox.bitmap = self.bitmap + @checkbox.parent = self.parent + @slider.x = self.x + checkboxwidth + 4 + @slider.y = self.y + @slider.width = self.width - checkboxwidth + @slider.height = self.height + @slider.disabled = !@checkbox.checked + end + end + + #=============================================================================== + # + #=============================================================================== + class ControlWindow < SpriteWindow_Base + attr_reader :controls + + def initialize(x, y, width, height) + super(x, y, width, height) + self.contents = Bitmap.new(width - 32, height - 32) + pbSetNarrowFont(self.contents) + @controls = [] + end + + def dispose + self.contents.dispose + super + end + + def refresh + @controls.each { |ctrl| ctrl.refresh } + end + + def repaint + @controls.each { |ctrl| ctrl.repaint } + end + + def invalidate + @controls.each { |ctrl| ctrl.invalidate } + end + + def hittest?(i) + mousepos = Mouse.getMousePos + return false if !mousepos + return false if i < 0 || i >= @controls.length + rc = Rect.new(@controls[i].parentX, @controls[i].parentY, + @controls[i].width, @controls[i].height) + return rc.contains?(mousepos[0], mousepos[1]) + end + + def addControl(control) + i = @controls.length + @controls[i] = control + @controls[i].x = 0 + @controls[i].y = i * 32 + @controls[i].width = self.contents.width + @controls[i].height = 32 + @controls[i].parent = self + @controls[i].bitmap = self.contents + @controls[i].invalidate + refresh + return i + end + + def addLabel(label) + return addControl(Label.new(label)) + end + + def addButton(label) + return addControl(Button.new(label)) + end + + def addSlider(label, minvalue, maxvalue, curvalue) + return addControl(Slider.new(label, minvalue, maxvalue, curvalue)) + end + + def addOptionalSlider(label, minvalue, maxvalue, curvalue) + return addControl(OptionalSlider.new(label, minvalue, maxvalue, curvalue)) + end + + def addTextSlider(label, options, curvalue) + return addControl(TextSlider.new(label, options, curvalue)) + end + + def addOptionalTextSlider(label, options, curvalue) + return addControl(OptionalTextSlider.new(label, options, curvalue)) + end + + def addCheckbox(label) + return addControl(Checkbox.new(label)) + end + + def addSpace + return addControl(UIControl.new("")) + end + + def update + super + @controls.each { |ctrl| ctrl.update } + repaint + end + + def changed?(i) + return false if i < 0 + return @controls[i].changed + end + + def value(i) + return false if i < 0 + return @controls[i].curvalue end - x += @maxoptionwidth - shadowtext(bitmap, x, y, rightarrows.width, height, ">> ", - self.disabled || self.curvalue == self.maxvalue) - @rightarrow = Rect.new(x, y, rightarrows.width, height) - end -end - -#=============================================================================== -# -#=============================================================================== -class OptionalTextSlider < TextSlider - def initialize(label, options, curval) - @slider = TextSlider.new(label, options, curval) - @checkbox = Checkbox.new("") - end - - def curvalue - return @checkbox.checked ? @slider.curvalue : nil - end - - def curvalue=(value) - slider.curvalue = value - end - - def checked - return @checkbox.checked - end - - def checked=(value) - @checkbox.checked = value - end - - def invalid? - return @slider.invalid? || @checkbox.invalid? - end - - def invalidate - @slider.invalidate - @checkbox.invalidate - end - - def validate? - @slider.validate - @checkbox.validate - end - - def changed - return @slider.changed || @checkbox.changed - end - - def minvalue - return @slider.minvalue - end - - def minvalue=(value) - slider.minvalue = value - end - - def maxvalue - return @slider.maxvalue - end - - def maxvalue=(value) - slider.maxvalue = value - end - - def update - updatedefs - @slider.update - @checkbox.update - end - - def refresh - updatedefs - @slider.refresh - @checkbox.refresh - end - - #----------------------------------------------------------------------------- - - private - - def updatedefs - checkboxwidth = 32 - @slider.bitmap = self.bitmap - @slider.parent = self.parent - @checkbox.x = self.x - @checkbox.y = self.y - @checkbox.width = checkboxwidth - @checkbox.height = self.height - @checkbox.bitmap = self.bitmap - @checkbox.parent = self.parent - @slider.x = self.x + checkboxwidth + 4 - @slider.y = self.y - @slider.width = self.width - checkboxwidth - @slider.height = self.height - @slider.disabled = !@checkbox.checked - end -end - -#=============================================================================== -# -#=============================================================================== -class ControlWindow < SpriteWindow_Base - attr_reader :controls - - def initialize(x, y, width, height) - super(x, y, width, height) - self.contents = Bitmap.new(width - 32, height - 32) - pbSetNarrowFont(self.contents) - @controls = [] - end - - def dispose - self.contents.dispose - super - end - - def refresh - @controls.each { |ctrl| ctrl.refresh } - end - - def repaint - @controls.each { |ctrl| ctrl.repaint } - end - - def invalidate - @controls.each { |ctrl| ctrl.invalidate } - end - - def hittest?(i) - mousepos = Mouse.getMousePos - return false if !mousepos - return false if i < 0 || i >= @controls.length - rc = Rect.new(@controls[i].parentX, @controls[i].parentY, - @controls[i].width, @controls[i].height) - return rc.contains(mousepos[0], mousepos[1]) - end - - def addControl(control) - i = @controls.length - @controls[i] = control - @controls[i].x = 0 - @controls[i].y = i * 32 - @controls[i].width = self.contents.width - @controls[i].height = 32 - @controls[i].parent = self - @controls[i].bitmap = self.contents - @controls[i].invalidate - refresh - return i - end - - def addLabel(label) - return addControl(Label.new(label)) - end - - def addButton(label) - return addControl(Button.new(label)) - end - - def addSlider(label, minvalue, maxvalue, curvalue) - return addControl(Slider.new(label, minvalue, maxvalue, curvalue)) - end - - def addOptionalSlider(label, minvalue, maxvalue, curvalue) - return addControl(OptionalSlider.new(label, minvalue, maxvalue, curvalue)) - end - - def addTextSlider(label, options, curvalue) - return addControl(TextSlider.new(label, options, curvalue)) - end - - def addOptionalTextSlider(label, options, curvalue) - return addControl(OptionalTextSlider.new(label, options, curvalue)) - end - - def addCheckbox(label) - return addControl(Checkbox.new(label)) - end - - def addSpace - return addControl(UIControl.new("")) - end - - def update - super - @controls.each { |ctrl| ctrl.update } - repaint - end - - def changed?(i) - return false if i < 0 - return @controls[i].changed - end - - def value(i) - return false if i < 0 - return @controls[i].curvalue end end diff --git a/Data/Scripts/020_Debug/002_Animation editor/003_AnimEditor_Interpolation.rb b/Data/Scripts/020_Debug/002_Animation editor/003_AnimEditor_Interpolation.rb index 0571f1adf..df4fe74c3 100644 --- a/Data/Scripts/020_Debug/002_Animation editor/003_AnimEditor_Interpolation.rb +++ b/Data/Scripts/020_Debug/002_Animation editor/003_AnimEditor_Interpolation.rb @@ -1,432 +1,436 @@ -#=============================================================================== -# Paths and interpolation -#=============================================================================== -class ControlPointSprite < Sprite - attr_accessor :dragging +module BattleAnimationEditor + module_function - def initialize(red, viewport = nil) - super(viewport) - self.bitmap = Bitmap.new(6, 6) - self.bitmap.fill_rect(0, 0, 6, 1, Color.black) - self.bitmap.fill_rect(0, 0, 1, 6, Color.black) - self.bitmap.fill_rect(0, 5, 6, 1, Color.black) - self.bitmap.fill_rect(5, 0, 1, 6, Color.black) - color = (red) ? Color.new(255, 0, 0) : Color.black - self.bitmap.fill_rect(2, 2, 2, 2, color) - self.x = -6 - self.y = -6 - self.visible = false - @dragging = false - end + #=============================================================================== + # Paths and interpolation + #=============================================================================== + class ControlPointSprite < Sprite + attr_accessor :dragging - def mouseover - if Input.time?(Input::MOUSELEFT) == 0 || !@dragging + def initialize(red, viewport = nil) + super(viewport) + self.bitmap = Bitmap.new(6, 6) + self.bitmap.fill_rect(0, 0, 6, 1, Color.black) + self.bitmap.fill_rect(0, 0, 1, 6, Color.black) + self.bitmap.fill_rect(0, 5, 6, 1, Color.black) + self.bitmap.fill_rect(5, 0, 1, 6, Color.black) + color = (red) ? Color.new(255, 0, 0) : Color.black + self.bitmap.fill_rect(2, 2, 2, 2, color) + self.x = -6 + self.y = -6 + self.visible = false @dragging = false - return end - mouse = Mouse.getMousePos(true) - return if !mouse - self.x = [[mouse[0], 0].max, 512].min - self.y = [[mouse[1], 0].max, 384].min - end - def hittest? - return true if !self.visible - mouse = Mouse.getMousePos(true) - return false if !mouse - return mouse[0] >= self.x && mouse[0] < self.x + 6 && - mouse[1] >= self.y && mouse[1] < self.y + 6 - end - - def inspect - return "[#{self.x},#{self.y}]" - end - - def dispose - self.bitmap.dispose - super - end -end - -#=============================================================================== -# -#=============================================================================== -class PointSprite < Sprite - def initialize(x, y, viewport = nil) - super(viewport) - self.bitmap = Bitmap.new(2, 2) - self.bitmap.fill_rect(0, 0, 2, 2, Color.black) - self.x = x - self.y = y - end - - def dispose - self.bitmap.dispose - super - end -end - -#=============================================================================== -# -#=============================================================================== -class PointPath - include Enumerable - - def initialize - @points = [] - @distances = [] - @totaldist = 0 - end - - def [](x) - return @points[x].clone - end - - def each - @points.each { |o| yield o.clone } - end - - def size - return @points.size - end - - def length - return @points.length - end - - def totalDistance - return @totaldist - end - - def inspect - p = [] - @points.each do |point| - p.push([point[0].to_i, point[1].to_i]) - end - return p.inspect - end - - def isEndPoint?(x, y) - return false if @points.length == 0 - index = @points.length - 1 - return @points[index][0] == x && - @points[index][1] == y - end - - def addPoint(x, y) - @points.push([x, y]) - if @points.length > 1 - len = @points.length - dx = @points[len - 2][0] - @points[len - 1][0] - dy = @points[len - 2][1] - @points[len - 1][1] - dist = Math.sqrt((dx * dx) + (dy * dy)) - @distances.push(dist) - @totaldist += dist - end - end - - def clear - @points.clear - @distances.clear - @totaldist = 0 - end - - def smoothPointPath(frames, roundValues = false) - raise ArgumentError.new("frames out of range: #{frames}") if frames < 0 - ret = PointPath.new - return ret if @points.length == 0 - step = 1.0 / frames - t = 0.0 - (frames + 2).times do - point = pointOnPath(t) - if roundValues - ret.addPoint(point[0].round, point[1].round) - else - ret.addPoint(point[0], point[1]) + def mouseover + if Input.time?(Input::MOUSELEFT) == 0 || !@dragging + @dragging = false + return end - t += step - t = [1.0, t].min + mouse = Mouse.getMousePos(true) + return if !mouse + self.x = [[mouse[0], 0].max, 512].min + self.y = [[mouse[1], 0].max, 384].min + end + + def hittest? + return true if !self.visible + mouse = Mouse.getMousePos(true) + return false if !mouse + return mouse[0] >= self.x && mouse[0] < self.x + 6 && + mouse[1] >= self.y && mouse[1] < self.y + 6 + end + + def inspect + return "[#{self.x},#{self.y}]" + end + + def dispose + self.bitmap.dispose + super end - return ret end - def pointOnPath(t) - if t < 0 || t > 1 - raise ArgumentError.new("t out of range for pointOnPath: #{t}") + #=============================================================================== + # + #=============================================================================== + class PointSprite < Sprite + def initialize(x, y, viewport = nil) + super(viewport) + self.bitmap = Bitmap.new(2, 2) + self.bitmap.fill_rect(0, 0, 2, 2, Color.black) + self.x = x + self.y = y end - return nil if @points.length == 0 - ret = @points[@points.length - 1].clone - return ret if @points.length == 1 - curdist = 0 - distForT = @totaldist * t - i = 0 - @distances.each do |dist| - curdist += dist - if dist > 0.0 && curdist >= distForT - distT = 1.0 - ((curdist - distForT) / dist) - dx = @points[i + 1][0] - @points[i][0] - dy = @points[i + 1][1] - @points[i][1] - ret = [@points[i][0] + (dx * distT), - @points[i][1] + (dy * distT)] - break + + def dispose + self.bitmap.dispose + super + end + end + + #=============================================================================== + # + #=============================================================================== + class PointPath + include Enumerable + + def initialize + @points = [] + @distances = [] + @totaldist = 0 + end + + def [](x) + return @points[x].clone + end + + def each + @points.each { |o| yield o.clone } + end + + def size + return @points.size + end + + def length + return @points.length + end + + def totalDistance + return @totaldist + end + + def inspect + p = [] + @points.each do |point| + p.push([point[0].to_i, point[1].to_i]) end - i += 1 + return p.inspect end - return ret - end -end -#=============================================================================== -# -#=============================================================================== -def catmullRom(p1, p2, p3, p4, t) - # p1=prevPoint, p2=startPoint, p3=endPoint, p4=nextPoint, t is from 0 through 1 - t2 = t * t - t3 = t2 * t - return 0.5 * ((2 * p2) + (t * (p3 - p1)) + - (t2 * ((2 * p1) - (5 * p2) + (4 * p3) - p4)) + - (t3 * (p4 - (3 * p3) + (3 * p2) - p1))) -end + def isEndPoint?(x, y) + return false if @points.length == 0 + index = @points.length - 1 + return @points[index][0] == x && + @points[index][1] == y + end -def getCatmullRomPoint(src, t) - x = 0, y = 0 - t *= 3.0 - if t < 1.0 - x = catmullRom(src[0].x, src[0].x, src[1].x, src[2].x, t) - y = catmullRom(src[0].y, src[0].y, src[1].y, src[2].y, t) - elsif t < 2.0 - t -= 1.0 - x = catmullRom(src[0].x, src[1].x, src[2].x, src[3].x, t) - y = catmullRom(src[0].y, src[1].y, src[2].y, src[3].y, t) - else - t -= 2.0 - x = catmullRom(src[1].x, src[2].x, src[3].x, src[3].x, t) - y = catmullRom(src[1].y, src[2].y, src[3].y, src[3].y, t) - end - return [x, y] -end + def addPoint(x, y) + @points.push([x, y]) + if @points.length > 1 + len = @points.length + dx = @points[len - 2][0] - @points[len - 1][0] + dy = @points[len - 2][1] - @points[len - 1][1] + dist = Math.sqrt((dx * dx) + (dy * dy)) + @distances.push(dist) + @totaldist += dist + end + end -def getCurvePoint(src, t) - return getCatmullRomPoint(src, t) -end + def clear + @points.clear + @distances.clear + @totaldist = 0 + end -def curveToPointPath(curve, numpoints) - return nil if numpoints < 2 - path = PointPath.new - step = 1.0 / (numpoints - 1) - t = 0.0 - numpoints.times do - point = getCurvePoint(curve, t) - path.addPoint(point[0], point[1]) - t += step - end - return path -end - -def pbDefinePath(canvas) - sliderwin2 = ControlWindow.new(0, 0, 320, 320) - sliderwin2.viewport = canvas.viewport - sliderwin2.addSlider(_INTL("Number of frames:"), 2, 500, 20) - sliderwin2.opacity = 200 - defcurvebutton = sliderwin2.addButton(_INTL("Define Smooth Curve")) - defpathbutton = sliderwin2.addButton(_INTL("Define Freehand Path")) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - points = [] - path = nil - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(0) # Number of frames - if path - path = path.smoothPointPath(sliderwin2.value(0), false) - i = 0 - path.each do |point| - if i < points.length - points[i].x = point[0] - points[i].y = point[1] - else - points.push(PointSprite.new(point[0], point[1], canvas.viewport)) - end - i += 1 + def smoothPointPath(frames, roundValues = false) + raise ArgumentError.new("frames out of range: #{frames}") if frames < 0 + ret = PointPath.new + return ret if @points.length == 0 + step = 1.0 / frames + t = 0.0 + (frames + 2).times do + point = pointOnPath(t) + if roundValues + ret.addPoint(point[0].round, point[1].round) + else + ret.addPoint(point[0], point[1]) end - (i...points.length).each do |j| - points[j].dispose - points[j] = nil - end - points.compact! + t += step + t = [1.0, t].min end - elsif sliderwin2.changed?(defcurvebutton) - points.each do |point| - point.dispose + return ret + end + + def pointOnPath(t) + if t < 0 || t > 1 + raise ArgumentError.new("t out of range for pointOnPath: #{t}") end - points.clear - 30.times do - point = PointSprite.new(0, 0, canvas.viewport) - point.visible = false - points.push(point) - end - curve = [ - ControlPointSprite.new(true, canvas.viewport), - ControlPointSprite.new(false, canvas.viewport), - ControlPointSprite.new(false, canvas.viewport), - ControlPointSprite.new(true, canvas.viewport) - ] - showline = false - sliderwin2.visible = false - # This window displays the mouse's current position - window = Window_UnformattedTextPokemon.newWithSize( - "", 0, 320 - 64, 128, 64, canvas.viewport - ) - loop do - Graphics.update - Input.update - if Input.trigger?(Input::BACK) + return nil if @points.length == 0 + ret = @points[@points.length - 1].clone + return ret if @points.length == 1 + curdist = 0 + distForT = @totaldist * t + i = 0 + @distances.each do |dist| + curdist += dist + if dist > 0.0 && curdist >= distForT + distT = 1.0 - ((curdist - distForT) / dist) + dx = @points[i + 1][0] - @points[i][0] + dy = @points[i + 1][1] - @points[i][1] + ret = [@points[i][0] + (dx * distT), + @points[i][1] + (dy * distT)] break end - if Input.trigger?(Input::MOUSELEFT) + i += 1 + end + return ret + end + end + + #=============================================================================== + # + #=============================================================================== + def catmullRom(p1, p2, p3, p4, t) + # p1=prevPoint, p2=startPoint, p3=endPoint, p4=nextPoint, t is from 0 through 1 + t2 = t * t + t3 = t2 * t + return 0.5 * ((2 * p2) + (t * (p3 - p1)) + + (t2 * ((2 * p1) - (5 * p2) + (4 * p3) - p4)) + + (t3 * (p4 - (3 * p3) + (3 * p2) - p1))) + end + + def getCatmullRomPoint(src, t) + x = 0, y = 0 + t *= 3.0 + if t < 1.0 + x = catmullRom(src[0].x, src[0].x, src[1].x, src[2].x, t) + y = catmullRom(src[0].y, src[0].y, src[1].y, src[2].y, t) + elsif t < 2.0 + t -= 1.0 + x = catmullRom(src[0].x, src[1].x, src[2].x, src[3].x, t) + y = catmullRom(src[0].y, src[1].y, src[2].y, src[3].y, t) + else + t -= 2.0 + x = catmullRom(src[1].x, src[2].x, src[3].x, src[3].x, t) + y = catmullRom(src[1].y, src[2].y, src[3].y, src[3].y, t) + end + return [x, y] + end + + def getCurvePoint(src, t) + return getCatmullRomPoint(src, t) + end + + def curveToPointPath(curve, numpoints) + return nil if numpoints < 2 + path = PointPath.new + step = 1.0 / (numpoints - 1) + t = 0.0 + numpoints.times do + point = getCurvePoint(curve, t) + path.addPoint(point[0], point[1]) + t += step + end + return path + end + + def pbDefinePath(canvas) + sliderwin2 = ControlWindow.new(0, 0, 320, 320) + sliderwin2.viewport = canvas.viewport + sliderwin2.addSlider(_INTL("Number of frames:"), 2, 500, 20) + sliderwin2.opacity = 200 + defcurvebutton = sliderwin2.addButton(_INTL("Define Smooth Curve")) + defpathbutton = sliderwin2.addButton(_INTL("Define Freehand Path")) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + points = [] + path = nil + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(0) # Number of frames + if path + path = path.smoothPointPath(sliderwin2.value(0), false) + i = 0 + path.each do |point| + if i < points.length + points[i].x = point[0] + points[i].y = point[1] + else + points.push(PointSprite.new(point[0], point[1], canvas.viewport)) + end + i += 1 + end + (i...points.length).each do |j| + points[j].dispose + points[j] = nil + end + points.compact! + end + elsif sliderwin2.changed?(defcurvebutton) + points.each do |point| + point.dispose + end + points.clear + 30.times do + point = PointSprite.new(0, 0, canvas.viewport) + point.visible = false + points.push(point) + end + curve = [ + ControlPointSprite.new(true, canvas.viewport), + ControlPointSprite.new(false, canvas.viewport), + ControlPointSprite.new(false, canvas.viewport), + ControlPointSprite.new(true, canvas.viewport) + ] + showline = false + sliderwin2.visible = false + # This window displays the mouse's current position + window = Window_UnformattedTextPokemon.newWithSize( + "", 0, 320 - 64, 128, 64, canvas.viewport + ) + loop do + Graphics.update + Input.update + if Input.trigger?(Input::BACK) + break + end + if Input.trigger?(Input::MOUSELEFT) + 4.times do |j| + next if !curve[j].hittest? + if [1, 2].include?(j) && (!curve[0].visible || !curve[3].visible) + next + end + curve[j].visible = true + 4.times do |k| + curve[k].dragging = (k == j) + end + break + end + end 4.times do |j| - next if !curve[j].hittest? - if [1, 2].include?(j) && (!curve[0].visible || !curve[3].visible) - next + curve[j].mouseover + end + mousepos = Mouse.getMousePos(true) + newtext = (mousepos) ? sprintf("(%d,%d)", mousepos[0], mousepos[1]) : "(??,??)" + window.text = newtext if window.text != newtext + if curve[0].visible && curve[3].visible && + !curve[0].dragging && !curve[3].dragging + points.each do |point| + point.visible = true end - curve[j].visible = true - 4.times do |k| - curve[k].dragging = (k == j) + if !showline + curve[1].visible = true + curve[2].visible = true + curve[1].x = curve[0].x + (0.3333 * (curve[3].x - curve[0].x)) + curve[1].y = curve[0].y + (0.3333 * (curve[3].y - curve[0].y)) + curve[2].x = curve[0].x + (0.6666 * (curve[3].x - curve[0].x)) + curve[2].y = curve[0].y + (0.6666 * (curve[3].y - curve[0].y)) end + showline = true + end + if showline + step = 1.0 / (points.length - 1) + t = 0.0 + points.length.times do |j| + point = getCurvePoint(curve, t) + points[j].x = point[0] + points[j].y = point[1] + t += step + end + end + end + window.dispose + # dispose temporary path + points.each do |point| + point.dispose + end + points.clear + if showline + path = curveToPointPath(curve, sliderwin2.value(0)) + # File.open("pointpath.txt","wb") { |f| f.write(path.inspect) } + path.each do |point| + points.push(PointSprite.new(point[0], point[1], canvas.viewport)) + end + end + curve.each do |point| + point.dispose + end + sliderwin2.visible = true + next + elsif sliderwin2.changed?(defpathbutton) + canceled = false + pointpath = PointPath.new + points.each do |point| + point.dispose + end + points.clear + window = Window_UnformattedTextPokemon.newWithSize( + "", 0, 320 - 64, 128, 64, canvas.viewport + ) + sliderwin2.visible = false + loop do + Graphics.update + Input.update + if Input.triggerex?(:ESCAPE) + canceled = true + break + end + if Input.trigger?(Input::MOUSELEFT) + break + end + mousepos = Mouse.getMousePos(true) + window.text = (mousepos) ? sprintf("(%d,%d)", mousepos[0], mousepos[1]) : "(??,??)" + end + until canceled + mousepos = Mouse.getMousePos(true) + if mousepos && !pointpath.isEndPoint?(mousepos[0], mousepos[1]) + pointpath.addPoint(mousepos[0], mousepos[1]) + points.push(PointSprite.new(mousepos[0], mousepos[1], canvas.viewport)) + end + window.text = (mousepos) ? sprintf("(%d,%d)", mousepos[0], mousepos[1]) : "(??,??)" + Graphics.update + Input.update + if Input.triggerex?(:ESCAPE) || Input.time?(Input::MOUSELEFT) == 0 break end end - 4.times do |j| - curve[j].mouseover + window.dispose + # dispose temporary path + points.each do |point| + point.dispose end - mousepos = Mouse.getMousePos(true) - newtext = (mousepos) ? sprintf("(%d,%d)", mousepos[0], mousepos[1]) : "(??,??)" - window.text = newtext if window.text != newtext - if curve[0].visible && curve[3].visible && - !curve[0].dragging && !curve[3].dragging - points.each do |point| - point.visible = true - end - if !showline - curve[1].visible = true - curve[2].visible = true - curve[1].x = curve[0].x + (0.3333 * (curve[3].x - curve[0].x)) - curve[1].y = curve[0].y + (0.3333 * (curve[3].y - curve[0].y)) - curve[2].x = curve[0].x + (0.6666 * (curve[3].x - curve[0].x)) - curve[2].y = curve[0].y + (0.6666 * (curve[3].y - curve[0].y)) - end - showline = true - end - if showline - step = 1.0 / (points.length - 1) - t = 0.0 - points.length.times do |j| - point = getCurvePoint(curve, t) - points[j].x = point[0] - points[j].y = point[1] - t += step - end - end - end - window.dispose - # dispose temporary path - points.each do |point| - point.dispose - end - points.clear - if showline - path = curveToPointPath(curve, sliderwin2.value(0)) -# File.open("pointpath.txt","wb") { |f| f.write(path.inspect) } + points.clear + # generate smooth path from temporary path + path = pointpath.smoothPointPath(sliderwin2.value(0), true) + # redraw path from smooth path path.each do |point| points.push(PointSprite.new(point[0], point[1], canvas.viewport)) end - end - curve.each do |point| - point.dispose - end - sliderwin2.visible = true - next - elsif sliderwin2.changed?(defpathbutton) - canceled = false - pointpath = PointPath.new - points.each do |point| - point.dispose - end - points.clear - window = Window_UnformattedTextPokemon.newWithSize( - "", 0, 320 - 64, 128, 64, canvas.viewport - ) - sliderwin2.visible = false - loop do - Graphics.update - Input.update - if Input.triggerex?(:ESCAPE) - canceled = true - break + # File.open("pointpath.txt","wb") { |f| f.write(path.inspect) } + sliderwin2.visible = true + next + elsif sliderwin2.changed?(okbutton) && path + # File.open("pointpath.txt","wb") { |f| f.write(path.inspect) } + neededsize = canvas.currentframe + sliderwin2.value(0) + if neededsize > canvas.animation.length + canvas.animation.resize(neededsize) end - if Input.trigger?(Input::MOUSELEFT) - break + thiscel = canvas.currentCel + celnumber = canvas.currentcel + (canvas.currentframe...neededsize).each do |j| + cel = canvas.animation[j][celnumber] + if !canvas.animation[j][celnumber] + cel = pbCreateCel(0, 0, thiscel[AnimFrame::PATTERN], canvas.animation.position) + canvas.animation[j][celnumber] = cel + end + cel[AnimFrame::X] = path[j - canvas.currentframe][0] + cel[AnimFrame::Y] = path[j - canvas.currentframe][1] end - mousepos = Mouse.getMousePos(true) - window.text = (mousepos) ? sprintf("(%d,%d)", mousepos[0], mousepos[1]) : "(??,??)" + break + elsif sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break end - until canceled - mousepos = Mouse.getMousePos(true) - if mousepos && !pointpath.isEndPoint?(mousepos[0], mousepos[1]) - pointpath.addPoint(mousepos[0], mousepos[1]) - points.push(PointSprite.new(mousepos[0], mousepos[1], canvas.viewport)) - end - window.text = (mousepos) ? sprintf("(%d,%d)", mousepos[0], mousepos[1]) : "(??,??)" - Graphics.update - Input.update - if Input.triggerex?(:ESCAPE) || Input.time?(Input::MOUSELEFT) == 0 - break - end - end - window.dispose - # dispose temporary path - points.each do |point| - point.dispose - end - points.clear - # generate smooth path from temporary path - path = pointpath.smoothPointPath(sliderwin2.value(0), true) - # redraw path from smooth path - path.each do |point| - points.push(PointSprite.new(point[0], point[1], canvas.viewport)) - end -# File.open("pointpath.txt","wb") { |f| f.write(path.inspect) } - sliderwin2.visible = true - next - elsif sliderwin2.changed?(okbutton) && path -# File.open("pointpath.txt","wb") { |f| f.write(path.inspect) } - neededsize = canvas.currentframe + sliderwin2.value(0) - if neededsize > canvas.animation.length - canvas.animation.resize(neededsize) - end - thiscel = canvas.currentCel - celnumber = canvas.currentcel - (canvas.currentframe...neededsize).each do |j| - cel = canvas.animation[j][celnumber] - if !canvas.animation[j][celnumber] - cel = pbCreateCel(0, 0, thiscel[AnimFrame::PATTERN], canvas.animation.position) - canvas.animation[j][celnumber] = cel - end - cel[AnimFrame::X] = path[j - canvas.currentframe][0] - cel[AnimFrame::Y] = path[j - canvas.currentframe][1] - end - break - elsif sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break end + # dispose all points + points.each do |point| + point.dispose + end + points.clear + sliderwin2.dispose + return end - # dispose all points - points.each do |point| - point.dispose - end - points.clear - sliderwin2.dispose - return end diff --git a/Data/Scripts/020_Debug/002_Animation editor/004_AnimEditor_ExportImport.rb b/Data/Scripts/020_Debug/002_Animation editor/004_AnimEditor_ExportImport.rb index fc56ec72e..45e07eabf 100644 --- a/Data/Scripts/020_Debug/002_Animation editor/004_AnimEditor_ExportImport.rb +++ b/Data/Scripts/020_Debug/002_Animation editor/004_AnimEditor_ExportImport.rb @@ -1,143 +1,147 @@ -################################################################################ -# Importing and exporting -################################################################################ -def pbRgssChdir(dir) - RTP.eachPathFor(dir) { |path| Dir.chdir(path) { yield } } -end +module BattleAnimationEditor + module_function -def tryLoadData(file) - begin - return load_data(file) - rescue - return nil + ################################################################################ + # Importing and exporting + ################################################################################ + def pbRgssChdir(dir) + RTP.eachPathFor(dir) { |path| Dir.chdir(path) { yield } } end -end -def dumpBase64Anim(s) - return [Zlib::Deflate.deflate(Marshal.dump(s))].pack("m").gsub(/\n/, "\r\n") -end - -def loadBase64Anim(s) - return Marshal.restore(Zlib::Inflate.inflate(s.unpack("m")[0])) -end - -def pbExportAnim(animations) - filename = pbMessageFreeText(_INTL("Enter a filename."), "", false, 32) - if filename != "" + def tryLoadData(file) begin - filename += ".anm" - File.open(filename, "wb") do |f| - f.write(dumpBase64Anim(animations[animations.selected])) - end - failed = false + return load_data(file) rescue - pbMessage(_INTL("Couldn't save the animation to {1}.", filename)) - failed = true - end - if !failed - pbMessage(_INTL("Animation was saved to {1} in the game folder.", filename)) - pbMessage(_INTL("It's a text file, so it can be transferred to others easily.")) + return nil end end -end -def pbImportAnim(animations, canvas, animwin) - animfiles = [] - pbRgssChdir(".") { animfiles.concat(Dir.glob("*.anm")) } - cmdwin = pbListWindow(animfiles, 320) - cmdwin.opacity = 200 - cmdwin.height = 480 - cmdwin.viewport = canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - if Input.trigger?(Input::USE) && animfiles.length > 0 + def dumpBase64Anim(s) + return [Zlib::Deflate.deflate(Marshal.dump(s))].pack("m").gsub(/\n/, "\r\n") + end + + def loadBase64Anim(s) + return Marshal.restore(Zlib::Inflate.inflate(s.unpack("m")[0])) + end + + def pbExportAnim(animations) + filename = pbMessageFreeText(_INTL("Enter a filename."), "", false, 32) + if filename != "" begin - textdata = loadBase64Anim(IO.read(animfiles[cmdwin.index])) - throw "Bad data" if !textdata.is_a?(PBAnimation) - textdata.id = -1 # this is not an RPG Maker XP animation - pbConvertAnimToNewFormat(textdata) - animations[animations.selected] = textdata + filename += ".anm" + File.open(filename, "wb") do |f| + f.write(dumpBase64Anim(animations[animations.selected])) + end + failed = false rescue - pbMessage(_INTL("The animation is invalid or could not be loaded.")) - next + pbMessage(_INTL("Couldn't save the animation to {1}.", filename)) + failed = true end - graphic = animations[animations.selected].graphic - graphic = "Graphics/Animations/#{graphic}" - if graphic && graphic != "" && !FileTest.image_exist?(graphic) - pbMessage(_INTL("The animation file {1} was not found. The animation will load anyway.", graphic)) + if !failed + pbMessage(_INTL("Animation was saved to {1} in the game folder.", filename)) + pbMessage(_INTL("It's a text file, so it can be transferred to others easily.")) end - canvas.loadAnimation(animations[animations.selected]) - animwin.animbitmap = canvas.animbitmap - break - end - if Input.trigger?(Input::BACK) - break end end - cmdwin.dispose - return -end -################################################################################ -# Format conversion -################################################################################ -def pbConvertAnimToNewFormat(textdata) - needconverting = false - textdata.length.times do |i| - next if !textdata[i] - PBAnimation::MAX_SPRITES.times do |j| - next if !textdata[i][j] - needconverting = true if textdata[i][j][AnimFrame::FOCUS].nil? - break if needconverting + def pbImportAnim(animations, canvas, animwin) + animfiles = [] + pbRgssChdir(".") { animfiles.concat(Dir.glob("*.anm")) } + cmdwin = pbListWindow(animfiles, 320) + cmdwin.opacity = 200 + cmdwin.height = 480 + cmdwin.viewport = canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + if Input.trigger?(Input::USE) && animfiles.length > 0 + begin + textdata = loadBase64Anim(IO.read(animfiles[cmdwin.index])) + throw "Bad data" if !textdata.is_a?(PBAnimation) + textdata.id = -1 # this is not an RPG Maker XP animation + pbConvertAnimToNewFormat(textdata) + animations[animations.selected] = textdata + rescue + pbMessage(_INTL("The animation is invalid or could not be loaded.")) + next + end + graphic = animations[animations.selected].graphic + graphic = "Graphics/Animations/#{graphic}" + if graphic && graphic != "" && !FileTest.image_exist?(graphic) + pbMessage(_INTL("The animation file {1} was not found. The animation will load anyway.", graphic)) + end + canvas.loadAnimation(animations[animations.selected]) + animwin.animbitmap = canvas.animbitmap + break + end + if Input.trigger?(Input::BACK) + break + end end - break if needconverting + cmdwin.dispose + return end - if needconverting + + ################################################################################ + # Format conversion + ################################################################################ + def pbConvertAnimToNewFormat(textdata) + needconverting = false textdata.length.times do |i| next if !textdata[i] PBAnimation::MAX_SPRITES.times do |j| next if !textdata[i][j] - textdata[i][j][AnimFrame::PRIORITY] = 1 if textdata[i][j][AnimFrame::PRIORITY].nil? - case j - when 0 # User battler - textdata[i][j][AnimFrame::FOCUS] = 2 - textdata[i][j][AnimFrame::X] = Battle::Scene::FOCUSUSER_X - textdata[i][j][AnimFrame::Y] = Battle::Scene::FOCUSUSER_Y - when 1 # Target battler - textdata[i][j][AnimFrame::FOCUS] = 1 - textdata[i][j][AnimFrame::X] = Battle::Scene::FOCUSTARGET_X - textdata[i][j][AnimFrame::Y] = Battle::Scene::FOCUSTARGET_Y - else - textdata[i][j][AnimFrame::FOCUS] = (textdata.position || 4) - if textdata.position == 1 - textdata[i][j][AnimFrame::X] += Battle::Scene::FOCUSTARGET_X - textdata[i][j][AnimFrame::Y] += Battle::Scene::FOCUSTARGET_Y - 2 + needconverting = true if textdata[i][j][AnimFrame::FOCUS].nil? + break if needconverting + end + break if needconverting + end + if needconverting + textdata.length.times do |i| + next if !textdata[i] + PBAnimation::MAX_SPRITES.times do |j| + next if !textdata[i][j] + textdata[i][j][AnimFrame::PRIORITY] = 1 if textdata[i][j][AnimFrame::PRIORITY].nil? + case j + when 0 # User battler + textdata[i][j][AnimFrame::FOCUS] = 2 + textdata[i][j][AnimFrame::X] = Battle::Scene::FOCUSUSER_X + textdata[i][j][AnimFrame::Y] = Battle::Scene::FOCUSUSER_Y + when 1 # Target battler + textdata[i][j][AnimFrame::FOCUS] = 1 + textdata[i][j][AnimFrame::X] = Battle::Scene::FOCUSTARGET_X + textdata[i][j][AnimFrame::Y] = Battle::Scene::FOCUSTARGET_Y + else + textdata[i][j][AnimFrame::FOCUS] = (textdata.position || 4) + if textdata.position == 1 + textdata[i][j][AnimFrame::X] += Battle::Scene::FOCUSTARGET_X + textdata[i][j][AnimFrame::Y] += Battle::Scene::FOCUSTARGET_Y - 2 + end end end end end + return needconverting end - return needconverting -end -def pbConvertAnimsToNewFormat - pbMessage(_INTL("Will convert animations now.")) - count = 0 - animations = pbLoadBattleAnimations - if !animations || !animations[0] - pbMessage(_INTL("No animations exist.")) - return + def pbConvertAnimsToNewFormat + pbMessage(_INTL("Will convert animations now.")) + count = 0 + animations = pbLoadBattleAnimations + if !animations || !animations[0] + pbMessage(_INTL("No animations exist.")) + return + end + animations.length.times do |k| + next if !animations[k] + ret = pbConvertAnimToNewFormat(animations[k]) + count += 1 if ret + end + if count > 0 + save_data(animations, "Data/PkmnAnimations.rxdata") + $game_temp.battle_animations_data = nil + end + pbMessage(_INTL("{1} animations converted to new format.", count)) end - animations.length.times do |k| - next if !animations[k] - ret = pbConvertAnimToNewFormat(animations[k]) - count += 1 if ret - end - if count > 0 - save_data(animations, "Data/PkmnAnimations.rxdata") - $game_temp.battle_animations_data = nil - end - pbMessage(_INTL("{1} animations converted to new format.", count)) end diff --git a/Data/Scripts/020_Debug/002_Animation editor/005_AnimEditor_Functions.rb b/Data/Scripts/020_Debug/002_Animation editor/005_AnimEditor_Functions.rb index 10d8dc4e2..ba8112029 100644 --- a/Data/Scripts/020_Debug/002_Animation editor/005_AnimEditor_Functions.rb +++ b/Data/Scripts/020_Debug/002_Animation editor/005_AnimEditor_Functions.rb @@ -1,661 +1,605 @@ -#=============================================================================== -# Mini battle scene -#=============================================================================== -class MiniBattler - attr_accessor :index - attr_accessor :pokemon +module BattleAnimationEditor + module_function - def initialize(index); self.index = index; end -end + #=============================================================================== + # Mini battle scene + #=============================================================================== + class MiniBattler + attr_accessor :index + attr_accessor :pokemon -#=============================================================================== -# -#=============================================================================== -class MiniBattle - attr_accessor :battlers - - def initialize - @battlers = [] - 4.times { |i| @battlers[i] = MiniBattler.new(i) } + def initialize(index); self.index = index; end end -end -#=============================================================================== -# Pop-up menus for buttons in bottom menu -#=============================================================================== -def pbSelectAnim(canvas, animwin) - animfiles = [] - pbRgssChdir(File.join("Graphics", "Animations")) { animfiles.concat(Dir.glob("*.png")) } - cmdwin = pbListWindow(animfiles, 320) - cmdwin.opacity = 200 - cmdwin.height = 512 - bmpwin = BitmapDisplayWindow.new(320, 0, 320, 448) - ctlwin = ControlWindow.new(320, 448, 320, 64) - cmdwin.viewport = canvas.viewport - bmpwin.viewport = canvas.viewport - ctlwin.viewport = canvas.viewport - ctlwin.addSlider(_INTL("Hue:"), 0, 359, 0) - loop do - bmpwin.bitmapname = cmdwin.commands[cmdwin.index] - Graphics.update - Input.update - cmdwin.update - bmpwin.update - ctlwin.update - bmpwin.hue = ctlwin.value(0) if ctlwin.changed?(0) - if Input.trigger?(Input::USE) && animfiles.length > 0 - filename = cmdwin.commands[cmdwin.index] - bitmap = AnimatedBitmap.new("Graphics/Animations/" + filename, ctlwin.value(0)).deanimate - canvas.animation.graphic = File.basename(filename, ".*") - canvas.animation.hue = ctlwin.value(0) - canvas.animbitmap = bitmap - animwin.animbitmap = bitmap - break - end - if Input.trigger?(Input::BACK) - break + #=============================================================================== + # + #=============================================================================== + class MiniBattle + attr_accessor :battlers + + def initialize + @battlers = [] + 4.times { |i| @battlers[i] = MiniBattler.new(i) } end end - bmpwin.dispose - cmdwin.dispose - ctlwin.dispose - return -end -def pbChangeMaximum(canvas) - sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 4) - sliderwin2.viewport = canvas.viewport - sliderwin2.addSlider(_INTL("Frames:"), 1, 1000, canvas.animation.length) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - sliderwin2.opacity = 200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - canvas.animation.resize(sliderwin2.value(0)) - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - sliderwin2.dispose - return -end - -def pbAnimName(animation, cmdwin) - window = ControlWindow.new(320, 128, 320, 32 * 4) - window.z = 99999 - window.addControl(TextField.new(_INTL("New Name:"), animation.name)) - Input.text_input = true - okbutton = window.addButton(_INTL("OK")) - cancelbutton = window.addButton(_INTL("Cancel")) - window.opacity = 224 - loop do - Graphics.update - Input.update - window.update - if window.changed?(okbutton) || Input.triggerex?(:RETURN) - cmdwin.commands[cmdwin.index] = _INTL("{1} {2}", cmdwin.index, window.controls[0].text) - animation.name = window.controls[0].text - break - end - if window.changed?(cancelbutton) || Input.triggerex?(:ESCAPE) - break - end - end - window.dispose - Input.text_input = false - return -end - -def pbAnimList(animations, canvas, animwin) - commands = [] - animations.length.times do |i| - animations[i] = PBAnimation.new if !animations[i] - commands[commands.length] = _INTL("{1} {2}", i, animations[i].name) - end - cmdwin = pbListWindow(commands, 320) - cmdwin.height = 416 - cmdwin.opacity = 224 - cmdwin.index = animations.selected - cmdwin.viewport = canvas.viewport - helpwindow = Window_UnformattedTextPokemon.newWithSize( - _INTL("Enter: Load/rename an animation\nEsc: Cancel"), - 320, 0, 320, 128, canvas.viewport - ) - maxsizewindow = ControlWindow.new(0, 416, 320, 32 * 3) - maxsizewindow.addSlider(_INTL("Total Animations:"), 1, 2000, animations.length) - maxsizewindow.addButton(_INTL("Resize Animation List")) - maxsizewindow.opacity = 224 - maxsizewindow.viewport = canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - maxsizewindow.update - helpwindow.update - if maxsizewindow.changed?(1) - newsize = maxsizewindow.value(0) - animations.resize(newsize) - commands.clear - animations.length.times do |i| - commands[commands.length] = _INTL("{1} {2}", i, animations[i].name) - end - cmdwin.commands = commands - cmdwin.index = animations.selected - next - end - if Input.trigger?(Input::USE) && animations.length > 0 - cmd2 = pbShowCommands(helpwindow, - [_INTL("Load Animation"), - _INTL("Rename"), - _INTL("Delete")], -1) - case cmd2 - when 0 # Load Animation - canvas.loadAnimation(animations[cmdwin.index]) - animwin.animbitmap = canvas.animbitmap - animations.selected = cmdwin.index + #=============================================================================== + # Pop-up menus for buttons in bottom menu + #=============================================================================== + def pbSelectAnim(canvas, animwin) + animfiles = [] + pbRgssChdir(File.join("Graphics", "Animations")) { animfiles.concat(Dir.glob("*.png")) } + cmdwin = pbListWindow(animfiles, 320) + cmdwin.opacity = 200 + cmdwin.height = 512 + bmpwin = BitmapDisplayWindow.new(320, 0, 320, 448) + ctlwin = ControlWindow.new(320, 448, 320, 64) + cmdwin.viewport = canvas.viewport + bmpwin.viewport = canvas.viewport + ctlwin.viewport = canvas.viewport + ctlwin.addSlider(_INTL("Hue:"), 0, 359, 0) + loop do + bmpwin.bitmapname = cmdwin.commands[cmdwin.index] + Graphics.update + Input.update + cmdwin.update + bmpwin.update + ctlwin.update + bmpwin.hue = ctlwin.value(0) if ctlwin.changed?(0) + if Input.trigger?(Input::USE) && animfiles.length > 0 + filename = cmdwin.commands[cmdwin.index] + bitmap = AnimatedBitmap.new("Graphics/Animations/" + filename, ctlwin.value(0)).deanimate + canvas.animation.graphic = File.basename(filename, ".*") + canvas.animation.hue = ctlwin.value(0) + canvas.animbitmap = bitmap + animwin.animbitmap = bitmap break - when 1 # Rename - pbAnimName(animations[cmdwin.index], cmdwin) - cmdwin.refresh - when 2 # Delete - if pbConfirmMessage(_INTL("Are you sure you want to delete this animation?")) - animations[cmdwin.index] = PBAnimation.new - cmdwin.commands[cmdwin.index] = _INTL("{1} {2}", cmdwin.index, animations[cmdwin.index].name) + end + if Input.trigger?(Input::BACK) + break + end + end + bmpwin.dispose + cmdwin.dispose + ctlwin.dispose + return + end + + def pbChangeMaximum(canvas) + sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 4) + sliderwin2.viewport = canvas.viewport + sliderwin2.addSlider(_INTL("Frames:"), 1, 1000, canvas.animation.length) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + sliderwin2.opacity = 200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + canvas.animation.resize(sliderwin2.value(0)) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + sliderwin2.dispose + return + end + + def pbAnimName(animation, cmdwin) + window = ControlWindow.new(320, 128, 320, 32 * 4) + window.z = 99999 + window.addControl(TextField.new(_INTL("New Name:"), animation.name)) + Input.text_input = true + okbutton = window.addButton(_INTL("OK")) + cancelbutton = window.addButton(_INTL("Cancel")) + window.opacity = 224 + loop do + Graphics.update + Input.update + window.update + if window.changed?(okbutton) || Input.triggerex?(:RETURN) + cmdwin.commands[cmdwin.index] = _INTL("{1} {2}", cmdwin.index, window.controls[0].text) + animation.name = window.controls[0].text + break + end + if window.changed?(cancelbutton) || Input.triggerex?(:ESCAPE) + break + end + end + window.dispose + Input.text_input = false + return + end + + def pbAnimList(animations, canvas, animwin) + commands = [] + animations.length.times do |i| + animations[i] = PBAnimation.new if !animations[i] + commands[commands.length] = _INTL("{1} {2}", i, animations[i].name) + end + cmdwin = pbListWindow(commands, 320) + cmdwin.height = 416 + cmdwin.opacity = 224 + cmdwin.index = animations.selected + cmdwin.viewport = canvas.viewport + helpwindow = Window_UnformattedTextPokemon.newWithSize( + _INTL("Enter: Load/rename an animation\nEsc: Cancel"), + 320, 0, 320, 128, canvas.viewport + ) + maxsizewindow = ControlWindow.new(0, 416, 320, 32 * 3) + maxsizewindow.addSlider(_INTL("Total Animations:"), 1, 2000, animations.length) + maxsizewindow.addButton(_INTL("Resize Animation List")) + maxsizewindow.opacity = 224 + maxsizewindow.viewport = canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + maxsizewindow.update + helpwindow.update + if maxsizewindow.changed?(1) + newsize = maxsizewindow.value(0) + animations.resize(newsize) + commands.clear + animations.length.times do |i| + commands[commands.length] = _INTL("{1} {2}", i, animations[i].name) + end + cmdwin.commands = commands + cmdwin.index = animations.selected + next + end + if Input.trigger?(Input::USE) && animations.length > 0 + cmd2 = pbShowCommands(helpwindow, + [_INTL("Load Animation"), + _INTL("Rename"), + _INTL("Delete")], -1) + case cmd2 + when 0 # Load Animation + canvas.loadAnimation(animations[cmdwin.index]) + animwin.animbitmap = canvas.animbitmap + animations.selected = cmdwin.index + break + when 1 # Rename + pbAnimName(animations[cmdwin.index], cmdwin) + cmdwin.refresh + when 2 # Delete + if pbConfirmMessage(_INTL("Are you sure you want to delete this animation?")) + animations[cmdwin.index] = PBAnimation.new + cmdwin.commands[cmdwin.index] = _INTL("{1} {2}", cmdwin.index, animations[cmdwin.index].name) + cmdwin.refresh + end + end + end + if Input.trigger?(Input::BACK) + break + end + end + helpwindow.dispose + maxsizewindow.dispose + cmdwin.dispose + end + + #=============================================================================== + # Pop-up menus for individual cels + #=============================================================================== + def pbChooseNum(cel) + ret = cel + sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 5) + sliderwin2.z = 99999 + sliderwin2.addLabel(_INTL("Old Number: {1}", cel)) + sliderwin2.addSlider(_INTL("New Number:"), 2, PBAnimation::MAX_SPRITES, cel) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + ret = sliderwin2.value(1) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + ret = -1 + break + end + end + sliderwin2.dispose + return ret + end + + def pbSetTone(cel, previewsprite) + sliderwin2 = ControlWindow.new(0, 0, 320, 320) + sliderwin2.z = 99999 + sliderwin2.addSlider(_INTL("Red Offset:"), -255, 255, cel[AnimFrame::TONERED]) + sliderwin2.addSlider(_INTL("Green Offset:"), -255, 255, cel[AnimFrame::TONEGREEN]) + sliderwin2.addSlider(_INTL("Blue Offset:"), -255, 255, cel[AnimFrame::TONEBLUE]) + sliderwin2.addSlider(_INTL("Gray Tone:"), 0, 255, cel[AnimFrame::TONEGRAY]) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + loop do + previewsprite.tone.set(sliderwin2.value(0), sliderwin2.value(1), + sliderwin2.value(2), sliderwin2.value(3)) + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + cel[AnimFrame::TONERED] = sliderwin2.value(0) + cel[AnimFrame::TONEGREEN] = sliderwin2.value(1) + cel[AnimFrame::TONEBLUE] = sliderwin2.value(2) + cel[AnimFrame::TONEGRAY] = sliderwin2.value(3) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + sliderwin2.dispose + return + end + + def pbSetFlash(cel, previewsprite) + sliderwin2 = ControlWindow.new(0, 0, 320, 320) + sliderwin2.z = 99999 + sliderwin2.addSlider(_INTL("Red:"), 0, 255, cel[AnimFrame::COLORRED]) + sliderwin2.addSlider(_INTL("Green:"), 0, 255, cel[AnimFrame::COLORGREEN]) + sliderwin2.addSlider(_INTL("Blue:"), 0, 255, cel[AnimFrame::COLORBLUE]) + sliderwin2.addSlider(_INTL("Alpha:"), 0, 255, cel[AnimFrame::COLORALPHA]) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + loop do + previewsprite.tone.set(sliderwin2.value(0), sliderwin2.value(1), + sliderwin2.value(2), sliderwin2.value(3)) + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + cel[AnimFrame::COLORRED] = sliderwin2.value(0) + cel[AnimFrame::COLORGREEN] = sliderwin2.value(1) + cel[AnimFrame::COLORBLUE] = sliderwin2.value(2) + cel[AnimFrame::COLORALPHA] = sliderwin2.value(3) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + sliderwin2.dispose + return + end + + def pbCellProperties(canvas) + cel = canvas.currentCel.clone # Clone cell, in case operation is canceled + return if !cel + sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 16) + previewwin = ControlWindow.new(320, 0, 192, 192) + sliderwin2.viewport = canvas.viewport + previewwin.viewport = canvas.viewport + previewsprite = Sprite.new(canvas.viewport) + previewsprite.bitmap = canvas.animbitmap + previewsprite.z = previewwin.z + 1 + sliderwin2.z = previewwin.z + 2 + set0 = sliderwin2.addSlider(_INTL("Pattern:"), -2, 1000, cel[AnimFrame::PATTERN]) + set1 = sliderwin2.addSlider(_INTL("X:"), -64, 512 + 64, cel[AnimFrame::X]) + set2 = sliderwin2.addSlider(_INTL("Y:"), -64, 384 + 64, cel[AnimFrame::Y]) + set3 = sliderwin2.addSlider(_INTL("Zoom X:"), 5, 1000, cel[AnimFrame::ZOOMX]) + set4 = sliderwin2.addSlider(_INTL("Zoom Y:"), 5, 1000, cel[AnimFrame::ZOOMY]) + set5 = sliderwin2.addSlider(_INTL("Angle:"), 0, 359, cel[AnimFrame::ANGLE]) + set6 = sliderwin2.addSlider(_INTL("Opacity:"), 0, 255, cel[AnimFrame::OPACITY]) + set7 = sliderwin2.addSlider(_INTL("Blending:"), 0, 2, cel[AnimFrame::BLENDTYPE]) + set8 = sliderwin2.addTextSlider(_INTL("Flip:"), [_INTL("False"), _INTL("True")], cel[AnimFrame::MIRROR]) + prio = [_INTL("Back"), _INTL("Front"), _INTL("Behind focus"), _INTL("Above focus")] + set9 = sliderwin2.addTextSlider(_INTL("Priority:"), prio, cel[AnimFrame::PRIORITY] || 1) + foc = [_INTL("User"), _INTL("Target"), _INTL("User and target"), _INTL("Screen")] + curfoc = [3, 1, 0, 2, 3][cel[AnimFrame::FOCUS] || canvas.animation.position || 4] + set10 = sliderwin2.addTextSlider(_INTL("Focus:"), foc, curfoc) + flashbutton = sliderwin2.addButton(_INTL("Set Blending Color")) + tonebutton = sliderwin2.addButton(_INTL("Set Color Tone")) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + # Set X and Y for preview sprite + cel[AnimFrame::X] = 320 + 96 + cel[AnimFrame::Y] = 96 + canvas.setSpriteBitmap(previewsprite, cel) + pbSpriteSetAnimFrame(previewsprite, cel, nil, nil) + previewsprite.z = previewwin.z + 1 + sliderwin2.opacity = 200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(set0) || + sliderwin2.changed?(set3) || + sliderwin2.changed?(set4) || + sliderwin2.changed?(set5) || + sliderwin2.changed?(set6) || + sliderwin2.changed?(set7) || + sliderwin2.changed?(set8) || + sliderwin2.changed?(set9) || + sliderwin2.changed?(set10) + # Update preview sprite + cel[AnimFrame::PATTERN] = sliderwin2.value(set0) if set0 >= 0 + cel[AnimFrame::ZOOMX] = sliderwin2.value(set3) + cel[AnimFrame::ZOOMY] = sliderwin2.value(set4) + cel[AnimFrame::ANGLE] = sliderwin2.value(set5) + cel[AnimFrame::OPACITY] = sliderwin2.value(set6) + cel[AnimFrame::BLENDTYPE] = sliderwin2.value(set7) + cel[AnimFrame::MIRROR] = sliderwin2.value(set8) + cel[AnimFrame::PRIORITY] = sliderwin2.value(set9) + cel[AnimFrame::FOCUS] = [2, 1, 3, 4][sliderwin2.value(set10)] + canvas.setSpriteBitmap(previewsprite, cel) + pbSpriteSetAnimFrame(previewsprite, cel, nil, nil) + previewsprite.z = previewwin.z + 1 + end + if sliderwin2.changed?(flashbutton) + pbSetFlash(cel, previewsprite) + pbSpriteSetAnimFrame(previewsprite, cel, nil, nil) + previewsprite.z = previewwin.z + 1 + end + if sliderwin2.changed?(tonebutton) + pbSetTone(cel, previewsprite) + pbSpriteSetAnimFrame(previewsprite, cel, nil, nil) + previewsprite.z = previewwin.z + 1 + end + if sliderwin2.changed?(okbutton) + cel[AnimFrame::PATTERN] = sliderwin2.value(set0) if set0 >= 0 + cel[AnimFrame::X] = sliderwin2.value(set1) + cel[AnimFrame::Y] = sliderwin2.value(set2) + cel[AnimFrame::ZOOMX] = sliderwin2.value(set3) + cel[AnimFrame::ZOOMY] = sliderwin2.value(set4) + cel[AnimFrame::ANGLE] = sliderwin2.value(set5) + cel[AnimFrame::OPACITY] = sliderwin2.value(set6) + cel[AnimFrame::BLENDTYPE] = sliderwin2.value(set7) + cel[AnimFrame::MIRROR] = sliderwin2.value(set8) + cel[AnimFrame::PRIORITY] = sliderwin2.value(set9) + cel[AnimFrame::FOCUS] = [2, 1, 3, 4][sliderwin2.value(set10)] + thiscel = canvas.currentCel + # Save by replacing current cell + thiscel[0, thiscel.length] = cel + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + previewwin.dispose + previewsprite.dispose + sliderwin2.dispose + return + end + + #=============================================================================== + # Pop-up menus for buttons in right hand menu + #=============================================================================== + def pbTimingList(canvas) + commands = [] + cmdNewSound = -1 + cmdNewBG = -1 + cmdEditBG = -1 + cmdNewFO = -1 + cmdEditFO = -1 + canvas.animation.timing.each do |i| + commands.push(sprintf("%s", i)) + end + commands[cmdNewSound = commands.length] = _INTL("Add: Play Sound...") + commands[cmdNewBG = commands.length] = _INTL("Add: Set Background Graphic...") + commands[cmdEditBG = commands.length] = _INTL("Add: Edit Background Color/Location...") + commands[cmdNewFO = commands.length] = _INTL("Add: Set Foreground Graphic...") + commands[cmdEditFO = commands.length] = _INTL("Add: Edit Foreground Color/Location...") + cmdwin = pbListWindow(commands, 480) + cmdwin.x = 0 + cmdwin.y = 0 + cmdwin.width = 640 + cmdwin.height = 384 + cmdwin.opacity = 200 + cmdwin.viewport = canvas.viewport + framewindow = ControlWindow.new(0, 384, 640, 32 * 4) + framewindow.addSlider(_INTL("Frame:"), 1, canvas.animation.length, canvas.currentframe + 1) + framewindow.addButton(_INTL("Set Frame")) + framewindow.addButton(_INTL("Delete Timing")) + framewindow.opacity = 200 + framewindow.viewport = canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + framewindow.update + if cmdwin.index != cmdNewSound && + cmdwin.index != cmdNewBG && + cmdwin.index != cmdEditBG && + cmdwin.index != cmdNewFO && + cmdwin.index != cmdEditFO + if framewindow.changed?(1) # Set Frame + canvas.animation.timing[cmdwin.index].frame = framewindow.value(0) - 1 + cmdwin.commands[cmdwin.index] = sprintf("%s", canvas.animation.timing[cmdwin.index]) + cmdwin.refresh + next + end + if framewindow.changed?(2) # Delete Timing + canvas.animation.timing.delete_at(cmdwin.index) + cmdwin.commands.delete_at(cmdwin.index) + cmdNewSound -= 1 if cmdNewSound >= 0 + cmdNewBG -= 1 if cmdNewBG >= 0 + cmdEditBG -= 1 if cmdEditBG >= 0 + cmdNewFO -= 1 if cmdNewFO >= 0 + cmdEditFO -= 1 if cmdEditFO >= 0 + cmdwin.refresh + next + end + end + if Input.trigger?(Input::USE) + redrawcmds = false + if cmdwin.index == cmdNewSound # Add new sound + newaudio = PBAnimTiming.new(0) + if pbSelectSE(canvas, newaudio) + newaudio.frame = framewindow.value(0) - 1 + canvas.animation.timing.push(newaudio) + redrawcmds = true + end + elsif cmdwin.index == cmdNewBG # Add new background graphic set + newtiming = PBAnimTiming.new(1) + if pbSelectBG(canvas, newtiming) + newtiming.frame = framewindow.value(0) - 1 + canvas.animation.timing.push(newtiming) + redrawcmds = true + end + elsif cmdwin.index == cmdEditBG # Add new background edit + newtiming = PBAnimTiming.new(2) + if pbEditBG(canvas, newtiming) + newtiming.frame = framewindow.value(0) - 1 + canvas.animation.timing.push(newtiming) + redrawcmds = true + end + elsif cmdwin.index == cmdNewFO # Add new foreground graphic set + newtiming = PBAnimTiming.new(3) + if pbSelectBG(canvas, newtiming) + newtiming.frame = framewindow.value(0) - 1 + canvas.animation.timing.push(newtiming) + redrawcmds = true + end + elsif cmdwin.index == cmdEditFO # Add new foreground edit + newtiming = PBAnimTiming.new(4) + if pbEditBG(canvas, newtiming) + newtiming.frame = framewindow.value(0) - 1 + canvas.animation.timing.push(newtiming) + redrawcmds = true + end + else + # Edit a timing here + case canvas.animation.timing[cmdwin.index].timingType + when 0 + pbSelectSE(canvas, canvas.animation.timing[cmdwin.index]) + when 1, 3 + pbSelectBG(canvas, canvas.animation.timing[cmdwin.index]) + when 2, 4 + pbEditBG(canvas, canvas.animation.timing[cmdwin.index]) + end + cmdwin.commands[cmdwin.index] = sprintf("%s", canvas.animation.timing[cmdwin.index]) cmdwin.refresh end + if redrawcmds + cmdwin.commands[cmdNewSound] = nil if cmdNewSound >= 0 + cmdwin.commands[cmdNewBG] = nil if cmdNewBG >= 0 + cmdwin.commands[cmdEditBG] = nil if cmdEditBG >= 0 + cmdwin.commands[cmdNewFO] = nil if cmdNewFO >= 0 + cmdwin.commands[cmdEditFO] = nil if cmdEditFO >= 0 + cmdwin.commands.compact! + cmdwin.commands.push(sprintf("%s", canvas.animation.timing[canvas.animation.timing.length - 1])) + cmdwin.commands[cmdNewSound = cmdwin.commands.length] = _INTL("Add: Play Sound...") + cmdwin.commands[cmdNewBG = cmdwin.commands.length] = _INTL("Add: Set Background Graphic...") + cmdwin.commands[cmdEditBG = cmdwin.commands.length] = _INTL("Add: Edit Background Color/Location...") + cmdwin.commands[cmdNewFO = cmdwin.commands.length] = _INTL("Add: Set Foreground Graphic...") + cmdwin.commands[cmdEditFO = cmdwin.commands.length] = _INTL("Add: Edit Foreground Color/Location...") + cmdwin.refresh + end + elsif Input.trigger?(Input::BACK) + break end end - if Input.trigger?(Input::BACK) - break - end + cmdwin.dispose + framewindow.dispose + return end - helpwindow.dispose - maxsizewindow.dispose - cmdwin.dispose -end -#=============================================================================== -# Pop-up menus for individual cels -#=============================================================================== -def pbChooseNum(cel) - ret = cel - sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 5) - sliderwin2.z = 99999 - sliderwin2.addLabel(_INTL("Old Number: {1}", cel)) - sliderwin2.addSlider(_INTL("New Number:"), 2, PBAnimation::MAX_SPRITES, cel) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - ret = sliderwin2.value(1) - break + def pbSelectSE(canvas, audio) + filename = (audio.name != "") ? audio.name : "" + displayname = (filename != "") ? filename : _INTL("") + animfiles = [] + ret = false + pbRgssChdir(File.join("Audio", "SE", "Anim")) do + animfiles.concat(Dir.glob("*.wav")) + # animfiles.concat(Dir.glob("*.mp3")) + animfiles.concat(Dir.glob("*.ogg")) + animfiles.concat(Dir.glob("*.wma")) end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - ret = -1 - break - end - end - sliderwin2.dispose - return ret -end - -def pbSetTone(cel, previewsprite) - sliderwin2 = ControlWindow.new(0, 0, 320, 320) - sliderwin2.z = 99999 - sliderwin2.addSlider(_INTL("Red Offset:"), -255, 255, cel[AnimFrame::TONERED]) - sliderwin2.addSlider(_INTL("Green Offset:"), -255, 255, cel[AnimFrame::TONEGREEN]) - sliderwin2.addSlider(_INTL("Blue Offset:"), -255, 255, cel[AnimFrame::TONEBLUE]) - sliderwin2.addSlider(_INTL("Gray Tone:"), 0, 255, cel[AnimFrame::TONEGRAY]) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - loop do - previewsprite.tone.set(sliderwin2.value(0), sliderwin2.value(1), - sliderwin2.value(2), sliderwin2.value(3)) - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - cel[AnimFrame::TONERED] = sliderwin2.value(0) - cel[AnimFrame::TONEGREEN] = sliderwin2.value(1) - cel[AnimFrame::TONEBLUE] = sliderwin2.value(2) - cel[AnimFrame::TONEGRAY] = sliderwin2.value(3) - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - sliderwin2.dispose - return -end - -def pbSetFlash(cel, previewsprite) - sliderwin2 = ControlWindow.new(0, 0, 320, 320) - sliderwin2.z = 99999 - sliderwin2.addSlider(_INTL("Red:"), 0, 255, cel[AnimFrame::COLORRED]) - sliderwin2.addSlider(_INTL("Green:"), 0, 255, cel[AnimFrame::COLORGREEN]) - sliderwin2.addSlider(_INTL("Blue:"), 0, 255, cel[AnimFrame::COLORBLUE]) - sliderwin2.addSlider(_INTL("Alpha:"), 0, 255, cel[AnimFrame::COLORALPHA]) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - loop do - previewsprite.tone.set(sliderwin2.value(0), sliderwin2.value(1), - sliderwin2.value(2), sliderwin2.value(3)) - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - cel[AnimFrame::COLORRED] = sliderwin2.value(0) - cel[AnimFrame::COLORGREEN] = sliderwin2.value(1) - cel[AnimFrame::COLORBLUE] = sliderwin2.value(2) - cel[AnimFrame::COLORALPHA] = sliderwin2.value(3) - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - sliderwin2.dispose - return -end - -def pbCellProperties(canvas) - cel = canvas.currentCel.clone # Clone cell, in case operation is canceled - return if !cel - sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 16) - previewwin = ControlWindow.new(320, 0, 192, 192) - sliderwin2.viewport = canvas.viewport - previewwin.viewport = canvas.viewport - previewsprite = Sprite.new(canvas.viewport) - previewsprite.bitmap = canvas.animbitmap - previewsprite.z = previewwin.z + 1 - sliderwin2.z = previewwin.z + 2 - set0 = sliderwin2.addSlider(_INTL("Pattern:"), -2, 1000, cel[AnimFrame::PATTERN]) - set1 = sliderwin2.addSlider(_INTL("X:"), -64, 512 + 64, cel[AnimFrame::X]) - set2 = sliderwin2.addSlider(_INTL("Y:"), -64, 384 + 64, cel[AnimFrame::Y]) - set3 = sliderwin2.addSlider(_INTL("Zoom X:"), 5, 1000, cel[AnimFrame::ZOOMX]) - set4 = sliderwin2.addSlider(_INTL("Zoom Y:"), 5, 1000, cel[AnimFrame::ZOOMY]) - set5 = sliderwin2.addSlider(_INTL("Angle:"), 0, 359, cel[AnimFrame::ANGLE]) - set6 = sliderwin2.addSlider(_INTL("Opacity:"), 0, 255, cel[AnimFrame::OPACITY]) - set7 = sliderwin2.addSlider(_INTL("Blending:"), 0, 2, cel[AnimFrame::BLENDTYPE]) - set8 = sliderwin2.addTextSlider(_INTL("Flip:"), [_INTL("False"), _INTL("True")], cel[AnimFrame::MIRROR]) - prio = [_INTL("Back"), _INTL("Front"), _INTL("Behind focus"), _INTL("Above focus")] - set9 = sliderwin2.addTextSlider(_INTL("Priority:"), prio, cel[AnimFrame::PRIORITY] || 1) - foc = [_INTL("User"), _INTL("Target"), _INTL("User and target"), _INTL("Screen")] - curfoc = [3, 1, 0, 2, 3][cel[AnimFrame::FOCUS] || canvas.animation.position || 4] - set10 = sliderwin2.addTextSlider(_INTL("Focus:"), foc, curfoc) - flashbutton = sliderwin2.addButton(_INTL("Set Blending Color")) - tonebutton = sliderwin2.addButton(_INTL("Set Color Tone")) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - # Set X and Y for preview sprite - cel[AnimFrame::X] = 320 + 96 - cel[AnimFrame::Y] = 96 - canvas.setSpriteBitmap(previewsprite, cel) - pbSpriteSetAnimFrame(previewsprite, cel, nil, nil) - previewsprite.z = previewwin.z + 1 - sliderwin2.opacity = 200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(set0) || - sliderwin2.changed?(set3) || - sliderwin2.changed?(set4) || - sliderwin2.changed?(set5) || - sliderwin2.changed?(set6) || - sliderwin2.changed?(set7) || - sliderwin2.changed?(set8) || - sliderwin2.changed?(set9) || - sliderwin2.changed?(set10) - # Update preview sprite - cel[AnimFrame::PATTERN] = sliderwin2.value(set0) if set0 >= 0 - cel[AnimFrame::ZOOMX] = sliderwin2.value(set3) - cel[AnimFrame::ZOOMY] = sliderwin2.value(set4) - cel[AnimFrame::ANGLE] = sliderwin2.value(set5) - cel[AnimFrame::OPACITY] = sliderwin2.value(set6) - cel[AnimFrame::BLENDTYPE] = sliderwin2.value(set7) - cel[AnimFrame::MIRROR] = sliderwin2.value(set8) - cel[AnimFrame::PRIORITY] = sliderwin2.value(set9) - cel[AnimFrame::FOCUS] = [2, 1, 3, 4][sliderwin2.value(set10)] - canvas.setSpriteBitmap(previewsprite, cel) - pbSpriteSetAnimFrame(previewsprite, cel, nil, nil) - previewsprite.z = previewwin.z + 1 - end - if sliderwin2.changed?(flashbutton) - pbSetFlash(cel, previewsprite) - pbSpriteSetAnimFrame(previewsprite, cel, nil, nil) - previewsprite.z = previewwin.z + 1 - end - if sliderwin2.changed?(tonebutton) - pbSetTone(cel, previewsprite) - pbSpriteSetAnimFrame(previewsprite, cel, nil, nil) - previewsprite.z = previewwin.z + 1 - end - if sliderwin2.changed?(okbutton) - cel[AnimFrame::PATTERN] = sliderwin2.value(set0) if set0 >= 0 - cel[AnimFrame::X] = sliderwin2.value(set1) - cel[AnimFrame::Y] = sliderwin2.value(set2) - cel[AnimFrame::ZOOMX] = sliderwin2.value(set3) - cel[AnimFrame::ZOOMY] = sliderwin2.value(set4) - cel[AnimFrame::ANGLE] = sliderwin2.value(set5) - cel[AnimFrame::OPACITY] = sliderwin2.value(set6) - cel[AnimFrame::BLENDTYPE] = sliderwin2.value(set7) - cel[AnimFrame::MIRROR] = sliderwin2.value(set8) - cel[AnimFrame::PRIORITY] = sliderwin2.value(set9) - cel[AnimFrame::FOCUS] = [2, 1, 3, 4][sliderwin2.value(set10)] - thiscel = canvas.currentCel - # Save by replacing current cell - thiscel[0, thiscel.length] = cel - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - previewwin.dispose - previewsprite.dispose - sliderwin2.dispose - return -end - -#=============================================================================== -# Pop-up menus for buttons in right hand menu -#=============================================================================== -def pbTimingList(canvas) - commands = [] - cmdNewSound = -1 - cmdNewBG = -1 - cmdEditBG = -1 - cmdNewFO = -1 - cmdEditFO = -1 - canvas.animation.timing.each do |i| - commands.push(sprintf("%s", i)) - end - commands[cmdNewSound = commands.length] = _INTL("Add: Play Sound...") - commands[cmdNewBG = commands.length] = _INTL("Add: Set Background Graphic...") - commands[cmdEditBG = commands.length] = _INTL("Add: Edit Background Color/Location...") - commands[cmdNewFO = commands.length] = _INTL("Add: Set Foreground Graphic...") - commands[cmdEditFO = commands.length] = _INTL("Add: Edit Foreground Color/Location...") - cmdwin = pbListWindow(commands, 480) - cmdwin.x = 0 - cmdwin.y = 0 - cmdwin.width = 640 - cmdwin.height = 384 - cmdwin.opacity = 200 - cmdwin.viewport = canvas.viewport - framewindow = ControlWindow.new(0, 384, 640, 32 * 4) - framewindow.addSlider(_INTL("Frame:"), 1, canvas.animation.length, canvas.currentframe + 1) - framewindow.addButton(_INTL("Set Frame")) - framewindow.addButton(_INTL("Delete Timing")) - framewindow.opacity = 200 - framewindow.viewport = canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - framewindow.update - if cmdwin.index != cmdNewSound && - cmdwin.index != cmdNewBG && - cmdwin.index != cmdEditBG && - cmdwin.index != cmdNewFO && - cmdwin.index != cmdEditFO - if framewindow.changed?(1) # Set Frame - canvas.animation.timing[cmdwin.index].frame = framewindow.value(0) - 1 - cmdwin.commands[cmdwin.index] = sprintf("%s", canvas.animation.timing[cmdwin.index]) - cmdwin.refresh - next + animfiles.uniq! + animfiles.sort! { |a, b| a.downcase <=> b.downcase } + animfiles = [_INTL("[Play user's cry]")] + animfiles + cmdwin = pbListWindow(animfiles, 320) + cmdwin.height = 480 + cmdwin.opacity = 200 + cmdwin.viewport = canvas.viewport + maxsizewindow = ControlWindow.new(320, 0, 320, 32 * 8) + maxsizewindow.addLabel(_INTL("File: \"{1}\"", displayname)) + maxsizewindow.addSlider(_INTL("Volume:"), 0, 100, audio.volume) + maxsizewindow.addSlider(_INTL("Pitch:"), 20, 250, audio.pitch) + maxsizewindow.addButton(_INTL("Play Sound")) + maxsizewindow.addButton(_INTL("Stop Sound")) + maxsizewindow.addButton(_INTL("OK")) + maxsizewindow.addButton(_INTL("Cancel")) + maxsizewindow.opacity = 200 + maxsizewindow.viewport = canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + maxsizewindow.update + if maxsizewindow.changed?(3) && animfiles.length > 0 && filename != "" # Play Sound + pbSEPlay(RPG::AudioFile.new("Anim/" + filename, maxsizewindow.value(1), maxsizewindow.value(2))) end - if framewindow.changed?(2) # Delete Timing - canvas.animation.timing.delete_at(cmdwin.index) - cmdwin.commands.delete_at(cmdwin.index) - cmdNewSound -= 1 if cmdNewSound >= 0 - cmdNewBG -= 1 if cmdNewBG >= 0 - cmdEditBG -= 1 if cmdEditBG >= 0 - cmdNewFO -= 1 if cmdNewFO >= 0 - cmdEditFO -= 1 if cmdEditFO >= 0 - cmdwin.refresh - next + pbSEStop if maxsizewindow.changed?(4) && animfiles.length > 0 # Stop Sound + if maxsizewindow.changed?(5) # OK + audio.name = File.basename(filename, ".*") + audio.volume = maxsizewindow.value(1) + audio.pitch = maxsizewindow.value(2) + ret = true + break + end + break if maxsizewindow.changed?(6) # Cancel + if Input.trigger?(Input::USE) && animfiles.length > 0 + filename = (cmdwin.index == 0) ? "" : cmdwin.commands[cmdwin.index] + displayname = (filename != "") ? filename : _INTL("") + maxsizewindow.controls[0].text = _INTL("File: \"{1}\"", displayname) + elsif Input.trigger?(Input::BACK) + break end end - if Input.trigger?(Input::USE) - redrawcmds = false - if cmdwin.index == cmdNewSound # Add new sound - newaudio = PBAnimTiming.new(0) - if pbSelectSE(canvas, newaudio) - newaudio.frame = framewindow.value(0) - 1 - canvas.animation.timing.push(newaudio) - redrawcmds = true - end - elsif cmdwin.index == cmdNewBG # Add new background graphic set - newtiming = PBAnimTiming.new(1) - if pbSelectBG(canvas, newtiming) - newtiming.frame = framewindow.value(0) - 1 - canvas.animation.timing.push(newtiming) - redrawcmds = true - end - elsif cmdwin.index == cmdEditBG # Add new background edit - newtiming = PBAnimTiming.new(2) - if pbEditBG(canvas, newtiming) - newtiming.frame = framewindow.value(0) - 1 - canvas.animation.timing.push(newtiming) - redrawcmds = true - end - elsif cmdwin.index == cmdNewFO # Add new foreground graphic set - newtiming = PBAnimTiming.new(3) - if pbSelectBG(canvas, newtiming) - newtiming.frame = framewindow.value(0) - 1 - canvas.animation.timing.push(newtiming) - redrawcmds = true - end - elsif cmdwin.index == cmdEditFO # Add new foreground edit - newtiming = PBAnimTiming.new(4) - if pbEditBG(canvas, newtiming) - newtiming.frame = framewindow.value(0) - 1 - canvas.animation.timing.push(newtiming) - redrawcmds = true - end - else - # Edit a timing here - case canvas.animation.timing[cmdwin.index].timingType - when 0 - pbSelectSE(canvas, canvas.animation.timing[cmdwin.index]) - when 1, 3 - pbSelectBG(canvas, canvas.animation.timing[cmdwin.index]) - when 2, 4 - pbEditBG(canvas, canvas.animation.timing[cmdwin.index]) - end - cmdwin.commands[cmdwin.index] = sprintf("%s", canvas.animation.timing[cmdwin.index]) - cmdwin.refresh - end - if redrawcmds - cmdwin.commands[cmdNewSound] = nil if cmdNewSound >= 0 - cmdwin.commands[cmdNewBG] = nil if cmdNewBG >= 0 - cmdwin.commands[cmdEditBG] = nil if cmdEditBG >= 0 - cmdwin.commands[cmdNewFO] = nil if cmdNewFO >= 0 - cmdwin.commands[cmdEditFO] = nil if cmdEditFO >= 0 - cmdwin.commands.compact! - cmdwin.commands.push(sprintf("%s", canvas.animation.timing[canvas.animation.timing.length - 1])) - cmdwin.commands[cmdNewSound = cmdwin.commands.length] = _INTL("Add: Play Sound...") - cmdwin.commands[cmdNewBG = cmdwin.commands.length] = _INTL("Add: Set Background Graphic...") - cmdwin.commands[cmdEditBG = cmdwin.commands.length] = _INTL("Add: Edit Background Color/Location...") - cmdwin.commands[cmdNewFO = cmdwin.commands.length] = _INTL("Add: Set Foreground Graphic...") - cmdwin.commands[cmdEditFO = cmdwin.commands.length] = _INTL("Add: Edit Foreground Color/Location...") - cmdwin.refresh - end - elsif Input.trigger?(Input::BACK) - break - end + cmdwin.dispose + maxsizewindow.dispose + return ret end - cmdwin.dispose - framewindow.dispose - return -end -def pbSelectSE(canvas, audio) - filename = (audio.name != "") ? audio.name : "" - displayname = (filename != "") ? filename : _INTL("") - animfiles = [] - ret = false - pbRgssChdir(File.join("Audio", "SE", "Anim")) do - animfiles.concat(Dir.glob("*.wav")) -# animfiles.concat(Dir.glob("*.mp3")) - animfiles.concat(Dir.glob("*.ogg")) - animfiles.concat(Dir.glob("*.wma")) - end - animfiles.uniq! - animfiles.sort! { |a, b| a.downcase <=> b.downcase } - animfiles = [_INTL("[Play user's cry]")] + animfiles - cmdwin = pbListWindow(animfiles, 320) - cmdwin.height = 480 - cmdwin.opacity = 200 - cmdwin.viewport = canvas.viewport - maxsizewindow = ControlWindow.new(320, 0, 320, 32 * 8) - maxsizewindow.addLabel(_INTL("File: \"{1}\"", displayname)) - maxsizewindow.addSlider(_INTL("Volume:"), 0, 100, audio.volume) - maxsizewindow.addSlider(_INTL("Pitch:"), 20, 250, audio.pitch) - maxsizewindow.addButton(_INTL("Play Sound")) - maxsizewindow.addButton(_INTL("Stop Sound")) - maxsizewindow.addButton(_INTL("OK")) - maxsizewindow.addButton(_INTL("Cancel")) - maxsizewindow.opacity = 200 - maxsizewindow.viewport = canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - maxsizewindow.update - if maxsizewindow.changed?(3) && animfiles.length > 0 # Play Sound - fname = (cmdwin.index == 0) ? "Cries/000" : "Anim/" + filename - pbSEPlay(RPG::AudioFile.new(fname, maxsizewindow.value(1), maxsizewindow.value(2))) + def pbSelectBG(canvas, timing) + filename = timing.name + cmdErase = -1 + animfiles = [] + animfiles[cmdErase = animfiles.length] = _INTL("[Erase background graphic]") + ret = false + pbRgssChdir(File.join("Graphics", "Animations")) do + animfiles.concat(Dir.glob("*.png")) + animfiles.concat(Dir.glob("*.gif")) + # animfiles.concat(Dir.glob("*.jpg")) + # animfiles.concat(Dir.glob("*.jpeg")) + # animfiles.concat(Dir.glob("*.bmp")) end - pbSEStop if maxsizewindow.changed?(4) && animfiles.length > 0 # Stop Sound - if maxsizewindow.changed?(5) # OK - audio.name = File.basename(filename, ".*") - audio.volume = maxsizewindow.value(1) - audio.pitch = maxsizewindow.value(2) - ret = true - break - end - break if maxsizewindow.changed?(6) # Cancel - if Input.trigger?(Input::USE) && animfiles.length > 0 - filename = (cmdwin.index == 0) ? "" : cmdwin.commands[cmdwin.index] - displayname = (filename != "") ? filename : _INTL("") - maxsizewindow.controls[0].text = _INTL("File: \"{1}\"", displayname) - elsif Input.trigger?(Input::BACK) - break - end - end - cmdwin.dispose - maxsizewindow.dispose - return ret -end - -def pbSelectBG(canvas, timing) - filename = timing.name - cmdErase = -1 - animfiles = [] - animfiles[cmdErase = animfiles.length] = _INTL("[Erase background graphic]") - ret = false - pbRgssChdir(File.join("Graphics", "Animations")) do - animfiles.concat(Dir.glob("*.png")) - animfiles.concat(Dir.glob("*.gif")) -# animfiles.concat(Dir.glob("*.jpg")) -# animfiles.concat(Dir.glob("*.jpeg")) -# animfiles.concat(Dir.glob("*.bmp")) - end - animfiles.uniq! - animfiles.sort! { |a, b| a.downcase <=> b.downcase } - cmdwin = pbListWindow(animfiles, 320) - cmdwin.height = 480 - cmdwin.opacity = 200 - cmdwin.viewport = canvas.viewport - maxsizewindow = ControlWindow.new(320, 0, 320, 32 * 11) - maxsizewindow.addLabel(_INTL("File: \"{1}\"", filename)) - maxsizewindow.addSlider(_INTL("X:"), -500, 500, timing.bgX || 0) - maxsizewindow.addSlider(_INTL("Y:"), -500, 500, timing.bgY || 0) - maxsizewindow.addSlider(_INTL("Opacity:"), 0, 255, timing.opacity || 0) - maxsizewindow.addSlider(_INTL("Red:"), 0, 255, timing.colorRed || 0) - maxsizewindow.addSlider(_INTL("Green:"), 0, 255, timing.colorGreen || 0) - maxsizewindow.addSlider(_INTL("Blue:"), 0, 255, timing.colorBlue || 0) - maxsizewindow.addSlider(_INTL("Alpha:"), 0, 255, timing.colorAlpha || 0) - maxsizewindow.addButton(_INTL("OK")) - maxsizewindow.addButton(_INTL("Cancel")) - maxsizewindow.opacity = 200 - maxsizewindow.viewport = canvas.viewport - loop do - Graphics.update - Input.update - cmdwin.update - maxsizewindow.update - if maxsizewindow.changed?(8) # OK - timing.name = File.basename(filename, ".*") - timing.bgX = maxsizewindow.value(1) - timing.bgY = maxsizewindow.value(2) - timing.opacity = maxsizewindow.value(3) - timing.colorRed = maxsizewindow.value(4) - timing.colorGreen = maxsizewindow.value(5) - timing.colorBlue = maxsizewindow.value(6) - timing.colorAlpha = maxsizewindow.value(7) - ret = true - break - end - break if maxsizewindow.changed?(9) # Cancel - if Input.trigger?(Input::USE) && animfiles.length > 0 - filename = (cmdwin.index == cmdErase) ? "" : cmdwin.commands[cmdwin.index] - maxsizewindow.controls[0].text = _INTL("File: \"{1}\"", filename) - elsif Input.trigger?(Input::BACK) - break - end - end - cmdwin.dispose - maxsizewindow.dispose - return ret -end - -def pbEditBG(canvas, timing) - ret = false - maxsizewindow = ControlWindow.new(0, 0, 320, 32 * 11) - maxsizewindow.addSlider(_INTL("Duration:"), 0, 50, timing.duration) - maxsizewindow.addOptionalSlider(_INTL("X:"), -500, 500, timing.bgX || 0) - maxsizewindow.addOptionalSlider(_INTL("Y:"), -500, 500, timing.bgY || 0) - maxsizewindow.addOptionalSlider(_INTL("Opacity:"), 0, 255, timing.opacity || 0) - maxsizewindow.addOptionalSlider(_INTL("Red:"), 0, 255, timing.colorRed || 0) - maxsizewindow.addOptionalSlider(_INTL("Green:"), 0, 255, timing.colorGreen || 0) - maxsizewindow.addOptionalSlider(_INTL("Blue:"), 0, 255, timing.colorBlue || 0) - maxsizewindow.addOptionalSlider(_INTL("Alpha:"), 0, 255, timing.colorAlpha || 0) - maxsizewindow.addButton(_INTL("OK")) - maxsizewindow.addButton(_INTL("Cancel")) - maxsizewindow.controls[1].checked = !timing.bgX.nil? - maxsizewindow.controls[2].checked = !timing.bgY.nil? - maxsizewindow.controls[3].checked = !timing.opacity.nil? - maxsizewindow.controls[4].checked = !timing.colorRed.nil? - maxsizewindow.controls[5].checked = !timing.colorGreen.nil? - maxsizewindow.controls[6].checked = !timing.colorBlue.nil? - maxsizewindow.controls[7].checked = !timing.colorAlpha.nil? - maxsizewindow.opacity = 200 - maxsizewindow.viewport = canvas.viewport - loop do - Graphics.update - Input.update - maxsizewindow.update - if maxsizewindow.changed?(8) # OK - if maxsizewindow.controls[1].checked || - maxsizewindow.controls[2].checked || - maxsizewindow.controls[3].checked || - maxsizewindow.controls[4].checked || - maxsizewindow.controls[5].checked || - maxsizewindow.controls[6].checked || - maxsizewindow.controls[7].checked - timing.duration = maxsizewindow.value(0) + animfiles.uniq! + animfiles.sort! { |a, b| a.downcase <=> b.downcase } + cmdwin = pbListWindow(animfiles, 320) + cmdwin.height = 480 + cmdwin.opacity = 200 + cmdwin.viewport = canvas.viewport + maxsizewindow = ControlWindow.new(320, 0, 320, 32 * 11) + maxsizewindow.addLabel(_INTL("File: \"{1}\"", filename)) + maxsizewindow.addSlider(_INTL("X:"), -500, 500, timing.bgX || 0) + maxsizewindow.addSlider(_INTL("Y:"), -500, 500, timing.bgY || 0) + maxsizewindow.addSlider(_INTL("Opacity:"), 0, 255, timing.opacity || 0) + maxsizewindow.addSlider(_INTL("Red:"), 0, 255, timing.colorRed || 0) + maxsizewindow.addSlider(_INTL("Green:"), 0, 255, timing.colorGreen || 0) + maxsizewindow.addSlider(_INTL("Blue:"), 0, 255, timing.colorBlue || 0) + maxsizewindow.addSlider(_INTL("Alpha:"), 0, 255, timing.colorAlpha || 0) + maxsizewindow.addButton(_INTL("OK")) + maxsizewindow.addButton(_INTL("Cancel")) + maxsizewindow.opacity = 200 + maxsizewindow.viewport = canvas.viewport + loop do + Graphics.update + Input.update + cmdwin.update + maxsizewindow.update + if maxsizewindow.changed?(8) # OK + timing.name = File.basename(filename, ".*") timing.bgX = maxsizewindow.value(1) timing.bgY = maxsizewindow.value(2) timing.opacity = maxsizewindow.value(3) @@ -664,490 +608,550 @@ def pbEditBG(canvas, timing) timing.colorBlue = maxsizewindow.value(6) timing.colorAlpha = maxsizewindow.value(7) ret = true + break end - break - end - break if maxsizewindow.changed?(9) # Cancel - if Input.trigger?(Input::BACK) - break - end - end - maxsizewindow.dispose - return ret -end - -def pbCopyFrames(canvas) - sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 6) - sliderwin2.viewport = canvas.viewport - sliderwin2.addSlider(_INTL("First Frame:"), 1, canvas.animation.length, 1) - sliderwin2.addSlider(_INTL("Last Frame:"), 1, canvas.animation.length, canvas.animation.length) - sliderwin2.addSlider(_INTL("Copy to:"), 1, canvas.animation.length, canvas.currentframe + 1) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - sliderwin2.opacity = 200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - startvalue = sliderwin2.value(0) - 1 - endvalue = sliderwin2.value(1) - 1 - dstvalue = sliderwin2.value(2) - 1 - length = (endvalue - startvalue) + 1 - if length > 0 # Ensure correct overlap handling - if startvalue < dstvalue - startvalue += length - dstvalue += length - while length != 0 - canvas.copyFrame(startvalue - 1, dstvalue - 1) - startvalue -= 1 - dstvalue -= 1 - length -= 1 - end - elsif startvalue != dstvalue - while length != 0 - canvas.copyFrame(startvalue, dstvalue) - startvalue += 1 - dstvalue += 1 - length -= 1 - end - end - end - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - sliderwin2.dispose - return -end - -def pbClearFrames(canvas) - sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 5) - sliderwin2.viewport = canvas.viewport - sliderwin2.addSlider(_INTL("First Frame:"), 1, canvas.animation.length, 1) - sliderwin2.addSlider(_INTL("Last Frame:"), 1, canvas.animation.length, canvas.animation.length) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - sliderwin2.opacity = 200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - startframe = sliderwin2.value(0) - 1 - endframe = sliderwin2.value(1) - 1 - (startframe..endframe).each do |i| - canvas.clearFrame(i) - end - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - sliderwin2.dispose - return -end - -def pbTweening(canvas) - sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 10) - sliderwin2.viewport = canvas.viewport - sliderwin2.opacity = 200 - s1set0 = sliderwin2.addSlider(_INTL("Starting Frame:"), 1, canvas.animation.length, 1) - s1set1 = sliderwin2.addSlider(_INTL("Ending Frame:"), 1, canvas.animation.length, canvas.animation.length) - s1set2 = sliderwin2.addSlider(_INTL("First Cel:"), 0, PBAnimation::MAX_SPRITES - 1, 0) - s1set3 = sliderwin2.addSlider(_INTL("Last Cel:"), 0, PBAnimation::MAX_SPRITES - 1, PBAnimation::MAX_SPRITES - 1) - set0 = sliderwin2.addCheckbox(_INTL("Pattern")) - set1 = sliderwin2.addCheckbox(_INTL("Position/Zoom/Angle")) - set2 = sliderwin2.addCheckbox(_INTL("Opacity/Blending")) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) || Input.trigger?(Input::USE) - startframe = sliderwin2.value(s1set0) - 1 - endframe = sliderwin2.value(s1set1) - 1 - break if startframe >= endframe - frames = endframe - startframe - startcel = sliderwin2.value(s1set2) - endcel = sliderwin2.value(s1set3) - (startcel..endcel).each do |j| - cel1 = canvas.animation[startframe][j] - cel2 = canvas.animation[endframe][j] - next if !cel1 || !cel2 - diffPattern = cel2[AnimFrame::PATTERN] - cel1[AnimFrame::PATTERN] - diffX = cel2[AnimFrame::X] - cel1[AnimFrame::X] - diffY = cel2[AnimFrame::Y] - cel1[AnimFrame::Y] - diffZoomX = cel2[AnimFrame::ZOOMX] - cel1[AnimFrame::ZOOMX] - diffZoomY = cel2[AnimFrame::ZOOMY] - cel1[AnimFrame::ZOOMY] - diffAngle = cel2[AnimFrame::ANGLE] - cel1[AnimFrame::ANGLE] - diffOpacity = cel2[AnimFrame::OPACITY] - cel1[AnimFrame::OPACITY] - diffBlend = cel2[AnimFrame::BLENDTYPE] - cel1[AnimFrame::BLENDTYPE] - startPattern = cel1[AnimFrame::PATTERN] - startX = cel1[AnimFrame::X] - startY = cel1[AnimFrame::Y] - startZoomX = cel1[AnimFrame::ZOOMX] - startZoomY = cel1[AnimFrame::ZOOMY] - startAngle = cel1[AnimFrame::ANGLE] - startOpacity = cel1[AnimFrame::OPACITY] - startBlend = cel1[AnimFrame::BLENDTYPE] - (0..frames).each do |k| - cel = canvas.animation[startframe + k][j] - curcel = cel - if !cel - cel = pbCreateCel(0, 0, 0) - canvas.animation[startframe + k][j] = cel - end - if sliderwin2.value(set0) || !curcel - cel[AnimFrame::PATTERN] = startPattern + (diffPattern * k / frames) - end - if sliderwin2.value(set1) || !curcel - cel[AnimFrame::X] = startX + (diffX * k / frames) - cel[AnimFrame::Y] = startY + (diffY * k / frames) - cel[AnimFrame::ZOOMX] = startZoomX + (diffZoomX * k / frames) - cel[AnimFrame::ZOOMY] = startZoomY + (diffZoomY * k / frames) - cel[AnimFrame::ANGLE] = startAngle + (diffAngle * k / frames) - end - if sliderwin2.value(set2) || !curcel - cel[AnimFrame::OPACITY] = startOpacity + (diffOpacity * k / frames) - cel[AnimFrame::BLENDTYPE] = startBlend + (diffBlend * k / frames) - end - end - end - canvas.invalidate - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - sliderwin2.dispose -end - -def pbCellBatch(canvas) - sliderwin1 = ControlWindow.new(0, 0, 300, 32 * 5) - sliderwin1.viewport = canvas.viewport - sliderwin1.opacity = 200 - s1set0 = sliderwin1.addSlider(_INTL("First Frame:"), 1, canvas.animation.length, 1) - s1set1 = sliderwin1.addSlider(_INTL("Last Frame:"), 1, canvas.animation.length, canvas.animation.length) - s1set2 = sliderwin1.addSlider(_INTL("First Cel:"), 0, PBAnimation::MAX_SPRITES - 1, 0) - s1set3 = sliderwin1.addSlider(_INTL("Last Cel:"), 0, PBAnimation::MAX_SPRITES - 1, PBAnimation::MAX_SPRITES - 1) - sliderwin2 = ControlWindow.new(300, 0, 340, 32 * 14) - sliderwin2.viewport = canvas.viewport - sliderwin2.opacity = 200 - set0 = sliderwin2.addOptionalSlider(_INTL("Pattern:"), -2, 1000, 0) - set1 = sliderwin2.addOptionalSlider(_INTL("X:"), -64, 512 + 64, 0) - set2 = sliderwin2.addOptionalSlider(_INTL("Y:"), -64, 384 + 64, 0) - set3 = sliderwin2.addOptionalSlider(_INTL("Zoom X:"), 5, 1000, 100) - set4 = sliderwin2.addOptionalSlider(_INTL("Zoom Y:"), 5, 1000, 100) - set5 = sliderwin2.addOptionalSlider(_INTL("Angle:"), 0, 359, 0) - set6 = sliderwin2.addOptionalSlider(_INTL("Opacity:"), 0, 255, 255) - set7 = sliderwin2.addOptionalSlider(_INTL("Blending:"), 0, 2, 0) - set8 = sliderwin2.addOptionalTextSlider(_INTL("Flip:"), [_INTL("False"), _INTL("True")], 0) - prio = [_INTL("Back"), _INTL("Front"), _INTL("Behind focus"), _INTL("Above focus")] - set9 = sliderwin2.addOptionalTextSlider(_INTL("Priority:"), prio, 1) - foc = [_INTL("User"), _INTL("Target"), _INTL("User and target"), _INTL("Screen")] - curfoc = [3, 1, 0, 2, 3][canvas.animation.position || 4] - set10 = sliderwin2.addOptionalTextSlider(_INTL("Focus:"), foc, curfoc) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - loop do - Graphics.update - Input.update - sliderwin1.update - sliderwin2.update - if sliderwin2.changed?(okbutton) || Input.trigger?(Input::USE) - startframe = sliderwin1.value(s1set0) - 1 - endframe = sliderwin1.value(s1set1) - 1 - startcel = sliderwin1.value(s1set2) - endcel = sliderwin1.value(s1set3) - (startframe..endframe).each do |i| - (startcel..endcel).each do |j| - next if !canvas.animation[i][j] - cel = canvas.animation[i][j] - cel[AnimFrame::PATTERN] = sliderwin2.value(set0) if sliderwin2.value(set0) - cel[AnimFrame::X] = sliderwin2.value(set1) if sliderwin2.value(set1) - cel[AnimFrame::Y] = sliderwin2.value(set2) if sliderwin2.value(set2) - cel[AnimFrame::ZOOMX] = sliderwin2.value(set3) if sliderwin2.value(set3) - cel[AnimFrame::ZOOMY] = sliderwin2.value(set4) if sliderwin2.value(set4) - cel[AnimFrame::ANGLE] = sliderwin2.value(set5) if sliderwin2.value(set5) - cel[AnimFrame::OPACITY] = sliderwin2.value(set6) if sliderwin2.value(set6) - cel[AnimFrame::BLENDTYPE] = sliderwin2.value(set7) if sliderwin2.value(set7) - cel[AnimFrame::MIRROR] = sliderwin2.value(set8) if sliderwin2.value(set8) - cel[AnimFrame::PRIORITY] = sliderwin2.value(set9) if sliderwin2.value(set9) - cel[AnimFrame::FOCUS] = [2, 1, 3, 4][sliderwin2.value(set10)] if sliderwin2.value(set10) - end - end - canvas.invalidate - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - sliderwin1.dispose - sliderwin2.dispose -end - -def pbEntireSlide(canvas) - sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 7) - sliderwin2.viewport = canvas.viewport - sliderwin2.addSlider(_INTL("First Frame:"), 1, canvas.animation.length, 1) - sliderwin2.addSlider(_INTL("Last Frame:"), 1, canvas.animation.length, canvas.animation.length) - sliderwin2.addSlider(_INTL("X-Axis Movement"), -500, 500, 0) - sliderwin2.addSlider(_INTL("Y-Axis Movement"), -500, 500, 0) - okbutton = sliderwin2.addButton(_INTL("OK")) - cancelbutton = sliderwin2.addButton(_INTL("Cancel")) - sliderwin2.opacity = 200 - loop do - Graphics.update - Input.update - sliderwin2.update - if sliderwin2.changed?(okbutton) - startvalue = sliderwin2.value(0) - 1 - endvalue = sliderwin2.value(1) - 1 - xoffset = sliderwin2.value(2) - yoffset = sliderwin2.value(3) - (startvalue..endvalue).each do |i| - canvas.offsetFrame(i, xoffset, yoffset) - end - break - end - if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) - break - end - end - sliderwin2.dispose - return -end - -def pbAnimEditorHelpWindow - helptext = "" + - "To add a cel to the scene, click on the canvas. The selected cel will have a black " + - "frame. After a cel is selected, you can modify its properties using the keyboard:\n" + - "E, R - Rotate left/right.\nP - Open properties screen.\nArrow keys - Move cel 8 pixels " + - "(hold ALT for 2 pixels).\n+/- : Zoom in/out.\nL - Lock a cel. Locking a cel prevents it " + - "from being moved or deleted.\nDEL - Deletes the cel.\nAlso press TAB to switch the selected cel." - cmdwin = Window_UnformattedTextPokemon.newWithSize("", 0, 0, 640, 512) - cmdwin.opacity = 224 - cmdwin.z = 99999 - cmdwin.text = helptext - loop do - Graphics.update - Input.update - cmdwin.update - break if Input.trigger?(Input::BACK) || Input.trigger?(Input::USE) - end - cmdwin.dispose -end - -#=============================================================================== -# Main -#=============================================================================== -def animationEditorMain(animation) - viewport = Viewport.new(0, 0, Settings::SCREEN_WIDTH + 288, Settings::SCREEN_HEIGHT + 288) - viewport.z = 99999 - # Canvas - canvas = AnimationCanvas.new(animation[animation.selected] || animation[0], viewport) - # Right hand menu - sidewin = ControlWindow.new(512 + 128, 0, 160, 384 + 128) - sidewin.addButton(_INTL("SE and BG...")) - sidewin.addButton(_INTL("Cel Focus...")) - sidewin.addSpace - sidewin.addButton(_INTL("Paste Last")) - sidewin.addButton(_INTL("Copy Frames...")) - sidewin.addButton(_INTL("Clear Frames...")) - sidewin.addButton(_INTL("Tweening...")) - sidewin.addButton(_INTL("Cel Batch...")) - sidewin.addButton(_INTL("Entire Slide...")) - sidewin.addSpace - sidewin.addButton(_INTL("Play Animation")) - sidewin.addButton(_INTL("Play Opp Anim")) - sidewin.addButton(_INTL("Import Anim...")) - sidewin.addButton(_INTL("Export Anim...")) - sidewin.addButton(_INTL("Help")) - sidewin.viewport = canvas.viewport - # Bottom left menu - sliderwin = ControlWindow.new(0, 384 + 128, 240, 160) - sliderwin.addControl(FrameCountSlider.new(canvas)) - sliderwin.addControl(FrameCountButton.new(canvas)) - sliderwin.addButton(_INTL("Set Animation Sheet")) - sliderwin.addButton(_INTL("List of Animations")) - sliderwin.viewport = canvas.viewport - # Animation sheet window - animwin = CanvasAnimationWindow.new(canvas, 240, 384 + 128, 512, 96, canvas.viewport) - # Name window - bottomwindow = AnimationNameWindow.new(canvas, 240, 384 + 128 + 96, 512, 64, canvas.viewport) - loop do - Graphics.update - Input.update - sliderwin.update - canvas.update - sidewin.update - animwin.update - bottomwindow.update - canvas.pattern = animwin.selected if animwin.changed? - if Input.trigger?(Input::BACK) - if pbConfirmMessage(_INTL("Save changes?")) - save_data(animation, "Data/PkmnAnimations.rxdata") - end - if pbConfirmMessage(_INTL("Exit from the editor?")) - $game_temp.battle_animations_data = nil + break if maxsizewindow.changed?(9) # Cancel + if Input.trigger?(Input::USE) && animfiles.length > 0 + filename = (cmdwin.index == cmdErase) ? "" : cmdwin.commands[cmdwin.index] + maxsizewindow.controls[0].text = _INTL("File: \"{1}\"", filename) + elsif Input.trigger?(Input::BACK) break end end - if Input.triggerex?(:F5) - pbAnimEditorHelpWindow - next - elsif Input.trigger?(Input::MOUSERIGHT) && sliderwin.hittest?(0) # Right mouse button - commands = [ - _INTL("Copy Frame"), - _INTL("Paste Frame"), - _INTL("Clear Frame"), - _INTL("Insert Frame"), - _INTL("Delete Frame") - ] - hit = pbTrackPopupMenu(commands) - case hit - when 0 # Copy - if canvas.currentframe >= 0 - Clipboard.setData(canvas.animation[canvas.currentframe], "PBAnimFrame") + cmdwin.dispose + maxsizewindow.dispose + return ret + end + + def pbEditBG(canvas, timing) + ret = false + maxsizewindow = ControlWindow.new(0, 0, 320, 32 * 11) + maxsizewindow.addSlider(_INTL("Duration:"), 0, 50, timing.duration) + maxsizewindow.addOptionalSlider(_INTL("X:"), -500, 500, timing.bgX || 0) + maxsizewindow.addOptionalSlider(_INTL("Y:"), -500, 500, timing.bgY || 0) + maxsizewindow.addOptionalSlider(_INTL("Opacity:"), 0, 255, timing.opacity || 0) + maxsizewindow.addOptionalSlider(_INTL("Red:"), 0, 255, timing.colorRed || 0) + maxsizewindow.addOptionalSlider(_INTL("Green:"), 0, 255, timing.colorGreen || 0) + maxsizewindow.addOptionalSlider(_INTL("Blue:"), 0, 255, timing.colorBlue || 0) + maxsizewindow.addOptionalSlider(_INTL("Alpha:"), 0, 255, timing.colorAlpha || 0) + maxsizewindow.addButton(_INTL("OK")) + maxsizewindow.addButton(_INTL("Cancel")) + maxsizewindow.controls[1].checked = !timing.bgX.nil? + maxsizewindow.controls[2].checked = !timing.bgY.nil? + maxsizewindow.controls[3].checked = !timing.opacity.nil? + maxsizewindow.controls[4].checked = !timing.colorRed.nil? + maxsizewindow.controls[5].checked = !timing.colorGreen.nil? + maxsizewindow.controls[6].checked = !timing.colorBlue.nil? + maxsizewindow.controls[7].checked = !timing.colorAlpha.nil? + maxsizewindow.opacity = 200 + maxsizewindow.viewport = canvas.viewport + loop do + Graphics.update + Input.update + maxsizewindow.update + if maxsizewindow.changed?(8) # OK + if maxsizewindow.controls[1].checked || + maxsizewindow.controls[2].checked || + maxsizewindow.controls[3].checked || + maxsizewindow.controls[4].checked || + maxsizewindow.controls[5].checked || + maxsizewindow.controls[6].checked || + maxsizewindow.controls[7].checked + timing.duration = maxsizewindow.value(0) + timing.bgX = maxsizewindow.value(1) + timing.bgY = maxsizewindow.value(2) + timing.opacity = maxsizewindow.value(3) + timing.colorRed = maxsizewindow.value(4) + timing.colorGreen = maxsizewindow.value(5) + timing.colorBlue = maxsizewindow.value(6) + timing.colorAlpha = maxsizewindow.value(7) + ret = true end - when 1 # Paste - canvas.pasteFrame(canvas.currentframe) if canvas.currentframe >= 0 - when 2 # Clear Frame - canvas.clearFrame(canvas.currentframe) - when 3 # Insert Frame - canvas.insertFrame(canvas.currentframe) - sliderwin.invalidate - when 4 # Delete Frame - canvas.deleteFrame(canvas.currentframe) - sliderwin.controls[0].curvalue = canvas.currentframe + 1 - sliderwin.invalidate + break end - next - elsif Input.triggerex?(:Q) - if canvas.currentCel - pbDefinePath(canvas) - sliderwin.invalidate + break if maxsizewindow.changed?(9) # Cancel + if Input.trigger?(Input::BACK) + break end - next - elsif Input.trigger?(Input::MOUSERIGHT) # Right mouse button - mousepos = Mouse.getMousePos - mousepos = [0, 0] if !mousepos - commands = [ - _INTL("Properties..."), - _INTL("Cut"), - _INTL("Copy"), - _INTL("Paste"), - _INTL("Delete"), - _INTL("Renumber..."), - _INTL("Extrapolate Path...") - ] - hit = pbTrackPopupMenu(commands) - case hit - when 0 # Properties - if canvas.currentCel - pbCellProperties(canvas) - canvas.invalidateCel(canvas.currentcel) + end + maxsizewindow.dispose + return ret + end + + def pbCopyFrames(canvas) + sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 6) + sliderwin2.viewport = canvas.viewport + sliderwin2.addSlider(_INTL("First Frame:"), 1, canvas.animation.length, 1) + sliderwin2.addSlider(_INTL("Last Frame:"), 1, canvas.animation.length, canvas.animation.length) + sliderwin2.addSlider(_INTL("Copy to:"), 1, canvas.animation.length, canvas.currentframe + 1) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + sliderwin2.opacity = 200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + startvalue = sliderwin2.value(0) - 1 + endvalue = sliderwin2.value(1) - 1 + dstvalue = sliderwin2.value(2) - 1 + length = (endvalue - startvalue) + 1 + if length > 0 # Ensure correct overlap handling + if startvalue < dstvalue + startvalue += length + dstvalue += length + while length != 0 + canvas.copyFrame(startvalue - 1, dstvalue - 1) + startvalue -= 1 + dstvalue -= 1 + length -= 1 + end + elsif startvalue != dstvalue + while length != 0 + canvas.copyFrame(startvalue, dstvalue) + startvalue += 1 + dstvalue += 1 + length -= 1 + end + end end - when 1 # Cut - if canvas.currentCel - Clipboard.setData(canvas.currentCel, "PBAnimCel") - canvas.deleteCel(canvas.currentcel) + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + sliderwin2.dispose + return + end + + def pbClearFrames(canvas) + sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 5) + sliderwin2.viewport = canvas.viewport + sliderwin2.addSlider(_INTL("First Frame:"), 1, canvas.animation.length, 1) + sliderwin2.addSlider(_INTL("Last Frame:"), 1, canvas.animation.length, canvas.animation.length) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + sliderwin2.opacity = 200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + startframe = sliderwin2.value(0) - 1 + endframe = sliderwin2.value(1) - 1 + (startframe..endframe).each do |i| + canvas.clearFrame(i) end - when 2 # Copy - Clipboard.setData(canvas.currentCel, "PBAnimCel") if canvas.currentCel - when 3 # Paste - canvas.pasteCel(mousepos[0], mousepos[1]) - when 4 # Delete - canvas.deleteCel(canvas.currentcel) - when 5 # Renumber - if canvas.currentcel && canvas.currentcel >= 2 - cel1 = canvas.currentcel - cel2 = pbChooseNum(cel1) - canvas.swapCels(cel1, cel2) if cel2 >= 2 && cel1 != cel2 + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + sliderwin2.dispose + return + end + + def pbTweening(canvas) + sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 10) + sliderwin2.viewport = canvas.viewport + sliderwin2.opacity = 200 + s1set0 = sliderwin2.addSlider(_INTL("Starting Frame:"), 1, canvas.animation.length, 1) + s1set1 = sliderwin2.addSlider(_INTL("Ending Frame:"), 1, canvas.animation.length, canvas.animation.length) + s1set2 = sliderwin2.addSlider(_INTL("First Cel:"), 0, PBAnimation::MAX_SPRITES - 1, 0) + s1set3 = sliderwin2.addSlider(_INTL("Last Cel:"), 0, PBAnimation::MAX_SPRITES - 1, PBAnimation::MAX_SPRITES - 1) + set0 = sliderwin2.addCheckbox(_INTL("Pattern")) + set1 = sliderwin2.addCheckbox(_INTL("Position/Zoom/Angle")) + set2 = sliderwin2.addCheckbox(_INTL("Opacity/Blending")) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) || Input.trigger?(Input::USE) + startframe = sliderwin2.value(s1set0) - 1 + endframe = sliderwin2.value(s1set1) - 1 + break if startframe >= endframe + frames = endframe - startframe + startcel = sliderwin2.value(s1set2) + endcel = sliderwin2.value(s1set3) + (startcel..endcel).each do |j| + cel1 = canvas.animation[startframe][j] + cel2 = canvas.animation[endframe][j] + next if !cel1 || !cel2 + diffPattern = cel2[AnimFrame::PATTERN] - cel1[AnimFrame::PATTERN] + diffX = cel2[AnimFrame::X] - cel1[AnimFrame::X] + diffY = cel2[AnimFrame::Y] - cel1[AnimFrame::Y] + diffZoomX = cel2[AnimFrame::ZOOMX] - cel1[AnimFrame::ZOOMX] + diffZoomY = cel2[AnimFrame::ZOOMY] - cel1[AnimFrame::ZOOMY] + diffAngle = cel2[AnimFrame::ANGLE] - cel1[AnimFrame::ANGLE] + diffOpacity = cel2[AnimFrame::OPACITY] - cel1[AnimFrame::OPACITY] + diffBlend = cel2[AnimFrame::BLENDTYPE] - cel1[AnimFrame::BLENDTYPE] + startPattern = cel1[AnimFrame::PATTERN] + startX = cel1[AnimFrame::X] + startY = cel1[AnimFrame::Y] + startZoomX = cel1[AnimFrame::ZOOMX] + startZoomY = cel1[AnimFrame::ZOOMY] + startAngle = cel1[AnimFrame::ANGLE] + startOpacity = cel1[AnimFrame::OPACITY] + startBlend = cel1[AnimFrame::BLENDTYPE] + (0..frames).each do |k| + cel = canvas.animation[startframe + k][j] + curcel = cel + if !cel + cel = pbCreateCel(0, 0, 0) + canvas.animation[startframe + k][j] = cel + end + if sliderwin2.value(set0) || !curcel + cel[AnimFrame::PATTERN] = startPattern + (diffPattern * k / frames) + end + if sliderwin2.value(set1) || !curcel + cel[AnimFrame::X] = startX + (diffX * k / frames) + cel[AnimFrame::Y] = startY + (diffY * k / frames) + cel[AnimFrame::ZOOMX] = startZoomX + (diffZoomX * k / frames) + cel[AnimFrame::ZOOMY] = startZoomY + (diffZoomY * k / frames) + cel[AnimFrame::ANGLE] = startAngle + (diffAngle * k / frames) + end + if sliderwin2.value(set2) || !curcel + cel[AnimFrame::OPACITY] = startOpacity + (diffOpacity * k / frames) + cel[AnimFrame::BLENDTYPE] = startBlend + (diffBlend * k / frames) + end + end end - when 6 # Extrapolate Path + canvas.invalidate + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + sliderwin2.dispose + end + + def pbCellBatch(canvas) + sliderwin1 = ControlWindow.new(0, 0, 300, 32 * 5) + sliderwin1.viewport = canvas.viewport + sliderwin1.opacity = 200 + s1set0 = sliderwin1.addSlider(_INTL("First Frame:"), 1, canvas.animation.length, 1) + s1set1 = sliderwin1.addSlider(_INTL("Last Frame:"), 1, canvas.animation.length, canvas.animation.length) + s1set2 = sliderwin1.addSlider(_INTL("First Cel:"), 0, PBAnimation::MAX_SPRITES - 1, 0) + s1set3 = sliderwin1.addSlider(_INTL("Last Cel:"), 0, PBAnimation::MAX_SPRITES - 1, PBAnimation::MAX_SPRITES - 1) + sliderwin2 = ControlWindow.new(300, 0, 340, 32 * 14) + sliderwin2.viewport = canvas.viewport + sliderwin2.opacity = 200 + set0 = sliderwin2.addOptionalSlider(_INTL("Pattern:"), -2, 1000, 0) + set1 = sliderwin2.addOptionalSlider(_INTL("X:"), -64, 512 + 64, 0) + set2 = sliderwin2.addOptionalSlider(_INTL("Y:"), -64, 384 + 64, 0) + set3 = sliderwin2.addOptionalSlider(_INTL("Zoom X:"), 5, 1000, 100) + set4 = sliderwin2.addOptionalSlider(_INTL("Zoom Y:"), 5, 1000, 100) + set5 = sliderwin2.addOptionalSlider(_INTL("Angle:"), 0, 359, 0) + set6 = sliderwin2.addOptionalSlider(_INTL("Opacity:"), 0, 255, 255) + set7 = sliderwin2.addOptionalSlider(_INTL("Blending:"), 0, 2, 0) + set8 = sliderwin2.addOptionalTextSlider(_INTL("Flip:"), [_INTL("False"), _INTL("True")], 0) + prio = [_INTL("Back"), _INTL("Front"), _INTL("Behind focus"), _INTL("Above focus")] + set9 = sliderwin2.addOptionalTextSlider(_INTL("Priority:"), prio, 1) + foc = [_INTL("User"), _INTL("Target"), _INTL("User and target"), _INTL("Screen")] + curfoc = [3, 1, 0, 2, 3][canvas.animation.position || 4] + set10 = sliderwin2.addOptionalTextSlider(_INTL("Focus:"), foc, curfoc) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + loop do + Graphics.update + Input.update + sliderwin1.update + sliderwin2.update + if sliderwin2.changed?(okbutton) || Input.trigger?(Input::USE) + startframe = sliderwin1.value(s1set0) - 1 + endframe = sliderwin1.value(s1set1) - 1 + startcel = sliderwin1.value(s1set2) + endcel = sliderwin1.value(s1set3) + (startframe..endframe).each do |i| + (startcel..endcel).each do |j| + next if !canvas.animation[i][j] + cel = canvas.animation[i][j] + cel[AnimFrame::PATTERN] = sliderwin2.value(set0) if sliderwin2.value(set0) + cel[AnimFrame::X] = sliderwin2.value(set1) if sliderwin2.value(set1) + cel[AnimFrame::Y] = sliderwin2.value(set2) if sliderwin2.value(set2) + cel[AnimFrame::ZOOMX] = sliderwin2.value(set3) if sliderwin2.value(set3) + cel[AnimFrame::ZOOMY] = sliderwin2.value(set4) if sliderwin2.value(set4) + cel[AnimFrame::ANGLE] = sliderwin2.value(set5) if sliderwin2.value(set5) + cel[AnimFrame::OPACITY] = sliderwin2.value(set6) if sliderwin2.value(set6) + cel[AnimFrame::BLENDTYPE] = sliderwin2.value(set7) if sliderwin2.value(set7) + cel[AnimFrame::MIRROR] = sliderwin2.value(set8) if sliderwin2.value(set8) + cel[AnimFrame::PRIORITY] = sliderwin2.value(set9) if sliderwin2.value(set9) + cel[AnimFrame::FOCUS] = [2, 1, 3, 4][sliderwin2.value(set10)] if sliderwin2.value(set10) + end + end + canvas.invalidate + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + sliderwin1.dispose + sliderwin2.dispose + end + + def pbEntireSlide(canvas) + sliderwin2 = ControlWindow.new(0, 0, 320, 32 * 7) + sliderwin2.viewport = canvas.viewport + sliderwin2.addSlider(_INTL("First Frame:"), 1, canvas.animation.length, 1) + sliderwin2.addSlider(_INTL("Last Frame:"), 1, canvas.animation.length, canvas.animation.length) + sliderwin2.addSlider(_INTL("X-Axis Movement"), -500, 500, 0) + sliderwin2.addSlider(_INTL("Y-Axis Movement"), -500, 500, 0) + okbutton = sliderwin2.addButton(_INTL("OK")) + cancelbutton = sliderwin2.addButton(_INTL("Cancel")) + sliderwin2.opacity = 200 + loop do + Graphics.update + Input.update + sliderwin2.update + if sliderwin2.changed?(okbutton) + startvalue = sliderwin2.value(0) - 1 + endvalue = sliderwin2.value(1) - 1 + xoffset = sliderwin2.value(2) + yoffset = sliderwin2.value(3) + (startvalue..endvalue).each do |i| + canvas.offsetFrame(i, xoffset, yoffset) + end + break + end + if sliderwin2.changed?(cancelbutton) || Input.trigger?(Input::BACK) + break + end + end + sliderwin2.dispose + return + end + + def pbAnimEditorHelpWindow + helptext = "" + + "To add a cel to the scene, click on the canvas. The selected cel will have a black " + + "frame. After a cel is selected, you can modify its properties using the keyboard:\n" + + "E, R - Rotate left/right.\nP - Open properties screen.\nArrow keys - Move cel 8 pixels " + + "(hold ALT for 2 pixels).\n+/- : Zoom in/out.\nL - Lock a cel. Locking a cel prevents it " + + "from being moved or deleted.\nDEL - Deletes the cel.\nAlso press TAB to switch the selected cel." + cmdwin = Window_UnformattedTextPokemon.newWithSize("", 0, 0, 640, 512) + cmdwin.opacity = 224 + cmdwin.z = 99999 + cmdwin.text = helptext + loop do + Graphics.update + Input.update + cmdwin.update + break if Input.trigger?(Input::BACK) || Input.trigger?(Input::USE) + end + cmdwin.dispose + end + + #============================================================================= + # Main + #============================================================================= + def animationEditorMain(animation) + echoln animation.selected + viewport = Viewport.new(0, 0, Settings::SCREEN_WIDTH + 288, Settings::SCREEN_HEIGHT + 288) + viewport.z = 99999 + # Canvas + canvas = AnimationCanvas.new(animation[animation.selected] || animation[0], viewport) + # Right hand menu + sidewin = ControlWindow.new(512 + 128, 0, 160, 384 + 128) + sidewin.addButton(_INTL("SE and BG...")) + sidewin.addButton(_INTL("Cel Focus...")) + sidewin.addSpace + sidewin.addButton(_INTL("Paste Last")) + sidewin.addButton(_INTL("Copy Frames...")) + sidewin.addButton(_INTL("Clear Frames...")) + sidewin.addButton(_INTL("Tweening...")) + sidewin.addButton(_INTL("Cel Batch...")) + sidewin.addButton(_INTL("Entire Slide...")) + sidewin.addSpace + sidewin.addButton(_INTL("Play Animation")) + sidewin.addButton(_INTL("Play Opp Anim")) + sidewin.addButton(_INTL("Import Anim...")) + sidewin.addButton(_INTL("Export Anim...")) + sidewin.addButton(_INTL("Help")) + sidewin.viewport = canvas.viewport + # Bottom left menu + sliderwin = ControlWindow.new(0, 384 + 128, 240, 160) + sliderwin.addControl(FrameCountSlider.new(canvas)) + sliderwin.addControl(FrameCountButton.new(canvas)) + sliderwin.addButton(_INTL("Set Animation Sheet")) + sliderwin.addButton(_INTL("List of Animations")) + sliderwin.viewport = canvas.viewport + # Animation sheet window + animwin = CanvasAnimationWindow.new(canvas, 240, 384 + 128, 512, 96, canvas.viewport) + # Name window + bottomwindow = AnimationNameWindow.new(canvas, 240, 384 + 128 + 96, 512, 64, canvas.viewport) + loop do + Graphics.update + Input.update + sliderwin.update + canvas.update + sidewin.update + animwin.update + bottomwindow.update + canvas.pattern = animwin.selected if animwin.changed? + if Input.trigger?(Input::BACK) + if pbConfirmMessage(_INTL("Save changes?")) + save_data(animation, "Data/PkmnAnimations.rxdata") + end + if pbConfirmMessage(_INTL("Exit from the editor?")) + $game_temp.battle_animations_data = nil + break + end + end + if Input.triggerex?(:F5) + pbAnimEditorHelpWindow + next + elsif Input.trigger?(Input::MOUSERIGHT) && sliderwin.hittest?(0) # Right mouse button + commands = [ + _INTL("Copy Frame"), + _INTL("Paste Frame"), + _INTL("Clear Frame"), + _INTL("Insert Frame"), + _INTL("Delete Frame") + ] + hit = pbTrackPopupMenu(commands) + case hit + when 0 # Copy + if canvas.currentframe >= 0 + Clipboard.setData(canvas.animation[canvas.currentframe], "PBAnimFrame") + end + when 1 # Paste + canvas.pasteFrame(canvas.currentframe) if canvas.currentframe >= 0 + when 2 # Clear Frame + canvas.clearFrame(canvas.currentframe) + when 3 # Insert Frame + canvas.insertFrame(canvas.currentframe) + sliderwin.invalidate + when 4 # Delete Frame + canvas.deleteFrame(canvas.currentframe) + sliderwin.controls[0].curvalue = canvas.currentframe + 1 + sliderwin.invalidate + end + next + elsif Input.triggerex?(:Q) if canvas.currentCel pbDefinePath(canvas) sliderwin.invalidate end + next + elsif Input.trigger?(Input::MOUSERIGHT) # Right mouse button + mousepos = Mouse.getMousePos + mousepos = [0, 0] if !mousepos + commands = [ + _INTL("Properties..."), + _INTL("Cut"), + _INTL("Copy"), + _INTL("Paste"), + _INTL("Delete"), + _INTL("Renumber..."), + _INTL("Extrapolate Path...") + ] + hit = pbTrackPopupMenu(commands) + case hit + when 0 # Properties + if canvas.currentCel + pbCellProperties(canvas) + canvas.invalidateCel(canvas.currentcel) + end + when 1 # Cut + if canvas.currentCel + Clipboard.setData(canvas.currentCel, "PBAnimCel") + canvas.deleteCel(canvas.currentcel) + end + when 2 # Copy + Clipboard.setData(canvas.currentCel, "PBAnimCel") if canvas.currentCel + when 3 # Paste + canvas.pasteCel(mousepos[0], mousepos[1]) + when 4 # Delete + canvas.deleteCel(canvas.currentcel) + when 5 # Renumber + if canvas.currentcel && canvas.currentcel >= 2 + cel1 = canvas.currentcel + cel2 = pbChooseNum(cel1) + canvas.swapCels(cel1, cel2) if cel2 >= 2 && cel1 != cel2 + end + when 6 # Extrapolate Path + if canvas.currentCel + pbDefinePath(canvas) + sliderwin.invalidate + end + end + next end - next - end - if sliderwin.changed?(0) # Current frame changed - canvas.currentframe = sliderwin.value(0) - 1 - end - if sliderwin.changed?(1) # Change frame count - pbChangeMaximum(canvas) - if canvas.currentframe >= canvas.animation.length - canvas.currentframe = canvas.animation.length - 1 + if sliderwin.changed?(0) # Current frame changed + canvas.currentframe = sliderwin.value(0) - 1 + end + if sliderwin.changed?(1) # Change frame count + pbChangeMaximum(canvas) + if canvas.currentframe >= canvas.animation.length + canvas.currentframe = canvas.animation.length - 1 + sliderwin.controls[0].curvalue = canvas.currentframe + 1 + end + sliderwin.refresh + end + if sliderwin.changed?(2) # Set Animation Sheet + pbSelectAnim(canvas, animwin) + animwin.refresh + sliderwin.refresh + end + if sliderwin.changed?(3) # List of Animations + pbAnimList(animation, canvas, animwin) sliderwin.controls[0].curvalue = canvas.currentframe + 1 + bottomwindow.refresh + animwin.refresh + sliderwin.refresh end - sliderwin.refresh - end - if sliderwin.changed?(2) # Set Animation Sheet - pbSelectAnim(canvas, animwin) - animwin.refresh - sliderwin.refresh - end - if sliderwin.changed?(3) # List of Animations - pbAnimList(animation, canvas, animwin) - sliderwin.controls[0].curvalue = canvas.currentframe + 1 - bottomwindow.refresh - animwin.refresh - sliderwin.refresh - end - pbTimingList(canvas) if sidewin.changed?(0) - if sidewin.changed?(1) - positions = [_INTL("User"), _INTL("Target"), _INTL("User and target"), _INTL("Screen")] - indexes = [2, 1, 3, 4] # Keeping backwards compatibility - positions.length.times do |i| - selected = "[ ]" - selected = "[x]" if animation[animation.selected].position == indexes[i] - positions[i] = sprintf("%s %s", selected, positions[i]) + pbTimingList(canvas) if sidewin.changed?(0) + if sidewin.changed?(1) + positions = [_INTL("User"), _INTL("Target"), _INTL("User and target"), _INTL("Screen")] + indexes = [2, 1, 3, 4] # Keeping backwards compatibility + positions.length.times do |i| + selected = "[ ]" + selected = "[X]" if animation[animation.selected].position == indexes[i] + positions[i] = sprintf("%s %s", selected, positions[i]) + end + pos = pbShowCommands(nil, positions, -1) + if pos >= 0 + animation[animation.selected].position = indexes[pos] + canvas.update + end end - pos = pbShowCommands(nil, positions, -1) - if pos >= 0 - animation[animation.selected].position = indexes[pos] - canvas.update + canvas.pasteLast if sidewin.changed?(3) + pbCopyFrames(canvas) if sidewin.changed?(4) + pbClearFrames(canvas) if sidewin.changed?(5) + pbTweening(canvas) if sidewin.changed?(6) + pbCellBatch(canvas) if sidewin.changed?(7) + pbEntireSlide(canvas) if sidewin.changed?(8) + canvas.play if sidewin.changed?(10) + canvas.play(true) if sidewin.changed?(11) + if sidewin.changed?(12) + pbImportAnim(animation, canvas, animwin) + sliderwin.controls[0].curvalue = canvas.currentframe + 1 + bottomwindow.refresh + animwin.refresh + sliderwin.refresh end + if sidewin.changed?(13) + pbExportAnim(animation) + bottomwindow.refresh + animwin.refresh + sliderwin.refresh + end + pbAnimEditorHelpWindow if sidewin.changed?(14) end - canvas.pasteLast if sidewin.changed?(3) - pbCopyFrames(canvas) if sidewin.changed?(4) - pbClearFrames(canvas) if sidewin.changed?(5) - pbTweening(canvas) if sidewin.changed?(6) - pbCellBatch(canvas) if sidewin.changed?(7) - pbEntireSlide(canvas) if sidewin.changed?(8) - canvas.play if sidewin.changed?(10) - canvas.play(true) if sidewin.changed?(11) - if sidewin.changed?(12) - pbImportAnim(animation, canvas, animwin) - sliderwin.controls[0].curvalue = canvas.currentframe + 1 - bottomwindow.refresh - animwin.refresh - sliderwin.refresh - end - if sidewin.changed?(13) - pbExportAnim(animation) - bottomwindow.refresh - animwin.refresh - sliderwin.refresh - end - pbAnimEditorHelpWindow if sidewin.changed?(14) + canvas.dispose + animwin.dispose + sliderwin.dispose + sidewin.dispose + bottomwindow.dispose + viewport.dispose + RPG::Cache.clear end - canvas.dispose - animwin.dispose - sliderwin.dispose - sidewin.dispose - bottomwindow.dispose - viewport.dispose - RPG::Cache.clear end #=============================================================================== @@ -1162,7 +1166,7 @@ def pbAnimationEditor end Graphics.resize_screen(Settings::SCREEN_WIDTH + 288, Settings::SCREEN_HEIGHT + 288) pbSetResizeFactor(1) - animationEditorMain(animation) + BattleAnimationEditor.animationEditorMain(animation) Graphics.resize_screen(Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT) pbSetResizeFactor($PokemonSystem.screensize) $game_map&.autoplay diff --git a/Data/Scripts/020_Debug/003_Debug menus/003_Debug_MenuExtraCode.rb b/Data/Scripts/020_Debug/003_Debug menus/003_Debug_MenuExtraCode.rb index 1531c21d0..90fe84f9b 100644 --- a/Data/Scripts/020_Debug/003_Debug menus/003_Debug_MenuExtraCode.rb +++ b/Data/Scripts/020_Debug/003_Debug menus/003_Debug_MenuExtraCode.rb @@ -558,7 +558,7 @@ def pbExportAllAnimations safename = anim.name.gsub(/\W/, "_") Dir.mkdir("Animations/#{safename}") rescue nil File.open("Animations/#{safename}/#{safename}.anm", "wb") do |f| - f.write(dumpBase64Anim(anim)) + f.write(BattleAnimationEditor.dumpBase64Anim(anim)) end if anim.graphic && anim.graphic != "" graphicname = RTP.getImagePath("Graphics/Animations/" + anim.graphic) @@ -626,13 +626,13 @@ def pbImportAllAnimations pbSafeCopyFile(image, RTP.getImagePath("Graphics/Animations/" + File.basename(image)), "Graphics/Animations/" + File.basename(image)) end Dir.glob(folder + "/*.anm") do |f| - textdata = loadBase64Anim(IO.read(f)) rescue nil + textdata = BattleAnimationEditor.loadBase64Anim(IO.read(f)) rescue nil if textdata.is_a?(PBAnimation) index = pbAllocateAnimation(animations, textdata.name) missingFiles = [] textdata.name = File.basename(folder) if textdata.name == "" textdata.id = -1 # This is not an RPG Maker XP animation - pbConvertAnimToNewFormat(textdata) + BattleAnimationEditor.pbConvertAnimToNewFormat(textdata) if textdata.graphic && textdata.graphic != "" && !safeExists?(folder + "/" + textdata.graphic) && !FileTest.image_exist?("Graphics/Animations/" + textdata.graphic)