diff --git a/Data/Scripts/007_Objects and windows/005_SpriteWindow_text.rb b/Data/Scripts/007_Objects and windows/005_SpriteWindow_text.rb index 544f746f8..f1d201e76 100644 --- a/Data/Scripts/007_Objects and windows/005_SpriteWindow_text.rb +++ b/Data/Scripts/007_Objects and windows/005_SpriteWindow_text.rb @@ -231,7 +231,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base dims = [0, 0] cwidth = (maxwidth < 0) ? Graphics.width : maxwidth chars = getFormattedTextForDims(self.contents, 0, 0, - cwidth - self.borderX - 2 - 6, -1, text, @lineHeight, true) + cwidth - self.borderX - SpriteWindow_Base::TEXT_PADDING, -1, text, @lineHeight, true) chars.each do |ch| dims[0] = [dims[0], ch[1] + ch[3]].max dims[1] = [dims[1], ch[2] + ch[4]].max @@ -244,7 +244,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base oldstarting = @starting @starting = true self.width = (width < 0) ? Graphics.width : width - self.height = dims[1] + self.borderY + self.height = dims[1] + self.borderY + 2 # TEXT OFFSET @starting = oldstarting redrawText end @@ -953,7 +953,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base new_top_row = [[new_top_row, self.row_max - self.page_row_max].min, 0].max if self.top_row != new_top_row self.top_row = new_top_row -# dorefresh = true + dorefresh = true end # End of code cursor_width = (self.width - self.borderX) / @column_max diff --git a/Data/Scripts/007_Objects and windows/010_DrawText.rb b/Data/Scripts/007_Objects and windows/010_DrawText.rb index a18f98a33..d4a5dc569 100644 --- a/Data/Scripts/007_Objects and windows/010_DrawText.rb +++ b/Data/Scripts/007_Objects and windows/010_DrawText.rb @@ -147,7 +147,7 @@ def getFormattedTextFast(bitmap, xDst, yDst, widthDst, heightDst, text, lineheig elsif isspace hadspace = true end - texty = (lineheight * y) + yDst + yStart + texty = (lineheight * y) + yDst + yStart - 2 # TEXT OFFSET # Push character if heightDst < 0 || yStart < yDst + heightDst havenl = true if isWaitChar(textchars[position]) diff --git a/Data/Scripts/014_Pokemon/001_Pokemon-related/003_Pokemon_Sprites.rb b/Data/Scripts/014_Pokemon/001_Pokemon-related/003_Pokemon_Sprites.rb index 12da4a054..acfe24fb6 100644 --- a/Data/Scripts/014_Pokemon/001_Pokemon-related/003_Pokemon_Sprites.rb +++ b/Data/Scripts/014_Pokemon/001_Pokemon-related/003_Pokemon_Sprites.rb @@ -123,6 +123,21 @@ class PokemonIconSprite < Sprite def pokemon=(value) @pokemon = value + # Check if the bitmap needs to be reloaded + new_values = nil + if @pokemon + new_values = { + :species => @pokemon.species, + :form => @pokemon.form, + :gender => @pokemon.gender, + :shiny => @pokemon.shiny?, + :shadow => @pokemon.shadowPokemon?, + :egg => @pokemon.egg? + } + end + return if @pokemon_values == new_values + @pokemon_values = new_values + # Reload the bitmap @animBitmap&.dispose @animBitmap = nil if !@pokemon diff --git a/Data/Scripts/014_Pokemon/001_Pokemon-related/004_PokemonStorage.rb b/Data/Scripts/014_Pokemon/001_Pokemon-related/004_PokemonStorage.rb index 2e8271da7..3c5e03df9 100644 --- a/Data/Scripts/014_Pokemon/001_Pokemon-related/004_PokemonStorage.rb +++ b/Data/Scripts/014_Pokemon/001_Pokemon-related/004_PokemonStorage.rb @@ -60,13 +60,13 @@ class PokemonStorage attr_accessor :currentBox attr_writer :unlockedWallpapers - BASICWALLPAPERQTY = 16 + BASIC_WALLPAPER_COUNT = 16 def initialize(maxBoxes = Settings::NUM_STORAGE_BOXES, maxPokemon = PokemonBox::BOX_SIZE) @boxes = [] maxBoxes.times do |i| @boxes[i] = PokemonBox.new(_INTL("Box {1}", i + 1), maxPokemon) - @boxes[i].background = i % BASICWALLPAPERQTY + @boxes[i].background = i % BASIC_WALLPAPER_COUNT end @currentBox = 0 @boxmode = -1 @@ -76,6 +76,11 @@ class PokemonStorage end end + # NOTE: These wallpaper names are shown in a list in the storage screen that + # is a fixed width. The names should be kept relatively short; longer + # names will get shrunk to fit the width of the list, and that looks bad. + # NOTE: The order these wallpapers are listed determines the number in their + # filenames. def allWallpapers return [ # Basic wallpapers @@ -85,9 +90,9 @@ class PokemonStorage _INTL("Poké Center"), _INTL("Machine"), _INTL("Checks"), _INTL("Simple"), # Special wallpapers _INTL("Space"), _INTL("Backyard"), _INTL("Nostalgic 1"), _INTL("Torchic"), - _INTL("Trio 1"), _INTL("PikaPika 1"), _INTL("Legend 1"), _INTL("Team Galactic 1"), + _INTL("Trio 1"), _INTL("PikaPika 1"), _INTL("Legend 1"), _INTL("Galactic 1"), _INTL("Distortion"), _INTL("Contest"), _INTL("Nostalgic 2"), _INTL("Croagunk"), - _INTL("Trio 2"), _INTL("PikaPika 2"), _INTL("Legend 2"), _INTL("Team Galactic 2"), + _INTL("Trio 2"), _INTL("PikaPika 2"), _INTL("Legend 2"), _INTL("Galactic 2"), _INTL("Heart"), _INTL("Soul"), _INTL("Big Brother"), _INTL("Pokéathlon"), _INTL("Trio 3"), _INTL("Spiky Pika"), _INTL("Kimono Girl"), _INTL("Revival") ] @@ -100,25 +105,22 @@ class PokemonStorage def isAvailableWallpaper?(i) @unlockedWallpapers = [] if !@unlockedWallpapers - return true if i < BASICWALLPAPERQTY + return true if i < BASIC_WALLPAPER_COUNT return true if @unlockedWallpapers[i] return false end def availableWallpapers - ret = [[], []] # Names, IDs - papers = allWallpapers @unlockedWallpapers = [] if !@unlockedWallpapers - papers.length.times do |i| - next if !isAvailableWallpaper?(i) - ret[0].push(papers[i]) - ret[1].push(i) + ret = {} + allWallpapers.each_with_index do |paper, i| + ret[i] = paper if isAvailableWallpaper?(i) end return ret end def party - $player.party + return $player.party end def party=(_value) diff --git a/Data/Scripts/016_UI/023_UI_PurifyChamber.rb b/Data/Scripts/016_UI/023_UI_PurifyChamber.rb index f6c2acd5a..fcff5894d 100644 --- a/Data/Scripts/016_UI/023_UI_PurifyChamber.rb +++ b/Data/Scripts/016_UI/023_UI_PurifyChamber.rb @@ -1267,13 +1267,19 @@ class PurifyChamberScene pbRefresh end + # TODO: Depending on which position is selected, make Shadow Pokémon/non-Shadow + # Pokémon in UI::PokemonStorage semi-transparent and don't let them be + # selected. + # TODO: Don't let eggs be selected. + # TODO: Don't let the last able Pokémon in the party be selected. def pbChoosePokemon - visible = pbFadeOutAndHide(@sprites) - scene = PokemonStorageScene.new - screen = PokemonStorageScreen.new(scene, $PokemonStorage) - pos = screen.pbChoosePokemon - pbRefresh - pbFadeInAndShow(@sprites, visible) + pos = nil + pbFadeOutInWithUpdate(@sprites) do + screen = UI::PokemonStorage.new($PokemonStorage, mode: :choose_pokemon) + screen.main + pos = screen.result + pbRefresh + end return pos end end diff --git a/Data/Scripts/016_UI/025_UI_TextEntry.rb b/Data/Scripts/016_UI/025_UI_TextEntry.rb index 88e615097..6bf05e597 100644 --- a/Data/Scripts/016_UI/025_UI_TextEntry.rb +++ b/Data/Scripts/016_UI/025_UI_TextEntry.rb @@ -779,6 +779,8 @@ def pbEnterNPCName(helptext, minlength, maxlength, initialText = "", id = 0, nof return pbEnterText(helptext, minlength, maxlength, initialText, 3, id, nofadeout) end +# TODO: maxlength for this is 16, so the entry screen should support showing 16 +# characters. def pbEnterBoxName(helptext, minlength, maxlength, initialText = "", nofadeout = false) return pbEnterText(helptext, minlength, maxlength, initialText, 4, nil, nofadeout) end diff --git a/Data/Scripts/016b_UI redesign/000_UI_base.rb b/Data/Scripts/016b_UI redesign/000_UI_base.rb index 302c43894..e53458357 100644 --- a/Data/Scripts/016b_UI redesign/000_UI_base.rb +++ b/Data/Scripts/016b_UI redesign/000_UI_base.rb @@ -340,6 +340,7 @@ module UI end def initialize_message_box + # TODO: It looks like :message_box isn't used anywhere. @sprites[:message_box] = Window_AdvancedTextPokemon.new("") @sprites[:message_box].viewport = @viewport @sprites[:message_box].z = 2000 @@ -385,10 +386,14 @@ module UI #--------------------------------------------------------------------------- + def position_speech_box(text = "") + pbBottomLeftLines(@sprites[:speech_box], 2) + end + def show_message(text) @sprites[:speech_box].visible = true @sprites[:speech_box].text = text - pbBottomLeftLines(@sprites[:speech_box], 2) + position_speech_box(text) yielded = false loop do Graphics.update @@ -414,7 +419,7 @@ module UI ret = false @sprites[:speech_box].visible = true @sprites[:speech_box].text = text - pbBottomLeftLines(@sprites[:speech_box], 2) + position_speech_box(text) using(cmd_window = Window_CommandPokemon.new([_INTL("Yes"), _INTL("No")])) do cmd_window.z = @viewport.z + 1 cmd_window.visible = false @@ -444,6 +449,40 @@ module UI return ret end + def show_confirm_serious_message(text) + ret = false + @sprites[:speech_box].visible = true + @sprites[:speech_box].text = text + position_speech_box(text) + using(cmd_window = Window_CommandPokemon.new([_INTL("No"), _INTL("Yes")])) do + cmd_window.z = @viewport.z + 1 + cmd_window.visible = false + pbBottomRight(cmd_window) + cmd_window.y -= @sprites[:speech_box].height + cmd_window.visible = true if !@sprites[:speech_box].busy? + loop do + Graphics.update + Input.update + update_visuals + cmd_window.visible = true if !@sprites[:speech_box].busy? + cmd_window.update + if !@sprites[:speech_box].busy? + if Input.trigger?(Input::BACK) + pbPlayCancelSE + ret = false + break + elsif Input.trigger?(Input::USE) && @sprites[:speech_box].resume + pbPlayDecisionSE + ret = (cmd_window.index == 1) + break + end + end + end + end + @sprites[:speech_box].visible = false + return ret + end + # Used for dialogue. # align: Where the command window is in relation to the message window. # :horizontal is side by side, :vertical is command window above. @@ -547,7 +586,7 @@ module UI def choose_number_as_money_multiplier(help_text, money_per_unit, maximum, init_value = 1) @sprites[:speech_box].visible = true @sprites[:speech_box].text = help_text - pbBottomLeftLines(@sprites[:speech_box], 2) + position_speech_box(text) # Show the help text loop do Graphics.update @@ -701,6 +740,10 @@ module UI alias pbConfirm show_confirm_message + def show_confirm_serious_message(text) + return @visuals.show_confirm_serious_message(text) + end + def show_choice_message(text, options, initial_index = 0) return @visuals.show_choice_message(text, options, initial_index) end diff --git a/Data/Scripts/016b_UI redesign/005_UI_Party.rb b/Data/Scripts/016b_UI redesign/005_UI_Party.rb index 9c7963905..49074c291 100644 --- a/Data/Scripts/016b_UI redesign/005_UI_Party.rb +++ b/Data/Scripts/016b_UI redesign/005_UI_Party.rb @@ -766,10 +766,6 @@ class UI::Party < UI::BaseScreen #----------------------------------------------------------------------------- - def set_index(new_index) - @visuals.set_index(new_index) - end - def pokemon return (index < @party.length) ? @party[index] : nil end @@ -778,6 +774,10 @@ class UI::Party < UI::BaseScreen return @visuals.can_access_storage? end + def set_index(new_index) + @visuals.set_index(new_index) + end + def set_help_text(text) @visuals.set_help_text(text) end @@ -1306,9 +1306,7 @@ UIActionHandlers.add(UI::Party::SCREEN_ID, :clear_sub_mode, { UIActionHandlers.add(UI::Party::SCREEN_ID, :open_storage, { :effect => proc { |screen| pbFadeOutInWithUpdate(screen.sprites) do - storage_scene = PokemonStorageScene.new - storage_screen = PokemonStorageScreen.new(storage_scene, $PokemonStorage) - storage_screen.pbStartScreen(0) + UI::PokemonStorage.new($PokemonStorage, mode: :organize).main screen.refresh_party screen.refresh end diff --git a/Data/Scripts/016b_UI redesign/006_UI_Summary.rb b/Data/Scripts/016b_UI redesign/006_UI_Summary.rb index 283283545..4fcbe35ce 100644 --- a/Data/Scripts/016b_UI redesign/006_UI_Summary.rb +++ b/Data/Scripts/016b_UI redesign/006_UI_Summary.rb @@ -181,6 +181,7 @@ class UI::PokemonSummaryVisuals < UI::BaseVisuals :draw_page_icons, :draw_poke_ball, :draw_pokemon_name, + :draw_party_icons, :draw_markings, :draw_egg_memo ] diff --git a/Data/Scripts/016b_UI redesign/017_UI_PokemonStorage.rb b/Data/Scripts/016b_UI redesign/017_UI_PokemonStorage.rb new file mode 100644 index 000000000..e862f932c --- /dev/null +++ b/Data/Scripts/016b_UI redesign/017_UI_PokemonStorage.rb @@ -0,0 +1,2274 @@ +#=============================================================================== +# +#=============================================================================== +class UI::PokemonStorageVisualsSidePane < UI::SpriteContainer + attr_reader :pokemon + + GRAPHICS_FOLDER = "Storage/" + TEXT_COLOR_THEMES = { # These color themes are added to @sprites[:overlay] + :default => [Color.new(88, 88, 80), Color.new(168, 184, 184)], # Base and shadow colour + :no_item => [Color.new(192, 200, 208), Color.new(212, 216, 220)], + :male => [Color.new(24, 112, 216), Color.new(136, 168, 208)], + :female => [Color.new(248, 56, 32), Color.new(224, 152, 144)] + } + MARK_WIDTH = 16 + MARK_HEIGHT = 16 + + def initialize_bitmaps + @bitmaps[:types] = AnimatedBitmap.new(UI_FOLDER + _INTL("types")) + @bitmaps[:markings] = AnimatedBitmap.new(graphics_folder + "markings") + @bitmaps[:numbers] = AnimatedBitmap.new(graphics_folder + "numbers") + end + + def initialize_sprites + initialize_pane_bg + initialize_overlay + initialize_pokemon_sprite + end + + def initialize_pane_bg + add_icon_sprite(:pane_bg, 0, 0, graphics_folder + "overlay_side_pane") + record_values(:pane_bg) + end + + def initialize_overlay + add_overlay(:overlay, @sprites[:pane_bg].bitmap.width, @sprites[:pane_bg].bitmap.height) + @sprites[:overlay].z = 10 + record_values(:overlay) + end + + def initialize_pokemon_sprite + # TODO: The Pokémon sprite probably needs its own viewport, to avoid + # spillover of overly large sprites. Also put it beneath the main + # background sprite and put another sprite beneath it? + @sprites[:pokemon] = UI::PokemonStorageVisualsMosaicPokemonSprite.new(@viewport) + @sprites[:pokemon].setOffset(PictureOrigin::CENTER) + @sprites[:pokemon].x = 90 + @sprites[:pokemon].y = 164 + @sprites[:pokemon].z = 1 + record_values(:pokemon) + mosaic_pokemon_sprite + end + + #----------------------------------------------------------------------------- + + def width + return @sprites[:pane_bg].width + end + + def pokemon=(value) + @pokemon = value + @sprites[:pokemon].setPokemonBitmap(@pokemon) if @sprites[:pokemon] && !@sprites[:pokemon].disposed? + refresh + end + + def mosaic_pokemon_sprite + @sprites[:pokemon].mosaic_duration = 0.25 # In seconds + end + + #----------------------------------------------------------------------------- + + def refresh_overlay + super + return if @pokemon.nil? + draw_name + draw_level + draw_shiny_icon + draw_gender + draw_markings + draw_type + draw_item + end + + def draw_name + pokemon_name = @pokemon.name + pokemon_name = crop_text(pokemon_name, 158) + draw_text(pokemon_name, 8, 14) + end + + def draw_level + return if @pokemon.egg? + draw_image(graphics_folder + _INTL("overlay_lv"), 8, 48) + draw_number_from_image(@bitmaps[:numbers], @pokemon.level, 30, 48) + end + + def draw_shiny_icon + return if @pokemon.egg? + draw_image(UI_FOLDER + "shiny", 106, 46) if @pokemon.shiny? + end + + def draw_gender + return if @pokemon.egg? + if @pokemon.male? + draw_text(_INTL("♂"), 150, 44, theme: :male) + elsif @pokemon.female? + draw_text(_INTL("♀"), 150, 44, theme: :female) + end + end + + def draw_markings + mark_variants = @bitmaps[:markings].bitmap.height / MARK_HEIGHT + (@bitmaps[:markings].bitmap.width / MARK_WIDTH).times do |i| + draw_image(@bitmaps[:markings], 38 + (i * MARK_WIDTH), 262, + i * MARK_WIDTH, [(@pokemon.markings[i] || 0), mark_variants - 1].min * MARK_HEIGHT, + MARK_WIDTH, MARK_HEIGHT) + end + end + + def draw_type + return if @pokemon.egg? + @pokemon.types.each_with_index do |type, i| + type_number = GameData::Type.get(type).icon_position + type_x = (@pokemon.types.length == 1) ? 52 : 18 + ((GameData::Type::ICON_SIZE[0] + 6) * i) + draw_image(@bitmaps[:types], type_x, 282, + 0, type_number * GameData::Type::ICON_SIZE[1], *GameData::Type::ICON_SIZE) + end + end + + def draw_item + return if @pokemon.egg? + if @pokemon.hasItem? + item_name = @pokemon.item.name + item_name = crop_text(item_name, 166) + draw_text(item_name, 86, 316, align: :center) + else + draw_text(_INTL("No item"), 86, 316, align: :center, theme: :no_item) + end + end +end + +#=============================================================================== +# Pokémon sprite. +#=============================================================================== +class UI::PokemonStorageVisualsMosaicPokemonSprite < PokemonSprite + attr_reader :mosaic + + INITIAL_MOSAIC = 10 # Pixellation factor + + def initialize(*args) + super(*args) + @mosaic = 0 + @in_refresh = false + @mosaic_bitmap = nil + @mosaic_bitmap2 = nil + @old_bitmap = self.bitmap + end + + def dispose + super + @mosaic_bitmap&.dispose + @mosaic_bitmap = nil + @mosaic_bitmap2&.dispose + @mosaic_bitmap2 = nil + end + + def bitmap=(value) + super + refresh_mosaic(value) + end + + def mosaic=(value) + @mosaic = value + @mosaic = 0 if @mosaic < 0 + @start_mosaic = @mosaic if !@start_mosaic + end + + def mosaic_duration=(val) + @mosaic_duration = val + @mosaic_duration = 0 if @mosaic_duration < 0 + @mosaic_timer_start = System.uptime if @mosaic_duration > 0 + end + + def refresh_mosaic(bitmap) + return if @in_refresh + @in_refresh = true + @old_bitmap = bitmap + if @mosaic <= 0 || !@old_bitmap + @mosaic_bitmap&.dispose + @mosaic_bitmap = nil + @mosaic_bitmap2&.dispose + @mosaic_bitmap2 = nil + self.bitmap = @old_bitmap + else + newWidth = [(@old_bitmap.width / @mosaic), 1].max + newHeight = [(@old_bitmap.height / @mosaic), 1].max + @mosaic_bitmap2&.dispose + @mosaic_bitmap = pbDoEnsureBitmap(@mosaic_bitmap, newWidth, newHeight) + @mosaic_bitmap.clear + @mosaic_bitmap2 = pbDoEnsureBitmap(@mosaic_bitmap2, @old_bitmap.width, @old_bitmap.height) + @mosaic_bitmap2.clear + @mosaic_bitmap.stretch_blt(Rect.new(0, 0, newWidth, newHeight), @old_bitmap, @old_bitmap.rect) + @mosaic_bitmap2.stretch_blt( + Rect.new((-@mosaic / 2) + 1, (-@mosaic / 2) + 1, @mosaic_bitmap2.width, @mosaic_bitmap2.height), + @mosaic_bitmap, Rect.new(0, 0, newWidth, newHeight) + ) + self.bitmap = @mosaic_bitmap2 + end + @in_refresh = false + end + + def update + super + if @mosaic_timer_start + @start_mosaic = INITIAL_MOSAIC if !@start_mosaic || @start_mosaic == 0 + new_mosaic = lerp(@start_mosaic, 0, @mosaic_duration, @mosaic_timer_start, System.uptime).to_i + self.mosaic = new_mosaic + refresh_mosaic(@old_bitmap) + if new_mosaic == 0 + @mosaic_timer_start = nil + @start_mosaic = nil + end + end + end +end + +#=============================================================================== +# +#=============================================================================== +class UI::PokemonStorageVisualsPokemonIcon < PokemonIconSprite + OUTLINE_COLOR = Color.new(248, 0, 0) + FULL_BORDER = true # true = draws the corners + + def create_outline_bitmap + @selected_bitmap = Bitmap.new(@animBitmap.height + 4, @animBitmap.height + 4) + # Copy the icon's bitmap to the new bitmap + @selected_bitmap.blt(2, 2, @animBitmap.bitmap, Rect.new(0, 0, @animBitmap.height, @animBitmap.height)) + # Determine where the outline's pixels go + pixels = [] + size = @animBitmap.height / 2 + size.times do |j| + size.times do |i| + pixel = @animBitmap.bitmap.get_pixel(i * 2, j * 2) + this_coord = ((j + 1) * (size + 2)) + i + 1 + pixels[this_coord] = 1 if pixel.alpha == 255 # Visible pixel + next if pixels[this_coord] != 1 + pixels[this_coord - 1] ||= 2 + pixels[this_coord + 1] = 2 + pixels[this_coord - size - 2] ||= 2 + pixels[this_coord + size + 2] = 2 + if FULL_BORDER + pixels[this_coord - size - 2 - 1] ||= 2 + pixels[this_coord - size - 2 + 1] ||= 2 + pixels[this_coord + size + 2 - 1] = 2 + pixels[this_coord + size + 2 + 1] = 2 + end + end + end + # Draw the outline + (size + 2).times do |j| + (size + 2).times do |i| + if pixels[(j * (size + 2)) + i] == 3 + @selected_bitmap.fill_rect(i * 2, j * 2, 2, 2, Color.new(255,255,0)) + end + next if pixels[(j * (size + 2)) + i] != 2 + @selected_bitmap.fill_rect(i * 2, j * 2, 2, 2, OUTLINE_COLOR) + end + end + end + + def pokemon=(value) + super + # NOTE: This only matters when refreshing the screen after giving an item to + # a Pokémon (a selected Pokémon). It should remain selected. + if @selected_bitmap + self.bitmap = @selected_bitmap + self.src_rect.width = @selected_bitmap.width + self.src_rect.height = @selected_bitmap.height + changeOrigin + end + end + + def make_selected + return if @selected_bitmap + create_outline_bitmap + self.bitmap = @selected_bitmap + self.src_rect.width = @selected_bitmap.width + self.src_rect.height = @selected_bitmap.height + changeOrigin + self.z += 1 + end + + def make_not_selected + return if !@selected_bitmap + @selected_bitmap.dispose + @selected_bitmap = nil + if @animBitmap + self.bitmap = @animBitmap.bitmap + self.src_rect.width = @animBitmap.height + self.src_rect.height = @animBitmap.height + changeOrigin + end + self.z -= 1 + end + + def update; end # Don't animate it +end + +#=============================================================================== +# +#=============================================================================== +class UI::PokemonStorageVisualsBox < UI::SpriteContainer + attr_reader :sprites + + GRAPHICS_FOLDER = "Storage/" + TEXT_COLOR_THEMES = { # These color themes are added to @sprites[:overlay] + :default => [Color.new(248, 248, 240), Color.new(40, 48, 48)], # Base and shadow colour + } + + def initialize(storage, box_number, viewport) + @storage = storage + @box_number = box_number + super(viewport) + end + + def initialize_sprites + initialize_box_background + initialize_overlay + initialize_pokemon_icons + end + + def initialize_box_background + set_box_background + record_values(:background) + end + + def initialize_overlay + add_overlay(:overlay, @sprites[:background].bitmap.width, @sprites[:background].bitmap.height) + @sprites[:overlay].z = 10 + record_values(:overlay) + end + + def initialize_pokemon_icons + PokemonBox::BOX_SIZE.times do |i| + @sprites["pokemon_#{i}"] = UI::PokemonStorageVisualsPokemonIcon.new(@storage[@box_number, i], @viewport) + @sprites["pokemon_#{i}"].x, @sprites["pokemon_#{i}"].y = pokemon_coords(i) + @sprites["pokemon_#{i}"].z = 1 + @sprites["pokemon_#{i}"].setOffset + record_values("pokemon_#{i}") + end + end + + #----------------------------------------------------------------------------- + + def width + return @sprites[:background].width + end + + def pokemon_coords(index) + return 42 + (48 * (index % PokemonBox::BOX_WIDTH)), + 70 + (48 * (index / PokemonBox::BOX_WIDTH)) + end + + def pokemon_icon(index) + return @sprites["pokemon_#{index}"] + end + + def reset_pokemon_icon_position(index) + new_coords = pokemon_coords(index) + @sprites["pokemon_#{index}"].x = self.x + new_coords[0] + @sprites["pokemon_#{index}"].y = self.y + new_coords[1] + end + + def set_box_background(wallpaper_number = -1) + @sprites[:background]&.dispose + add_icon_sprite(:background, self.x, self.y, graphics_folder + box_bitmap(wallpaper_number)) + end + + def box_bitmap(wallpaper_number = -1) + return "box_#{wallpaper_number}" if wallpaper_number >= 0 + ret = @storage[@box_number].background + if !ret.is_a?(Integer) || !@storage.isAvailableWallpaper?(ret) + ret = @box_number % PokemonStorage::BASIC_WALLPAPER_COUNT + @storage[@box_number].background = ret + end + return "box_#{ret}" + end + + def set_visible_proc(this_proc) + @visible_proc = this_proc + apply_visible_proc + end + + def apply_visible_proc + PokemonBox::BOX_SIZE.times do |i| + if @visible_proc && !@visible_proc.call(@sprites["pokemon_#{i}"].pokemon) + @sprites["pokemon_#{i}"].opacity = 96 + else + @sprites["pokemon_#{i}"].opacity = 255 + end + end + end + + def fade_all_pokemon + PokemonBox::BOX_SIZE.times { |i| @sprites["pokemon_#{i}"].opacity = 96 } + end + + def unfade_all_pokemon + apply_visible_proc + end + + #----------------------------------------------------------------------------- + + def refresh + super + set_box_background + draw_box_name + refresh_existing_pokemon + end + + def refresh_box_name + draw_box_name + end + + def draw_box_name + box_name = @storage[@box_number].name + box_name = crop_text(box_name, 216) + draw_text(box_name, 162, 14, align: :center) + end + + def refresh_existing_pokemon + PokemonBox::BOX_SIZE.times do |i| + @sprites["pokemon_#{i}"].pokemon = @storage[@box_number, i] + end + end +end + +#=============================================================================== +# +#=============================================================================== +class UI::PokemonStorageVisualsPartyPanel < UI::SpriteContainer + attr_reader :sprites + + GRAPHICS_FOLDER = "Storage/" + TEXT_COLOR_THEMES = { # These color themes are added to @sprites[:overlay] + :default => [Color.new(248, 248, 240), Color.new(40, 48, 48)], # Base and shadow colour + } + + def initialize(party, mode, viewport) + @party = party + @mode = mode + super(viewport) + refresh + end + + def initialize_sprites + initialize_panel_background + initialize_overlay + initialize_pokemon_icons + end + + def initialize_panel_background + add_icon_sprite(:background, 0, 0, graphics_folder + "overlay_party") + record_values(:background) + end + + def initialize_overlay + add_overlay(:overlay, @sprites[:background].bitmap.width, @sprites[:background].bitmap.height) + @sprites[:overlay].z = 10 + record_values(:overlay) + end + + def initialize_pokemon_icons + Settings::MAX_PARTY_SIZE.times do |i| + @sprites["pokemon_#{i}"] = UI::PokemonStorageVisualsPokemonIcon.new(@party[i], @viewport) + @sprites["pokemon_#{i}"].x, @sprites["pokemon_#{i}"].y = pokemon_coords(i) + @sprites["pokemon_#{i}"].z = 1 + @sprites["pokemon_#{i}"].setOffset + record_values("pokemon_#{i}") + end + end + + #----------------------------------------------------------------------------- + + def height + return @sprites[:background].bitmap.height + end + + def pokemon_coords(index) + return 50 + (72 * (index % 2)), + 42 + (16 * (index % 2)) + (64 * (index / 2)) + end + + def pokemon_icon(index) + return @sprites["pokemon_#{index}"] + end + + def reset_pokemon_icon_position(index) + new_coords = pokemon_coords(index) + @sprites["pokemon_#{index}"].x = self.x + new_coords[0] + @sprites["pokemon_#{index}"].y = self.y + new_coords[1] + end + + def set_visible_proc(this_proc) + @visible_proc = this_proc + apply_visible_proc + end + + def apply_visible_proc + Settings::MAX_PARTY_SIZE.times do |i| + if @visible_proc && !@visible_proc.call(@sprites["pokemon_#{i}"].pokemon) + @sprites["pokemon_#{i}"].opacity = 96 + else + @sprites["pokemon_#{i}"].opacity = 255 + end + end + end + + #----------------------------------------------------------------------------- + + def refresh + super + draw_button_text + refresh_existing_pokemon + end + + def draw_button_text + text = (@mode == :deposit) ? _INTL("Exit") : _INTL("Back") + draw_text(text, 86, 248, align: :center, outline: :outline) + end + + def refresh_existing_pokemon + Settings::MAX_PARTY_SIZE.times do |i| + @sprites["pokemon_#{i}"].pokemon = @party[i] + end + end +end + +#=============================================================================== +# +#=============================================================================== +class UI::PokemonStorageVisualsCursor < UI::SpriteContainer + attr_reader :quick_swap_mode + + GRAPHICS_FOLDER = "Storage/" + BITMAPS = { + :point1 => ["cursor_point_1"], + :point2 => ["cursor_point_2"], + :grab => ["cursor_grab"], + :fist => ["cursor_fist"], + :point1q => ["cursor_point_1_q"], + :point2q => ["cursor_point_2_q"], + :grabq => ["cursor_grab_q"], + :fistq => ["cursor_fist_q"] + } + # Time in seconds for the cursor to move down or back up to grab/drop a + # Pokémon. + GRAB_TIME = 0.2 + + def initialize_sprites + initialize_cursor + initialize_pokemon_icon + initialize_item_icon + end + + def initialize_cursor + @sprites[:cursor] = ChangelingSprite.new(0, 0, @viewport) + BITMAPS.each_pair do |key, data| + @sprites[:cursor].add_bitmap(key, graphics_folder + data[0]) + end + @sprites[:cursor].change_bitmap(:fist) + record_values(:cursor) + end + + def initialize_pokemon_icon + @sprites[:pokemon] = UI::PokemonStorageVisualsPokemonIcon.new(nil, @viewport) + @sprites[:pokemon].x = 32 + @sprites[:pokemon].y = 48 + @sprites[:pokemon].z = -1 + @sprites[:pokemon].setOffset + record_values(:pokemon) + end + + def initialize_item_icon + @sprites[:item] = ItemIconSprite.new(32, 48, nil, @viewport) + @sprites[:item].z = -1 + @sprites[:item].setOffset + @sprites[:item].blankzero = true + record_values(:item) + end + + #----------------------------------------------------------------------------- + + def held_pokemon + return @sprites[:pokemon].pokemon + end + + def held_pokemon=(value) + @sprites[:pokemon].pokemon = value + end + + def holding_pokemon? + return !held_pokemon.nil? + end + + def held_item + return @sprites[:item].item + end + + def held_item=(value) + @sprites[:item].item = value + end + + def holding_item? + return !held_item.nil? + end + + def pokemon_icon + return @sprites[:pokemon] + end + + def quick_swap_mode=(value) + return if @quick_swap_mode == value + @quick_swap_mode = value + refresh_cursor + end + + #----------------------------------------------------------------------------- + + def animating? + return @pick_up_timer_1_start || @pick_up_timer_2_start || + @put_down_timer_1_start || @put_down_timer_2_start + end + + def pick_up_animation_1 + @pick_up_timer_1_start = System.uptime + @start_y = self.y + @sprites[:cursor].change_bitmap((@quick_swap_mode) ? :grabq : :grab) + end + + def pick_up_animation_2 + @pick_up_timer_2_start = System.uptime + @start_y = self.y + @sprites[:cursor].change_bitmap((@quick_swap_mode) ? :fistq : :fist) + end + + def put_down_animation_1 + @put_down_timer_1_start = System.uptime + @start_y = self.y + @sprites[:cursor].change_bitmap((@quick_swap_mode) ? :fistq : :fist) + end + + def put_down_animation_2 + @put_down_timer_2_start = System.uptime + @start_y = self.y + @sprites[:cursor].change_bitmap((@quick_swap_mode) ? :grabq : :grab) + end + + #----------------------------------------------------------------------------- + + def refresh_cursor + if (System.uptime / 0.5).to_i.even? # Changes every 0.5 seconds + @sprites[:cursor].change_bitmap((@quick_swap_mode) ? :point1q : :point1) + else + @sprites[:cursor].change_bitmap((@quick_swap_mode) ? :point2q : :point2) + end + end + + def update + super + if @pick_up_timer_1_start + y_offset = lerp(0, 16, GRAB_TIME, @pick_up_timer_1_start, System.uptime) + self.y = @start_y + y_offset + @pick_up_timer_1_start = nil if y_offset == 16 + elsif @pick_up_timer_2_start + y_offset = lerp(0, -16, GRAB_TIME, @pick_up_timer_2_start, System.uptime) + self.y = @start_y + y_offset + @pick_up_timer_2_start = nil if y_offset == -16 + elsif @put_down_timer_1_start + y_offset = lerp(0, 16, GRAB_TIME, @put_down_timer_1_start, System.uptime) + self.y = @start_y + y_offset + @put_down_timer_1_start = nil if y_offset == 16 + elsif @put_down_timer_2_start + y_offset = lerp(0, -16, GRAB_TIME, @put_down_timer_2_start, System.uptime) + self.y = @start_y + y_offset + @put_down_timer_2_start = nil if y_offset == -16 + elsif !holding_pokemon? && !holding_item? # Idling animation + refresh_cursor + end + end +end + +#=============================================================================== +# +#=============================================================================== +class UI::PokemonStorageVisuals < UI::BaseVisuals + # -3 = Exit button + # -2 = Party button, or Back button in party panel + # -1 = Box name + # 0+ = index in box/party + attr_reader :index + # -1 = party + # 0+ = box number + attr_reader :box + attr_reader :sub_mode + attr_reader :sprites + + GRAPHICS_FOLDER = "Storage/" # Subfolder in Graphics/UI + TEXT_COLOR_THEMES = { # These color themes are added to @sprites[:overlay] + :default => [Color.new(248, 248, 240), Color.new(40, 48, 48)], # Base and shadow colour + } + MARKING_WIDTH = 16 + MARKING_HEIGHT = 16 + + def initialize(storage, mode = :normal) + @storage = storage + @mode = mode + @index = 0 + @box = (@mode == :deposit) ? -1 : @storage.currentBox + super() + set_index(@index) + end + + def initialize_bitmaps + @bitmaps[:markings] = AnimatedBitmap.new(graphics_folder + "markings") + end + + def initialize_message_box + super + @sprites[:speech_box].width = Graphics.width - 180 + end + + def initialize_sprites + initialize_side_pane + initialize_box + initialize_party_panel + initialize_marking_sprites + initialize_cursor + initialize_buttons + end + + def initialize_side_pane + @sprites[:side_pane] = UI::PokemonStorageVisualsSidePane.new(@viewport) + @sprites[:side_pane].y = 16 + @sprites[:side_pane].z = 100 + end + + def initialize_box + @sprites[:box] = create_box_sprite(@storage.currentBox) + end + + def create_box_sprite(box_index) + ret = UI::PokemonStorageVisualsBox.new(@storage, box_index, @viewport) + ret.x = 184 + ret.y = 18 + ret.refresh + return ret + end + + def initialize_party_panel + @sprites[:party_panel] = UI::PokemonStorageVisualsPartyPanel.new(@storage.party, @mode, @viewport) + @sprites[:party_panel].x = 184 + @sprites[:party_panel].y = (showing_party_panel?) ? Graphics.height - 352 : Graphics.height + @sprites[:party_panel].z = 1100 + end + + def initialize_marking_sprites + # Background image of marking panel + add_icon_sprite(:marking_bg, 290, 68, graphics_folder + "overlay_marking") + @sprites[:marking_bg].z = 1900 + @sprites[:marking_bg].visible = false + # Overlay for marking panel + add_overlay(:marking_overlay) + @sprites[:marking_overlay].z = 1901 + @sprites[:marking_overlay].visible = false + # Cursor to highlight the currently selected marking option + add_icon_sprite(:marking_cursor, 0, 0, graphics_folder + "cursor_marking") + @sprites[:marking_cursor].z = 1902 + @sprites[:marking_cursor].visible = false + @sprites[:marking_cursor].src_rect.height = @sprites[:marking_cursor].bitmap.height / 2 + end + + def initialize_cursor + @sprites[:cursor] = UI::PokemonStorageVisualsCursor.new(@viewport) + @sprites[:cursor].z = 1500 + end + + def initialize_buttons + @sprites[:party_button] = IconSprite.new(188, 320, @viewport) + @sprites[:party_button].setBitmap(graphics_folder + "overlay_buttons") + @sprites[:party_button].src_rect.height = @sprites[:party_button].height / 2 + @sprites[:party_button].visible = ([:organize, :choose_pokemon].include?(@mode)) + @sprites[:exit_button] = IconSprite.new(386, 320, @viewport) + @sprites[:exit_button].setBitmap(graphics_folder + "overlay_buttons") + @sprites[:exit_button].src_rect.y = @sprites[:exit_button].height / 2 + @sprites[:exit_button].src_rect.height = @sprites[:exit_button].height / 2 + @sprites[:exit_button].visible = (@mode != :deposit) + end + + #----------------------------------------------------------------------------- + + def can_access_screen_menu? + return @mode == :organize + end + + def pokemon + return @sprites[:cursor].held_pokemon if holding_pokemon? + return slot_pokemon + end + + # Returns the Pokémon in the storage space the cursor is over. + def slot_pokemon + return nil if @index < 0 + return @storage.party[@index] if @box < 0 + return @storage[@box][@index] + end + + def holding_pokemon? + return @sprites[:cursor].holding_pokemon? + end + + def pokemon_icon + return @sprites[:cursor].pokemon_icon if holding_pokemon? + return @sprites[:box].pokemon_icon(@index) if @box >= 0 + return @sprites[:party_panel].pokemon_icon(@index) + end + + def item + return @sprites[:cursor].held_item + end + + def holding_item? + return @sprites[:cursor].holding_item? + end + + def showing_party_panel? + return @box == -1 + end + + def set_index(new_index) + mosaic_pokemon_sprite + @index = new_index + refresh_on_index_changed(@index) + end + + def set_sub_mode(sub_mode = :normal) + @sub_mode = sub_mode + @sprites[:cursor].quick_swap_mode = (@sub_mode != :normal) + @visible_proc = nil + if @sub_mode == :rearrange_items + @visible_proc = proc { |pkmn| pkmn.hasItem? } + end + @sprites[:box].set_visible_proc(@visible_proc) + @sprites[:party_panel].set_visible_proc(@visible_proc) + end + + def select_pokemon + pokemon_icon&.make_selected if !holding_pokemon? + end + + def deselect_pokemon + pokemon_icon&.make_not_selected if !holding_pokemon? + end + + #----------------------------------------------------------------------------- + + def go_to_next_box(new_box_number = -1) + @sprites[:side_pane].pokemon = nil if !holding_pokemon? + new_box_number = (@storage.currentBox + 1) % @storage.maxBoxes if new_box_number < 0 + @sprites[:cursor].visible = false + # Animate the boxes moving + offset_x = @sprites[:box].width + 12 + start_x = @sprites[:box].x + new_box = create_box_sprite(new_box_number) + new_box.x = start_x + offset_x + timer_start = System.uptime + loop do + @sprites[:box].x = lerp(start_x, start_x - offset_x, 0.25, timer_start, System.uptime) + new_box.x = @sprites[:box].x + offset_x + update + Graphics.update + break if new_box.x == start_x + end + @sprites[:box].dispose + @sprites[:box] = new_box + Input.update + # Tidy up + @sprites[:cursor].visible = true + @storage.currentBox = new_box_number + @box = new_box_number + refresh_side_pane + mosaic_pokemon_sprite + end + + def go_to_previous_box(new_box_number = -1) + @sprites[:side_pane].pokemon = nil if !holding_pokemon? + new_box_number = (@storage.currentBox + @storage.maxBoxes - 1) % @storage.maxBoxes if new_box_number < 0 + @sprites[:cursor].visible = false + # Animate the boxes moving + offset_x = @sprites[:box].width + 12 + start_x = @sprites[:box].x + new_box = create_box_sprite(new_box_number) + new_box.x = start_x - offset_x + timer_start = System.uptime + loop do + @sprites[:box].x = lerp(start_x, start_x + offset_x, 0.25, timer_start, System.uptime) + new_box.x = @sprites[:box].x - offset_x + update + Graphics.update + break if new_box.x == start_x + end + @sprites[:box].dispose + @sprites[:box] = new_box + Input.update + # Tidy up + @sprites[:cursor].visible = true + @storage.currentBox = new_box_number + @box = new_box_number + refresh_side_pane + mosaic_pokemon_sprite + end + + def show_party_panel + pbSEPlay("GUI storage show party panel") + @sprites[:cursor].visible = false + @sprites[:side_pane].pokemon = nil if !holding_pokemon? + start_y = @sprites[:party_panel].y # Graphics.height + timer_start = System.uptime + loop do + @sprites[:party_panel].y = lerp(start_y, start_y - @sprites[:party_panel].height, + 0.4, timer_start, System.uptime) + update + Graphics.update + break if @sprites[:party_panel].y == start_y - @sprites[:party_panel].height + end + Input.update + @box = -1 + set_index(0) + mosaic_pokemon_sprite + @sprites[:cursor].visible = true + end + + def hide_party_panel + pbSEPlay("GUI storage hide party panel") + @sprites[:cursor].visible = false + @sprites[:side_pane].pokemon = nil if !holding_pokemon? + start_y = @sprites[:party_panel].y # Graphics.height - @sprites[:party_panel].height + timer_start = System.uptime + loop do + @sprites[:party_panel].y = lerp(start_y, start_y + @sprites[:party_panel].height, + 0.4, timer_start, System.uptime) + self.update + Graphics.update + break if @sprites[:party_panel].y == start_y + @sprites[:party_panel].height + end + Input.update + @box = @storage.currentBox + set_index(-2) # Party button + mosaic_pokemon_sprite + @sprites[:cursor].visible = true + end + + #----------------------------------------------------------------------------- + + def animate_cursor(anim_method) + @sprites[:cursor].send(anim_method) + loop do + Graphics.update + update_visuals + break if !@sprites[:cursor].animating? + end + end + + def pick_up_pokemon + pbSEPlay("GUI storage pick up") + deselect_pokemon + # Animate cursor moving down to grab the Pokémon + animate_cursor(:pick_up_animation_1) + # Move Pokémon to cursor + sprite_key = (@box >= 0) ? :box : :party_panel + spr = @sprites[sprite_key].pokemon_icon(@index) + @sprites[:cursor].held_pokemon = spr.pokemon + spr.pokemon = nil + @sprites[sprite_key].reset_pokemon_icon_position(@index) + # Animate cursor moving back up holding the picked-up Pokémon + animate_cursor(:pick_up_animation_2) + Input.update + end + + def swap_pokemon + pbSEPlay("GUI storage pick up") + # Move Pokémon between cursor and slot + held_pkmn = pokemon + slot_pkmn = slot_pokemon + sprite_key = (@box >= 0) ? :box : :party_panel + spr = @sprites[sprite_key].pokemon_icon(@index) + @sprites[:cursor].held_pokemon = slot_pkmn + spr.pokemon = held_pkmn + @sprites[sprite_key].reset_pokemon_icon_position(@index) + mosaic_pokemon_sprite(true) + end + + def put_down_pokemon + pbSEPlay("GUI storage put down") + # Animate cursor moving down to put down the held Pokémon + animate_cursor(:put_down_animation_1) + # Move Pokémon to slot + sprite_key = (@box >= 0) ? :box : :party_panel + spr = @sprites[sprite_key].pokemon_icon(@index) + spr.pokemon = @sprites[:cursor].held_pokemon + @sprites[:cursor].held_pokemon = nil + # Animate cursor moving back up after putting down the held Pokémon + animate_cursor(:put_down_animation_2) + Input.update + end + + # Called when interacting with a Pokémon in the box. Automatically puts that + # Pokemon into the party. + def withdraw_pokemon + old_index = @index + pick_up_pokemon if !holding_pokemon? + show_party_panel + set_index(@storage.party.length) + put_down_pokemon + hide_party_panel + set_index(old_index) + end + + # Called when interacting with a Pokémon in the party. Automatically puts that + # Pokemon into the box. + def store_pokemon(new_box, new_index) + pick_up_pokemon if !holding_pokemon? + hide_party_panel + old_index = @index + if new_box != @box + pbPlayCursorSE + (new_box > @box) ? go_to_next_box(new_box) : go_to_previous_box(new_box) + end + set_index(new_index) + put_down_pokemon + yield if block_given? + refresh_party_panel + show_party_panel + end + + def release_pokemon(skip_anim = false) + deselect_pokemon + sprite = pokemon_icon + if !skip_anim + timer_start = System.uptime + loop do + Graphics.update + update_visuals + sprite.zoom_x = lerp(1.0, 0.0, 1.5, timer_start, System.uptime) + sprite.zoom_y = sprite.zoom_x + sprite.opacity = lerp(255, 0, 1.5, timer_start, System.uptime) + break if sprite.opacity == 0 + end + Input.update + sprite.zoom_x = 1.0 + sprite.zoom_y = 1.0 + sprite.opacity = 255 + end + sprite.pokemon = nil + end + + def mosaic_pokemon_sprite(forced = false) + return if !forced && holding_pokemon? + @sprites[:side_pane].mosaic_pokemon_sprite if pokemon + end + + #----------------------------------------------------------------------------- + + def pick_up_item + pbSEPlay("GUI storage pick up") + # Animate cursor moving down to grab the item + animate_cursor(:pick_up_animation_1) + # Move item to cursor + @sprites[:cursor].held_item = pokemon.item + pokemon.item = nil + refresh_side_pane + @sprites[:box].set_visible_proc(@visible_proc) + @sprites[:party_panel].set_visible_proc(@visible_proc) + # Animate cursor moving back up holding the picked-up item + animate_cursor(:pick_up_animation_2) + Input.update + end + + def swap_items + pbSEPlay("GUI storage pick up") + # Move item from slot Pokémon to cursor + @sprites[:cursor].held_item = pokemon.item + end + + def put_down_item + pbSEPlay("GUI storage put down") + # Animate cursor moving down to put down the held item + animate_cursor(:put_down_animation_1) + # Move item to slot Pokémon + pokemon.item = @sprites[:cursor].held_item + @sprites[:cursor].held_item = nil + refresh_side_pane + @sprites[:box].set_visible_proc(@visible_proc) + @sprites[:party_panel].set_visible_proc(@visible_proc) + # Animate cursor moving back up after putting down the held item + animate_cursor(:put_down_animation_2) + Input.update + end + + #----------------------------------------------------------------------------- + + def choose_box(message, start_box = -1) + start_box = @storage.currentBox if start_box < 0 + commands = {} + @storage.maxBoxes.times do |i| + box = @storage[i] + commands[i] = _INTL("{1} ({2}/{3})", box.name, box.nitems, box.length) if box + end + return show_menu(message, commands, commands.keys.index(start_box) || 0) + end + + #----------------------------------------------------------------------------- + + def position_speech_box(text) + @sprites[:speech_box].resizeHeightToFit(text, Graphics.width - @sprites[:side_pane].width) + pbBottomRight(@sprites[:speech_box]) + end + + # Replaces the version in class UI::BaseVisuals because the speech box needs + # to be positioned differently. + def show_choice_message(text, options, index = 0, align: :vertical, cmd_side: :right) + ret = -1 + commands = options + commands = options.values if options.is_a?(Hash) + @sprites[:speech_box].visible = true + @sprites[:speech_box].text = text + using(cmd_window = Window_AdvancedCommandPokemon.new(commands)) do + position_speech_box(text) + cmd_window.viewport = @viewport + cmd_window.z = @sprites[:speech_box].z + 1 + pbBottomRight(cmd_window) + cmd_window.height = [cmd_window.height, Graphics.height - @sprites[:speech_box].height].min + cmd_window.y = Graphics.height - @sprites[:speech_box].height - cmd_window.height + cmd_window.visible = !@sprites[:speech_box].busy? + cmd_window.index = index + loop do + Graphics.update + Input.update + update_visuals + cmd_window.visible = true if !@sprites[:speech_box].busy? + cmd_window.update + if !@sprites[:speech_box].busy? + if Input.trigger?(Input::BACK) + pbPlayCancelSE + ret = -1 + break + elsif Input.trigger?(Input::USE) && @sprites[:speech_box].resume + pbPlayDecisionSE + ret = cmd_window.index + break + end + end + end + end + @sprites[:speech_box].visible = false + if options.is_a?(Hash) + ret = (ret < 0) ? nil : options.keys[ret] + end + return ret + end + + def choose_box_wallpaper(text, options, index = 0) + original_index = index + ret = -1 + commands = options + commands = options.values if options.is_a?(Hash) + old_letter_by_letter = @sprites[:speech_box].letterbyletter + @sprites[:speech_box].letterbyletter = false + @sprites[:speech_box].visible = true + @sprites[:speech_box].text = text + @sprites[:box].fade_all_pokemon + using(cmd_window = Window_AdvancedCommandPokemon.new(commands)) do + position_speech_box(text) + cmd_window.viewport = @viewport + cmd_window.z = @sprites[:speech_box].z + 1 + pbBottomLeft(cmd_window) + cmd_window.width = @sprites[:side_pane].width + cmd_window.height = [cmd_window.height, Graphics.height].min + cmd_window.y = Graphics.height - cmd_window.height + cmd_window.visible = !@sprites[:speech_box].busy? + cmd_window.index = index + loop do + Graphics.update + Input.update + update_visuals + cmd_window.visible = true if !@sprites[:speech_box].busy? + old_index = cmd_window.index + cmd_window.update + if cmd_window.index != old_index + paper_num = (options.is_a?(Hash)) ? options.keys[cmd_window.index] : cmd_window.index + @sprites[:box].set_box_background(paper_num) + end + if !@sprites[:speech_box].busy? + if Input.trigger?(Input::BACK) + pbPlayCancelSE + ret = -1 + break + elsif Input.trigger?(Input::USE) && @sprites[:speech_box].resume + pbPlayDecisionSE + ret = cmd_window.index + break + end + end + end + end + if options.is_a?(Hash) + ret = (ret < 0) ? nil : options.keys[ret] + end + @sprites[:speech_box].letterbyletter = old_letter_by_letter + @sprites[:speech_box].visible = false + @sprites[:box].unfade_all_pokemon + @sprites[:box].set_box_background(options.keys[original_index]) if ret.nil? + return ret + end + + #----------------------------------------------------------------------------- + + def refresh + super + refresh_box + refresh_side_pane + refresh_party_panel + refresh_buttons + refresh_cursor_position + end + + def refresh_box + @sprites[:box].refresh + end + + def refresh_side_pane + return if holding_pokemon? # Selected Pokémon is always the held one + refresh_selected_pokemon + end + + def refresh_party_panel + @sprites[:party_panel].refresh + end + + def refresh_selected_pokemon + @sprites[:side_pane].pokemon = pokemon + end + + def refresh_buttons + if [:organize, :choose_pokemon].include?(@mode) + draw_text(_INTL("Party: {1}", @storage.party.length), 270, 334, align: :center, outline: :outline) + end + if @mode != :deposit + draw_text(_INTL("Exit"), 446, 334, align: :center, outline: :outline) + end + end + + def refresh_cursor_position + if showing_party_panel? + if @index < 0 # Back button + @sprites[:cursor].x = 236 + @sprites[:cursor].y = 220 + else + coords = @sprites[:party_panel].pokemon_coords(@index) + @sprites[:cursor].x = @sprites[:party_panel].x + coords[0] - 32 + @sprites[:cursor].y = @sprites[:party_panel].y + coords[1] - 64 + end + return + end + case @index + when -1 # Box name + @sprites[:cursor].x = 314 + @sprites[:cursor].y = -24 + when -2 # Party Pokémon button + @sprites[:cursor].x = 238 + @sprites[:cursor].y = 278 + when -3 # Close Box button + @sprites[:cursor].x = 414 + @sprites[:cursor].y = 278 + else # Box space + coords = @sprites[:box].pokemon_coords(@index) + @sprites[:cursor].x = @sprites[:box].x + coords[0] - 32 + @sprites[:cursor].y = @sprites[:box].y + coords[1] - 64 + end + end + + def refresh_on_index_changed(old_index) + refresh_cursor_position + refresh_side_pane + end + + def refresh_markings_cursor + case @marking_index + when 6 # OK + @sprites[:marking_cursor].x = 318 + @sprites[:marking_cursor].y = 196 + @sprites[:marking_cursor].src_rect.y = @sprites[:marking_cursor].bitmap.height / 2 + when 7 # Cancel + @sprites[:marking_cursor].x = 318 + @sprites[:marking_cursor].y = 260 + @sprites[:marking_cursor].src_rect.y = @sprites[:marking_cursor].bitmap.height / 2 + else + @sprites[:marking_cursor].x = 318 + (58 * (@marking_index % 3)) + @sprites[:marking_cursor].y = 96 + (50 * (@marking_index / 3)) + @sprites[:marking_cursor].src_rect.y = 0 + end + end + + def refresh_markings_panel + # Set values to use when drawing the markings panel + marking_x = 334 + marking_y = 106 + marking_spacing_x = 42 + MARKING_WIDTH + marking_spacing_y = 34 + MARKING_HEIGHT + markings_per_row = 3 + mark_variants = @bitmaps[:markings].bitmap.height / MARKING_HEIGHT + # Clear the bitmap + @sprites[:marking_overlay].bitmap.clear + # Draw marking icons + (@bitmaps[:markings].bitmap.width / MARKING_WIDTH).times do |i| + src_x = i * MARKING_WIDTH + src_y = [(@markings[i] || 0), mark_variants - 1].min * MARKING_HEIGHT + draw_image(@bitmaps[:markings], + marking_x + (marking_spacing_x * (i % markings_per_row)), + marking_y + (marking_spacing_y * (i / markings_per_row)), + src_x, src_y, MARKING_WIDTH, MARKING_HEIGHT, + overlay: :marking_overlay) + end + # Draw text + draw_text(_INTL("OK"), 400, 216, align: :center, outline: :outline, overlay: :marking_overlay) + draw_text(_INTL("Cancel"), 400, 280, align: :center, outline: :outline, overlay: :marking_overlay) + end + + #----------------------------------------------------------------------------- + + def update_input + deselect_pokemon + # Check for movement to a new Pokémon/button + old_index = @index + update_cursor_movement + if @index != old_index + pbPlayCursorSE + set_index(@index) + end + # Check for interaction + if Input.trigger?(Input::USE) + return update_interaction(Input::USE) + elsif Input.trigger?(Input::BACK) + return update_interaction(Input::BACK) + elsif Input.trigger?(Input::ACTION) + return update_interaction(Input::ACTION) + elsif Input.trigger?(Input::JUMPUP) + return update_interaction(Input::JUMPUP) + elsif Input.trigger?(Input::JUMPDOWN) + return update_interaction(Input::JUMPDOWN) + end + return nil + end + + def update_cursor_movement + if showing_party_panel? + update_cursor_movement_party + return + end + if Input.repeat?(Input::UP) + case @index + when -1 # Box name + @index = (@mode == :withdraw) ? -3 : -2 # Exit button : Party button + when -2 # Party button + @index = PokemonBox::BOX_SIZE - 1 - (PokemonBox::BOX_WIDTH * 2 / 3) # 25 + when -3 # Exit button + @index = PokemonBox::BOX_SIZE - (PokemonBox::BOX_WIDTH / 3) # 28 + else + @index -= PokemonBox::BOX_WIDTH + @index = -1 if @index < 0 # Box name + end + elsif Input.repeat?(Input::DOWN) + case @index + when -1 # Box name + @index = PokemonBox::BOX_WIDTH / 3 # 2 + when -2, -3 # Party button, Exit button + @index = -1 # Box name + else + @index += PokemonBox::BOX_WIDTH + if @index >= PokemonBox::BOX_SIZE + if @index < PokemonBox::BOX_SIZE + (PokemonBox::BOX_WIDTH / 2) && @mode != :withdraw + @index = -2 # Party button + else + @index = -3 # Exit button + end + end + end + end + if Input.repeat?(Input::LEFT) + if @index == -1 # Box name + pbPlayCursorSE + go_to_previous_box + elsif @index == -2 # Party button + @index = -3 # Exit button + elsif @index == -3 # Exit button + @index = -2 if @mode != :withdraw # Party button + elsif (@index % PokemonBox::BOX_WIDTH) == 0 # Wrap around + @index += PokemonBox::BOX_WIDTH - 1 + else + @index -= 1 + end + elsif Input.repeat?(Input::RIGHT) + if @index == -1 # Box name + pbPlayCursorSE + go_to_next_box + elsif @index == -2 # Party button + @index = -3 # Exit button + elsif @index == -3 # Exit button + @index = -2 if @mode != :withdraw # Party button + elsif (@index % PokemonBox::BOX_WIDTH) == PokemonBox::BOX_WIDTH - 1 # Wrap around + @index -= PokemonBox::BOX_WIDTH - 1 + else + @index += 1 + end + end + end + + # The Back button is at @index -2. + def update_cursor_movement_party + if Input.repeat?(Input::UP) + if @index == -2 # Back button + @index = Settings::MAX_PARTY_SIZE - 1 + else + @index -= 2 + @index = -2 if @index < 0 # Back button + end + elsif Input.repeat?(Input::DOWN) + if @index == -2 # Back button + @index = 0 + else + @index += 2 + @index = -2 if @index >= Settings::MAX_PARTY_SIZE # Back button + end + end + if Input.repeat?(Input::LEFT) + @index -= 1 + @index = Settings::MAX_PARTY_SIZE - 1 if @index < -2 + @index = -2 if @index < 0 # Back button + elsif Input.repeat?(Input::RIGHT) + @index += 1 + @index = 0 if @index < 0 + @index = -2 if @index >= Settings::MAX_PARTY_SIZE # Back button + end + end + + def update_interaction(input) + case input + when Input::USE + if @index == -1 # Box name + pbPlayDecisionSE + return :interact_box_name_menu + elsif @index == -2 # Party button, or Back button in party panel + pbPlayDecisionSE + return :exit_screen if @mode == :deposit + return (showing_party_panel?) ? :hide_party_panel : :show_party_panel + elsif @index == -3 # Exit button + pbPlayDecisionSE + return :exit_screen + else + if pokemon + return :rearrange_pokemon if @sub_mode == :rearrange_pokemon + return :rearrange_items if @sub_mode == :rearrange_items + pbPlayDecisionSE + select_pokemon + return :interact_menu + end + end + when Input::ACTION + if can_access_screen_menu? + pbPlayDecisionSE + return :screen_menu + end + when Input::BACK + pbPlayCancelSE + if showing_party_panel? + return (@mode == :deposit) ? :exit_screen : :hide_party_panel + end + return :clear_sub_mode if (@sub_mode || :normal) != :normal + return :exit_screen + when Input::JUMPUP + pbPlayCursorSE + go_to_previous_box + when Input::JUMPDOWN + pbPlayCursorSE + go_to_next_box + end + return nil + end + + #----------------------------------------------------------------------------- + + # NOTE: This is hardcoded to assume there are 6 marks, arranged in a 3x2 grid, + # with an OK and Cancel button below. + def update_input_marking + # Check for movement to a new option + if Input.repeat?(Input::UP) + if @marking_index == 7 # Cancel + @marking_index = 6 + elsif @marking_index == 6 # OK + @marking_index = 4 + elsif @marking_index < 3 + @marking_index = 7 + else + @marking_index -= 3 + end + elsif Input.repeat?(Input::DOWN) + if @marking_index == 7 # Cancel + @marking_index = 1 + elsif @marking_index == 6 # OK + @marking_index = 7 + elsif @marking_index >= 3 + @marking_index = 6 + else + @marking_index += 3 + end + elsif Input.repeat?(Input::LEFT) + if @marking_index < 6 + @marking_index -= 1 + @marking_index += 3 if (@marking_index % 3) == 2 + end + elsif Input.repeat?(Input::RIGHT) + if @marking_index < 6 + @marking_index += 1 + @marking_index -= 3 if (@marking_index % 3) == 0 + end + end + # Check for interaction + if Input.trigger?(Input::USE) + pbPlayDecisionSE + case @marking_index + when 6 # OK + return true + when 7 # Cancel + @marking_index = -1 + return true + else # Change marking + mark_variants = @bitmaps[:markings].bitmap.height / MARKING_HEIGHT + @markings[@marking_index] = ((@markings[@marking_index] || 0) + 1) % mark_variants + refresh_markings_panel + end + elsif Input.trigger?(Input::BACK) + pbPlayCloseMenuSE + @marking_index = -1 + return true + elsif Input.trigger?(Input::ACTION) + if @marking_index < 6 && @markings[@marking_index] > 0 + pbPlayDecisionSE + @markings[@marking_index] = 0 + refresh_markings_panel + end + end + return false + end + + def navigate_markings + help_text = _INTL("Mark your Pokémon.") + help_window = Window_AdvancedTextPokemon.newWithSize( + help_text, 180, 0, Graphics.width - 180, 32, @viewport + ) + help_window.z = 2000 + help_window.setSkin(MessageConfig.pbGetSpeechFrame) + help_window.letterbyletter = false + help_window.resizeHeightToFit(help_text, Graphics.width - 180) + pbBottomRight(help_window) + # Setup + @sprites[:marking_bg].visible = true + @sprites[:marking_overlay].visible = true + @sprites[:marking_cursor].visible = true + @markings = pokemon.markings.clone + @marking_index = 0 + refresh_markings_panel + refresh_markings_cursor + # Navigate loop + loop do + Graphics.update + Input.update + update_visuals + old_marking_index = @marking_index + break if update_input_marking + if @marking_index != old_marking_index + pbPlayCursorSE + refresh_markings_panel + refresh_markings_cursor + end + end + # Clean up + @sprites[:marking_bg].visible = false + @sprites[:marking_overlay].visible = false + @sprites[:marking_cursor].visible = false + pokemon.markings = @markings if @marking_index >= 0 + @marking_index = nil + help_window.dispose + end +end + +#=============================================================================== +# +#=============================================================================== +class UI::PokemonStorage < UI::BaseScreen + attr_reader :storage, :mode + + SCREEN_ID = :pokemon_storage_screen + + # mode is one of: + # :withdraw + # :deposit + # :organize + # :choose_pokemon + def initialize(storage, mode: :organize) + @storage = storage + @mode = mode + super() + end + + def initialize_visuals + @visuals = UI::PokemonStorageVisuals.new(@storage, @mode) + end + + def start_screen + pbSEPlay("PC access") + super + end + + def end_screen + pbSEPlay("PC close") + super + end + + #----------------------------------------------------------------------------- + + # Returns the "active" Pokémon, i.e. the one that gets interacted with and is + # shown in the side pane. + def pokemon + return @visuals.pokemon + end + + def slot_pokemon + return @visuals.slot_pokemon + end + + # Returns whether the cursor is holding a Pokémon. + def holding_pokemon? + return @visuals.holding_pokemon? + end + + def item + return @visuals.item + end + + def holding_item? + return @visuals.holding_item? + end + + # -1 is the party, 0+ is a box. + def box + return @visuals.box + end + + def choose_box(message, start_box = -1) + return @visuals.choose_box(message, start_box) + end + + def set_index(new_index) + @visuals.set_index(new_index) + end + + def set_sub_mode(sub_mode = :normal) + @visuals.set_sub_mode(sub_mode) + end + + def party_able_count + return @storage.party.count { |pkmn| pkmn.able? } + end + + def deselect_pokemon + @visuals.deselect_pokemon + end + + #----------------------------------------------------------------------------- + + def refresh_selected_pokemon + @visuals.refresh_selected_pokemon + end + + def refresh_box + @visuals.refresh_box + end +end + +#=============================================================================== +# Actions that can be triggered in the Pokémon storage screen. +#=============================================================================== +# Shows a choice menu using the MenuHandlers options below. +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :screen_menu, { + :menu => :storage_screen_menu, + :menu_message => proc { |screen| _INTL("What do you want to do?") } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :rearrange_pokemon_mode, { + :effect => proc { |screen| + if screen.holding_item? + screen.show_message(_INTL("You're holding an item!")) + next + end + screen.set_sub_mode(:rearrange_pokemon) + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :rearrange_items_mode, { + :effect => proc { |screen| + if screen.holding_pokemon? + screen.show_message(_INTL("You're holding a Pokémon!")) + next + end + screen.set_sub_mode(:rearrange_items) + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :clear_sub_mode, { + :effect => proc { |screen| + if screen.holding_pokemon? + screen.show_message(_INTL("You're holding a Pokémon!")) + next + elsif screen.holding_item? + item_name = GameData::Item.get(screen.item).name + if screen.show_confirm_message(_INTL("Put the {1} in your Bag?", item_name)) + $bag.add(screen.item) + screen.visuals.sprites[:cursor].held_item = nil + end + next + end + screen.set_sub_mode(:normal) + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :rearrange_pokemon, { + :effect => proc { |screen| + if screen.holding_pokemon? + if screen.slot_pokemon + screen.perform_action(:swap_pokemon) + else + screen.perform_action(:put_down_pokemon) + end + else + screen.perform_action(:pick_up_pokemon) + end + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :rearrange_items, { + :effect => proc { |screen| + next if !screen.slot_pokemon + if screen.holding_item? + if screen.slot_pokemon && screen.slot_pokemon.hasItem? + screen.perform_action(:swap_items) + else + screen.perform_action(:put_down_item) + end + elsif screen.slot_pokemon && screen.slot_pokemon.hasItem? + screen.perform_action(:pick_up_item) + end + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :pick_up_item, { + :effect => proc { |screen| + next if screen.holding_item? || !screen.slot_pokemon || !screen.slot_pokemon.hasItem? + if screen.slot_pokemon.mail + screen.show_message("You can't move mail.") + next + end + screen.visuals.pick_up_item + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :swap_items, { + :effect => proc { |screen| + next if !screen.holding_item? || !screen.slot_pokemon || !screen.slot_pokemon.hasItem? + held_item = screen.item + slot_pkmn = screen.slot_pokemon + if slot_pkmn.mail + screen.show_message("You can't move mail.") + next + end + screen.visuals.swap_items + slot_pkmn.item = held_item + screen.refresh_selected_pokemon + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :put_down_item, { + :effect => proc { |screen| + next if !screen.holding_item? || !screen.slot_pokemon || screen.slot_pokemon.hasItem? + pkmn = screen.slot_pokemon + screen.visuals.put_down_item + } +}) + +#------------------------------------------------------------------------------- + +# Shows a choice menu using the MenuHandlers options below. +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :interact_menu, { + :menu => :storage_pokemon_interact, + :menu_message => proc { |screen| _INTL("Do what with {1}?", screen.pokemon.name) } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :select_pokemon, { + :returns_value => true, + :effect => proc { |screen| + if screen.slot_pokemon + screen.result = [screen.box, screen.index] + next :quit + end + next nil + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :pick_up_pokemon, { + :effect => proc { |screen| + raise _INTL("Tried picking up a Pokémon when holding one.") if screen.holding_pokemon? + raise _INTL("Position {1},{2} is empty...", screen.box, screen.index) if !screen.slot_pokemon + if screen.box < 0 && screen.slot_pokemon.able? && screen.party_able_count <= 1 + pbPlayBuzzerSE + screen.show_message(_INTL("That's your last Pokémon!")) + next + end + screen.visuals.pick_up_pokemon + screen.storage.pbDelete(screen.box, screen.index) + screen.refresh + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :swap_pokemon, { + :effect => proc { |screen| + raise _INTL("Tried swapping a Pokémon when not holding one.") if !screen.holding_pokemon? + raise _INTL("Position {1},{2} is empty...", screen.box, screen.index) if !screen.slot_pokemon + held_pkmn = screen.pokemon + slot_pkmn = screen.slot_pokemon + if screen.box >= 0 + if screen.index >= @storage.maxPokemon(screen.box) + screen.show_message("Can't place that there.") + next + elsif held_pkmn.mail + screen.show_message("Please remove the mail.") + next + elsif held_pkmn.cannot_store + screen.show_message(_INTL("{1} refuses to go into storage!", held_pkmn.name)) + next + end + elsif screen.box < 0 && slot_pkmn.able? && screen.party_able_count <= 1 && !held_pkmn.able? + pbPlayBuzzerSE + screen.show_message(_INTL("That's your last Pokémon!")) + next + end + screen.visuals.swap_pokemon + screen.storage[screen.box, screen.index] = held_pkmn + if Settings::HEAL_STORED_POKEMON && screen.box >= 0 + old_ready_evo = held_pkmn.ready_to_evolve + held_pkmn.heal + held_pkmn.ready_to_evolve = old_ready_evo + end + screen.refresh + screen.refresh_selected_pokemon + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :put_down_pokemon, { + :effect => proc { |screen| + raise _INTL("Tried placing a Pokémon when not holding one.") if !screen.holding_pokemon? + raise _INTL("Position {1},{2} is not empty...", screen.box, screen.index) if screen.slot_pokemon + pkmn = screen.pokemon # The held Pokémon + if screen.box >= 0 + if screen.index >= screen.storage.maxPokemon(screen.box) + screen.show_message("Can't place that there.") + next + elsif pkmn.mail + screen.show_message("Please remove the mail.") + next + elsif pkmn.cannot_store + screen.show_message(_INTL("{1} refuses to go into storage!", pkmn.name)) + next + end + end + screen.visuals.put_down_pokemon + screen.storage[screen.box, screen.index] = pkmn + screen.storage.party.compact! if screen.box < 0 + if Settings::HEAL_STORED_POKEMON && screen.box >= 0 + old_ready_evo = pkmn.ready_to_evolve + pkmn.heal + pkmn.ready_to_evolve = old_ready_evo + end + screen.refresh + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :summary, { + :effect => proc { |screen| + pbFadeOutInWithUpdate(screen.sprites) do + screen.deselect_pokemon + if screen.holding_pokemon? + UI::PokemonSummary.new(screen.pokemon, 0).main + else + party = (screen.box >= 0) ? screen.storage[screen.box].pokemon : screen.storage[screen.box] + new_index = UI::PokemonSummary.new(party, screen.index).main + screen.set_index(new_index) + end + end + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :withdraw, { + :effect => proc { |screen| + screen.perform_action(:withdraw_pokemon) + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :withdraw_pokemon, { + :effect => proc { |screen| + raise _INTL("Can't withdraw from party...") if screen.box < 0 + if screen.storage.party_full? + screen.show_message(_INTL("Your party's full!")) + next + end + was_holding = screen.holding_pokemon? + pkmn = screen.pokemon + screen.visuals.withdraw_pokemon + if was_holding + screen.storage.pbMoveCaughtToParty(pkmn) + else + screen.storage.pbMove(-1, -1, screen.box, screen.index) + end + screen.refresh + screen.refresh_selected_pokemon + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :store, { + :effect => proc { |screen| + screen.perform_action(:store_pokemon) + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :store_pokemon, { + :effect => proc { |screen| + raise _INTL("Can't deposit from box...") if screen.box >= 0 + was_holding = screen.holding_pokemon? + pkmn = screen.pokemon + if pkmn.able? && screen.party_able_count <= 1 && !screen.holding_pokemon? + pbPlayBuzzerSE + screen.show_message(_INTL("That's your last Pokémon!")) + next + elsif pkmn.mail + screen.show_message("Please remove the mail.") + next + elsif pkmn.cannot_store + screen.show_message(_INTL("{1} refuses to go into storage!", pkmn.name)) + next + end + old_box = screen.box + old_index = screen.index + loop do + new_box = screen.choose_box(_INTL("Deposit in which Box?"), old_box) + break if !new_box + new_index = screen.storage.pbFirstFreePos(new_box) + if new_index < 0 + screen.show_message(_INTL("The Box is full.")) + next + end + screen.visuals.store_pokemon(new_box, new_index) { + if was_holding + screen.storage.pbMoveCaughtToBox(pkmn, new_box) + else + screen.storage.pbMove(new_box, new_index, old_box, old_index) + end + } + screen.refresh + screen.refresh_selected_pokemon + break + end + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :give_or_take_item, { + :effect => proc { |screen| + pkmn = screen.pokemon + if pkmn.egg? + screen.show_message(_INTL("Eggs can't hold items.")) + next + elsif pkmn.mail + screen.show_message(_INTL("Please remove the mail.")) + next + end + # Take an item + if pkmn.hasItem? + item_name = pkmn.item.portion_name + if screen.show_confirm_message(_INTL("Take the {1}?", item_name)) + if $bag.add(pkmn.item) + pkmn.item = nil + screen.refresh + screen.show_message(_INTL("Took the {1}.", item_name)) + else + screen.show_message(_INTL("Can't store the {1}.", item_name)) + end + end + screen.deselect_pokemon + next + end + # Give an item + new_item = nil + pbFadeOutInWithUpdate(screen.sprites) do + bag_screen = UI::Bag.new($bag, mode: :choose_item) + bag_screen.set_filter_proc(proc { |itm| GameData::Item.get(itm).can_hold? }) + new_item = bag_screen.choose_item + screen.deselect_pokemon if !new_item + end + if new_item + item_name = GameData::Item.get(new_item).name + pkmn.item = new_item + $bag.remove(new_item) + screen.refresh + screen.show_message(_INTL("{1} is now being held.", item_name)) + screen.deselect_pokemon + end + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :mark_pokemon, { + :effect => proc { |screen| + screen.visuals.navigate_markings + screen.deselect_pokemon + screen.refresh + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :release_pokemon, { + :effect => proc { |screen| + raise _INTL("Tried releasing a Pokémon when not selecting or holding one.", screen.box, screen.index) if !screen.pokemon + pkmn = screen.pokemon + if pkmn.egg? + screen.show_message(_INTL("You can't release an Egg.")) + next + elsif pkmn.mail + screen.show_message(_INTL("Please remove the mail.")) + next + elsif pkmn.cannot_release + screen.show_message(_INTL("{1} refuses to leave you!", pkmn.name)) + next + elsif screen.box < 0 && pkmn.able? && screen.party_able_count <= 1 && !screen.holding_pokemon? + pbPlayBuzzerSE + screen.show_message(_INTL("That's your last Pokémon!")) + next + end + if screen.show_confirm_serious_message(_INTL("Release this Pokémon?")) + $bag.add(pkmn.item_id) if pkmn.hasItem? + pkmn_name = pkmn.name + screen.visuals.release_pokemon + screen.storage.pbDelete(screen.box, screen.index) if !screen.holding_pokemon? + screen.refresh + screen.show_message(_INTL("{1} was released.", pkmn_name)) + screen.show_message(_INTL("Bye-bye, {1}!", pkmn_name)) + $stats.pokemon_release_count += 1 + end + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :debug, { + :effect => proc { |screen| + screen.pokemon_debug_menu(screen.pokemon, [screen.box, screen.index]) + } +}) + +#------------------------------------------------------------------------------- + +# Shows a choice menu using the MenuHandlers options below. +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :interact_box_name_menu, { + :menu => :storage_box_interact, + :menu_message => proc { |screen| _INTL("Choose an option.") } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :jump_to_box, { + :effect => proc { |screen| + new_box = screen.choose_box(_INTL("Jump to which Box?")) + next if !new_box || new_box == box + (new_box > box) ? screen.visuals.go_to_next_box(new_box) : screen.visuals.go_to_previous_box(new_box) + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :rename_box, { + :effect => proc { |screen| + pbFadeOutInWithUpdate(screen.sprites) do + ret = pbEnterBoxName(_INTL("Box name?"), 0, 16) + if ret.length > 0 + screen.storage[screen.storage.currentBox].name = ret + screen.refresh_box + end + end + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :change_box_wallpaper, { + :effect => proc { |screen| + papers = screen.storage.availableWallpapers + old_paper = screen.storage[screen.storage.currentBox].background + index = papers.keys.index(old_paper) || 0 + new_paper = screen.visuals.choose_box_wallpaper(_INTL("Pick the wallpaper."), papers, index) + if new_paper && new_paper != old_paper + screen.storage[screen.storage.currentBox].background = new_paper + screen.refresh_box + end + } +}) + +#------------------------------------------------------------------------------- + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :show_party_panel, { + :effect => proc { |screen| + screen.visuals.show_party_panel + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :hide_party_panel, { + :effect => proc { |screen| + screen.visuals.hide_party_panel + } +}) + +UIActionHandlers.add(UI::PokemonStorage::SCREEN_ID, :exit_screen, { + :returns_value => true, + :effect => proc { |screen| + if screen.holding_pokemon? + screen.show_message(_INTL("You're holding a Pokémon!")) + next nil + elsif screen.holding_item? + screen.show_message(_INTL("You're holding an item!")) + next nil + end + next :quit if screen.show_confirm_message(_INTL("Exit from the Box?")) + next nil + } +}) + +#=============================================================================== +# Menu options for choice menus that exist in the Pokémon storage screen. +#=============================================================================== +MenuHandlers.add(:storage_screen_menu, :rearrange_pokemon_mode, { + "name" => _INTL("Mode: Switch Pokémon"), + "order" => 10 +}) + +MenuHandlers.add(:storage_screen_menu, :rearrange_items_mode, { + "name" => _INTL("Mode: Switch items"), + "order" => 20 +}) + +MenuHandlers.add(:storage_screen_menu, :cancel, { + "name" => _INTL("Cancel"), + "order" => 9999 +}) + +#------------------------------------------------------------------------------- + +# NOTE: This option is first in withdraw mode. +MenuHandlers.add(:storage_pokemon_interact, :withdraw, { + "name" => _INTL("Withdraw"), + "order" => 10, + "condition" => proc { |screen| next screen.mode == :withdraw && screen.box >= 0 } +}) + +# NOTE: This option is first in store mode. +MenuHandlers.add(:storage_pokemon_interact, :store, { + "name" => _INTL("Store"), + "order" => 10, + "condition" => proc { |screen| next screen.mode == :deposit && screen.box < 0 } +}) + +# NOTE: This option is for when in "choose a Pokémon" mode. +MenuHandlers.add(:storage_pokemon_interact, :select_pokemon, { + "name" => _INTL("Select"), + "order" => 10, + "condition" => proc { |screen| next screen.mode == :choose_pokemon } +}) + +MenuHandlers.add(:storage_pokemon_interact, :pick_up_pokemon, { + "name" => _INTL("Move"), + "order" => 20, + "condition" => proc { |screen| next screen.mode == :organize && !screen.holding_pokemon? } +}) + +MenuHandlers.add(:storage_pokemon_interact, :swap_pokemon, { + "name" => _INTL("Shift"), + "order" => 20, + "condition" => proc { |screen| next screen.mode == :organize && screen.holding_pokemon? && screen.slot_pokemon } +}) + +MenuHandlers.add(:storage_pokemon_interact, :put_down_pokemon, { + "name" => _INTL("Place"), + "order" => 20, + "condition" => proc { |screen| next screen.mode == :organize && screen.holding_pokemon? && !screen.slot_pokemon } +}) + +MenuHandlers.add(:storage_pokemon_interact, :summary, { + "name" => _INTL("Summary"), + "order" => 30 +}) + +MenuHandlers.add(:storage_pokemon_interact, :withdraw_pokemon, { + "name" => _INTL("Withdraw"), + "order" => 40, + "condition" => proc { |screen| next screen.mode == :organize && screen.box >= 0 } +}) + +MenuHandlers.add(:storage_pokemon_interact, :store_pokemon, { + "name" => _INTL("Store"), + "order" => 40, + "condition" => proc { |screen| next screen.mode == :organize && screen.box < 0 } +}) + +MenuHandlers.add(:storage_pokemon_interact, :give_or_take_item, { + "name" => _INTL("Item"), + "order" => 50, + "condition" => proc { |screen| next screen.mode == :organize } +}) + +MenuHandlers.add(:storage_pokemon_interact, :mark_pokemon, { + "name" => _INTL("Mark"), + "order" => 60 +}) + +MenuHandlers.add(:storage_pokemon_interact, :release_pokemon, { + "name" => _INTL("Release"), + "order" => 70, + "condition" => proc { |screen| next screen.mode != :choose_pokemon } +}) + +MenuHandlers.add(:storage_pokemon_interact, :debug, { + "name" => _INTL("Debug"), + "order" => 80, + "condition" => proc { |screen| next $DEBUG } +}) + +MenuHandlers.add(:storage_pokemon_interact, :cancel, { + "name" => _INTL("Cancel"), + "order" => 9999 +}) + +#------------------------------------------------------------------------------- + +MenuHandlers.add(:storage_box_interact, :jump_to_box, { + "name" => _INTL("Jump to box"), + "order" => 10 +}) + +MenuHandlers.add(:storage_box_interact, :rename_box, { + "name" => _INTL("Rename box"), + "order" => 20 +}) + +MenuHandlers.add(:storage_box_interact, :change_box_wallpaper, { + "name" => _INTL("Change wallpaper"), + "order" => 30 +}) + +MenuHandlers.add(:storage_box_interact, :cancel, { + "name" => _INTL("Cancel"), + "order" => 9999 +}) diff --git a/Data/Scripts/016b_UI redesign/019_UI_PC.rb b/Data/Scripts/016b_UI redesign/019_UI_PC.rb index d9bad242e..76dd6ab37 100644 --- a/Data/Scripts/016b_UI redesign/019_UI_PC.rb +++ b/Data/Scripts/016b_UI redesign/019_UI_PC.rb @@ -24,10 +24,7 @@ module UI::PC command = 0 loop do choice = pbMessage(_INTL("Which PC should be accessed?"), command_list, -1, nil, command) - if choice < 0 - pbPlayCloseMenuSE - break - end + break if choice < 0 break if commands[choice]["effect"].call end pbSEPlay("PC close") @@ -220,9 +217,7 @@ MenuHandlers.add(:pc_menu, :pokemon_storage, { when :organize pbPlayDecisionSE pbFadeOutIn do - scene = PokemonStorageScene.new - screen = PokemonStorageScreen.new(scene, $PokemonStorage) - screen.pbStartScreen(0) + UI::PokemonStorage.new($PokemonStorage, mode: :organize).main end when :withdraw if $PokemonStorage.party_full? @@ -231,9 +226,7 @@ MenuHandlers.add(:pc_menu, :pokemon_storage, { end pbPlayDecisionSE pbFadeOutIn do - scene = PokemonStorageScene.new - screen = PokemonStorageScreen.new(scene, $PokemonStorage) - screen.pbStartScreen(1) + UI::PokemonStorage.new($PokemonStorage, mode: :withdraw).main end when :deposit if $player.able_pokemon_count <= 1 @@ -242,9 +235,7 @@ MenuHandlers.add(:pc_menu, :pokemon_storage, { end pbPlayDecisionSE pbFadeOutIn do - scene = PokemonStorageScene.new - screen = PokemonStorageScreen.new(scene, $PokemonStorage) - screen.pbStartScreen(2) + UI::PokemonStorage.new($PokemonStorage, mode: :deposit).main end else break diff --git a/Data/Scripts/016_UI/017_UI_PokemonStorage.rb b/Data/Scripts/016c_UI_old/017_UI_old_PokemonStorage.rb similarity index 99% rename from Data/Scripts/016_UI/017_UI_PokemonStorage.rb rename to Data/Scripts/016c_UI_old/017_UI_old_PokemonStorage.rb index 1df5326f8..a133bab7a 100644 --- a/Data/Scripts/016_UI/017_UI_PokemonStorage.rb +++ b/Data/Scripts/016c_UI_old/017_UI_old_PokemonStorage.rb @@ -501,6 +501,13 @@ class PokemonBoxPartySprite < Sprite refresh end + def z=(value) + super + Settings::MAX_PARTY_SIZE.times do |i| + @pokemonsprites[i].z = value + 1 if @pokemonsprites[i] && !@pokemonsprites[i].disposed? + end + end + def color=(value) super Settings::MAX_PARTY_SIZE.times do |i| @@ -565,7 +572,7 @@ class PokemonBoxPartySprite < Sprite sprite.viewport = self.viewport sprite.x = self.x + xvalues[j] sprite.y = self.y + yvalues[j] - sprite.z = 1 + sprite.z = self.z + 1 end end @@ -1254,8 +1261,7 @@ class PokemonStorageScene pbPartySetArrow(@sprites["arrow"], @selection) pbUpdateOverlay(@selection, @storage.party) else - screen = UI::PokemonSummary.new(@storage.boxes[selected[0]].pokemon, selected[1]).main - @selection = screen.result + @selection = UI::PokemonSummary.new(@storage.boxes[selected[0]].pokemon, selected[1]).main pbSetArrow(@sprites["arrow"], @selection) pbUpdateOverlay(@selection) end diff --git a/Data/Scripts/020_Debug/003_Debug menus/001_Debug_Menus.rb b/Data/Scripts/020_Debug/003_Debug menus/001_Debug_Menus.rb index 86ca4e4eb..3c2cbb0ec 100644 --- a/Data/Scripts/020_Debug/003_Debug menus/001_Debug_Menus.rb +++ b/Data/Scripts/020_Debug/003_Debug menus/001_Debug_Menus.rb @@ -149,7 +149,7 @@ end # #=============================================================================== module PokemonDebugMixin - def pokemon_debug_menu(pkmn, pkmnid, heldpoke = nil, settingUpBattle = false) + def pokemon_debug_menu(pkmn, pkmnid, settingUpBattle = false) # Get all commands commands = CommandMenuList.new MenuHandlers.each_available(:pokemon_debug_menu) do |option, hash, name| @@ -170,7 +170,7 @@ module PokemonDebugMixin if commands.hasSubMenu?(cmd) commands.currentList = cmd command = 0 - elsif MenuHandlers.call(:pokemon_debug_menu, cmd, "effect", pkmn, pkmnid, heldpoke, settingUpBattle, self) + elsif MenuHandlers.call(:pokemon_debug_menu, cmd, "effect", pkmn, pkmnid, settingUpBattle, self) break end end @@ -178,6 +178,73 @@ module PokemonDebugMixin end end +#=============================================================================== +# +#=============================================================================== +class UI::Party + include PokemonDebugMixin +end + +#=============================================================================== +# +#=============================================================================== +class UI::PokemonStorage + include PokemonDebugMixin + + def choose_move(pkmn, message) + move_names = [] + pkmn.moves.each do |move| + next if !move || !move.id + if move.total_pp <= 0 + move_names.push(_INTL("{1} (PP: ---)", move.name)) + else + move_names.push(_INTL("{1} (PP: {2}/{3})", move.name, move.pp, move.total_pp)) + end + end + return show_menu(message, move_names) + end +end + +#=============================================================================== +# +#=============================================================================== +class UI::PartyDebugVisuals < UI::BaseVisuals + def initialize_background; end + def initialize_overlay; end + + def choose_number(help_text, maximum, init_value = 1) + old_letter_by_letter = @sprites[:speech_box].letterbyletter + @sprites[:speech_box].letterbyletter = false + ret = super + @sprites[:speech_box].letterbyletter = old_letter_by_letter + return ret + end +end + +class UI::PartyDebug < UI::BaseScreen + include PokemonDebugMixin + + def initialize_visuals + @visuals = UI::PartyDebugVisuals.new + end + + def choose_move(pkmn, message, index = 0) + # TODO: The move names can get rather wide, making the message box rather + # thin. It's just about acceptable, but maybe the choice window needs + # to be displayed above the message box instead of to the right of it. + move_names = [] + pkmn.moves.each do |move| + next if !move || !move.id + if move.total_pp <= 0 + move_names.push(_INTL("{1} (PP: ---)", move.name)) + else + move_names.push(_INTL("{1} (PP: {2}/{3})", move.name, move.pp, move.total_pp)) + end + end + return show_menu(message, move_names, index) + end +end + #=============================================================================== # #=============================================================================== @@ -405,60 +472,6 @@ module Battle::DebugMixin end end -#=============================================================================== -# -#=============================================================================== -class UI::Party - include PokemonDebugMixin -end - -#=============================================================================== -# -#=============================================================================== -class PokemonStorageScreen - include PokemonDebugMixin -end - -#=============================================================================== -# -#=============================================================================== -class UI::PartyDebugVisuals < UI::BaseVisuals - def initialize_background; end - def initialize_overlay; end - - def choose_number(help_text, maximum, init_value = 1) - old_letter_by_letter = @sprites[:speech_box].letterbyletter - @sprites[:speech_box].letterbyletter = false - ret = super - @sprites[:speech_box].letterbyletter = old_letter_by_letter - return ret - end -end - -class UI::PartyDebug < UI::BaseScreen - include PokemonDebugMixin - - def initialize_visuals - @visuals = UI::PartyDebugVisuals.new - end - - def choose_move(pkmn, message, index = 0) - # TODO: The move names can get rather wide, making the message box rather - # thin. It's just about acceptable, but maybe the choice window needs - # to be displayed above the message box instead of to the right of it. - move_names = [] - pkmn.moves.each do |move| - next if !move || !move.id - if move.total_pp <= 0 - move_names.push(_INTL("{1} (PP: ---)", move.name)) - else - move_names.push(_INTL("{1} (PP: {2}/{3})", move.name, move.pp, move.total_pp)) - end - end - return show_menu(message, move_names, index) - end -end - #=============================================================================== # #=============================================================================== diff --git a/Data/Scripts/020_Debug/003_Debug menus/002_Debug_MenuCommands.rb b/Data/Scripts/020_Debug/003_Debug menus/002_Debug_MenuCommands.rb index 2e36b99b3..37ab51a77 100644 --- a/Data/Scripts/020_Debug/003_Debug menus/002_Debug_MenuCommands.rb +++ b/Data/Scripts/020_Debug/003_Debug menus/002_Debug_MenuCommands.rb @@ -221,33 +221,33 @@ MenuHandlers.add(:debug_menu, :storage_wallpapers, { "description" => _INTL("Unlock and lock special wallpapers used in Pokémon storage."), "effect" => proc { w = $PokemonStorage.allWallpapers - if w.length <= PokemonStorage::BASICWALLPAPERQTY + if w.length <= PokemonStorage::BASIC_WALLPAPER_COUNT pbMessage(_INTL("There are no special wallpapers defined.")) - else - paperscmd = 0 - unlockarray = $PokemonStorage.unlockedWallpapers - loop do - paperscmds = [] - paperscmds.push(_INTL("Unlock all")) - paperscmds.push(_INTL("Lock all")) - (PokemonStorage::BASICWALLPAPERQTY...w.length).each do |i| - paperscmds.push((unlockarray[i] ? "[Y]" : "[ ]") + " " + w[i]) + next + end + paperscmd = 0 + unlockarray = $PokemonStorage.unlockedWallpapers + loop do + paperscmds = [] + paperscmds.push(_INTL("Unlock all")) + paperscmds.push(_INTL("Lock all")) + (PokemonStorage::BASIC_WALLPAPER_COUNT...w.length).each do |i| + paperscmds.push((unlockarray[i] ? "[Y]" : "[ ]") + " " + w[i]) + end + paperscmd = pbShowCommands(nil, paperscmds, -1, paperscmd) + break if paperscmd < 0 + case paperscmd + when 0 # Unlock all + (PokemonStorage::BASIC_WALLPAPER_COUNT...w.length).each do |i| + unlockarray[i] = true end - paperscmd = pbShowCommands(nil, paperscmds, -1, paperscmd) - break if paperscmd < 0 - case paperscmd - when 0 # Unlock all - (PokemonStorage::BASICWALLPAPERQTY...w.length).each do |i| - unlockarray[i] = true - end - when 1 # Lock all - (PokemonStorage::BASICWALLPAPERQTY...w.length).each do |i| - unlockarray[i] = false - end - else - paperindex = paperscmd - 2 + PokemonStorage::BASICWALLPAPERQTY - unlockarray[paperindex] = !$PokemonStorage.unlockedWallpapers[paperindex] + when 1 # Lock all + (PokemonStorage::BASIC_WALLPAPER_COUNT...w.length).each do |i| + unlockarray[i] = false end + else + paperindex = paperscmd - 2 + PokemonStorage::BASIC_WALLPAPER_COUNT + unlockarray[paperindex] = !$PokemonStorage.unlockedWallpapers[paperindex] end end } @@ -355,7 +355,7 @@ MenuHandlers.add(:debug_menu, :test_wild_battle_advanced, { else # Edit a Pokémon if pbConfirmMessage(_INTL("Change this Pokémon?")) scr = UI::PartyDebug.new - scr.pokemon_debug_menu(pkmn[pkmnCmd], -1, nil, true) + scr.pokemon_debug_menu(pkmn[pkmnCmd], -1, true) scr.silent_end_screen elsif pbConfirmMessage(_INTL("Delete this Pokémon?")) pkmn.delete_at(pkmnCmd) @@ -711,9 +711,7 @@ MenuHandlers.add(:debug_menu, :open_storage, { "description" => _INTL("Opens the Pokémon storage boxes in Organize Boxes mode."), "effect" => proc { pbFadeOutIn do - scene = PokemonStorageScene.new - screen = PokemonStorageScreen.new(scene, $PokemonStorage) - screen.pbStartScreen(0) + UI::PokemonStorage.new($PokemonStorage, mode: :organize).main end } }) diff --git a/Data/Scripts/020_Debug/003_Debug menus/007_Debug_PokemonCommands.rb b/Data/Scripts/020_Debug/003_Debug menus/007_Debug_PokemonCommands.rb index be8439297..24389beb1 100644 --- a/Data/Scripts/020_Debug/003_Debug menus/007_Debug_PokemonCommands.rb +++ b/Data/Scripts/020_Debug/003_Debug menus/007_Debug_PokemonCommands.rb @@ -10,7 +10,7 @@ MenuHandlers.add(:pokemon_debug_menu, :hp_status_menu, { MenuHandlers.add(:pokemon_debug_menu, :set_hp, { "name" => _INTL("Set HP"), "parent" => :hp_status_menu, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| if pkmn.egg? screen.show_message(_INTL("{1} is an egg.", pkmn.name)) next false @@ -30,7 +30,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_hp, { MenuHandlers.add(:pokemon_debug_menu, :set_status, { "name" => _INTL("Set status"), "parent" => :hp_status_menu, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| if pkmn.egg? screen.show_message(_INTL("{1} is an egg.", pkmn.name)) next false @@ -78,7 +78,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_status, { MenuHandlers.add(:pokemon_debug_menu, :full_heal, { "name" => _INTL("Fully heal"), "parent" => :hp_status_menu, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| if pkmn.egg? screen.show_message(_INTL("{1} is an egg.", pkmn.name)) else @@ -92,7 +92,7 @@ MenuHandlers.add(:pokemon_debug_menu, :full_heal, { MenuHandlers.add(:pokemon_debug_menu, :make_fainted, { "name" => _INTL("Make fainted"), "parent" => :hp_status_menu, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| if pkmn.egg? screen.show_message(_INTL("{1} is an egg.", pkmn.name)) else @@ -106,7 +106,7 @@ MenuHandlers.add(:pokemon_debug_menu, :make_fainted, { MenuHandlers.add(:pokemon_debug_menu, :set_pokerus, { "name" => _INTL("Set Pokérus"), "parent" => :hp_status_menu, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :random_strain => _INTL("Give random strain"), :non_infectious => _INTL("Make not infectious"), @@ -153,7 +153,7 @@ MenuHandlers.add(:pokemon_debug_menu, :level_stats, { MenuHandlers.add(:pokemon_debug_menu, :set_level, { "name" => _INTL("Set level"), "parent" => :level_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| if pkmn.egg? screen.show_message(_INTL("{1} is an egg.", pkmn.name)) next false @@ -174,7 +174,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_level, { MenuHandlers.add(:pokemon_debug_menu, :set_exp, { "name" => _INTL("Set Exp"), "parent" => :level_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| if pkmn.egg? screen.show_message(_INTL("{1} is an egg.", pkmn.name)) next false @@ -201,7 +201,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_exp, { MenuHandlers.add(:pokemon_debug_menu, :hidden_values, { "name" => _INTL("EV/IV/personal ID..."), "parent" => :level_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :set_evs => _INTL("Set EVs"), :set_ivs => _INTL("Set IVs"), @@ -315,7 +315,7 @@ MenuHandlers.add(:pokemon_debug_menu, :hidden_values, { MenuHandlers.add(:pokemon_debug_menu, :set_happiness, { "name" => _INTL("Set happiness"), "parent" => :level_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| params = ChooseNumberParams.new params.setRange(0, 255) params.setDefaultValue(pkmn.happiness) @@ -336,7 +336,7 @@ MenuHandlers.add(:pokemon_debug_menu, :contest_stats, { MenuHandlers.add(:pokemon_debug_menu, :set_beauty, { "name" => _INTL("Set Beauty"), "parent" => :contest_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| params = ChooseNumberParams.new params.setRange(0, 255) params.setDefaultValue(pkmn.beauty) @@ -352,7 +352,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_beauty, { MenuHandlers.add(:pokemon_debug_menu, :set_cool, { "name" => _INTL("Set Cool"), "parent" => :contest_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| params = ChooseNumberParams.new params.setRange(0, 255) params.setDefaultValue(pkmn.cool) @@ -368,7 +368,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_cool, { MenuHandlers.add(:pokemon_debug_menu, :set_cute, { "name" => _INTL("Set Cute"), "parent" => :contest_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| params = ChooseNumberParams.new params.setRange(0, 255) params.setDefaultValue(pkmn.cute) @@ -384,7 +384,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_cute, { MenuHandlers.add(:pokemon_debug_menu, :set_smart, { "name" => _INTL("Set Smart"), "parent" => :contest_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| params = ChooseNumberParams.new params.setRange(0, 255) params.setDefaultValue(pkmn.smart) @@ -400,7 +400,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_smart, { MenuHandlers.add(:pokemon_debug_menu, :set_tough, { "name" => _INTL("Set Tough"), "parent" => :contest_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| params = ChooseNumberParams.new params.setRange(0, 255) params.setDefaultValue(pkmn.tough) @@ -416,7 +416,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_tough, { MenuHandlers.add(:pokemon_debug_menu, :set_sheen, { "name" => _INTL("Set Sheen"), "parent" => :contest_stats, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| params = ChooseNumberParams.new params.setRange(0, 255) params.setDefaultValue(pkmn.sheen) @@ -441,7 +441,7 @@ MenuHandlers.add(:pokemon_debug_menu, :moves, { MenuHandlers.add(:pokemon_debug_menu, :teach_move, { "name" => _INTL("Teach move"), "parent" => :moves, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| move = pbChooseMoveList if move pbLearnMove(pkmn, move) @@ -456,7 +456,7 @@ MenuHandlers.add(:pokemon_debug_menu, :teach_move, { MenuHandlers.add(:pokemon_debug_menu, :forget_move, { "name" => _INTL("Forget move"), "parent" => :moves, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| move_index = screen.choose_move(pkmn, _INTL("Choose move to forget.")) if move_index >= 0 move_name = pkmn.moves[move_index].name @@ -471,7 +471,7 @@ MenuHandlers.add(:pokemon_debug_menu, :forget_move, { MenuHandlers.add(:pokemon_debug_menu, :reset_moves, { "name" => _INTL("Reset moves"), "parent" => :moves, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| pkmn.reset_moves screen.refresh screen.show_message(_INTL("{1}'s moves were reset.", pkmn.name)) @@ -482,7 +482,7 @@ MenuHandlers.add(:pokemon_debug_menu, :reset_moves, { MenuHandlers.add(:pokemon_debug_menu, :set_move_pp, { "name" => _INTL("Set move PP..."), "parent" => :moves, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| cmd = nil loop do commands = {} @@ -539,7 +539,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_move_pp, { MenuHandlers.add(:pokemon_debug_menu, :set_initial_moves, { "name" => _INTL("Reset initial moves"), "parent" => :moves, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| pkmn.record_first_moves screen.refresh screen.show_message(_INTL("{1}'s current moves were set as its first-known moves.", pkmn.name)) @@ -554,7 +554,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_initial_moves, { MenuHandlers.add(:pokemon_debug_menu, :set_item, { "name" => _INTL("Set item"), "parent" => :main, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :change_item => _INTL("Change item"), :delete_item => _INTL("Remove item") @@ -589,7 +589,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_item, { MenuHandlers.add(:pokemon_debug_menu, :set_ability, { "name" => _INTL("Set ability"), "parent" => :main, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :set_ability_index => _INTL("Set possible ability"), :give_any_ability => _INTL("Set any ability"), @@ -641,7 +641,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_ability, { MenuHandlers.add(:pokemon_debug_menu, :set_nature, { "name" => _INTL("Set nature"), "parent" => :main, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = {} GameData::Nature.each do |nature| if nature.stat_changes.length == 0 @@ -676,7 +676,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_nature, { MenuHandlers.add(:pokemon_debug_menu, :set_gender, { "name" => _INTL("Set gender"), "parent" => :main, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| if pkmn.singleGendered? screen.show_message(_INTL("{1} is single-gendered or genderless.", pkmn.speciesName)) next false @@ -713,7 +713,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_gender, { MenuHandlers.add(:pokemon_debug_menu, :species_and_form, { "name" => _INTL("Species/form..."), "parent" => :main, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :set_species => _INTL("Set species"), :set_form => _INTL("Set form"), @@ -731,6 +731,7 @@ MenuHandlers.add(:pokemon_debug_menu, :species_and_form, { if species && species != pkmn.species pbPlayDecisionSE pkmn.species = species + pkmn.gender = nil pkmn.calc_stats $player.pokedex.register(pkmn) if !setting_up_battle && !pkmn.egg? screen.refresh @@ -790,7 +791,7 @@ MenuHandlers.add(:pokemon_debug_menu, :cosmetic, { MenuHandlers.add(:pokemon_debug_menu, :set_shininess, { "name" => _INTL("Set shininess"), "parent" => :cosmetic, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :make_shiny => _INTL("Make shiny"), :make_super_shiny => _INTL("Make super shiny"), @@ -826,7 +827,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_shininess, { MenuHandlers.add(:pokemon_debug_menu, :set_pokeball, { "name" => _INTL("Set Poké Ball"), "parent" => :cosmetic, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = {} cmd = nil GameData::Item.each do |item| @@ -848,7 +849,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_pokeball, { MenuHandlers.add(:pokemon_debug_menu, :set_ribbons, { "name" => _INTL("Set ribbons"), "parent" => :cosmetic, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| cmd = nil loop do commands = {} @@ -876,7 +877,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_ribbons, { MenuHandlers.add(:pokemon_debug_menu, :set_nickname, { "name" => _INTL("Set nickname"), "parent" => :cosmetic, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :rename => _INTL("Rename"), :clear_name => _INTL("Erase name") @@ -905,7 +906,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_nickname, { MenuHandlers.add(:pokemon_debug_menu, :ownership, { "name" => _INTL("Ownership..."), "parent" => :cosmetic, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :make_players => _INTL("Make player's"), :set_ot_name => _INTL("Set OT's name"), @@ -960,7 +961,7 @@ MenuHandlers.add(:pokemon_debug_menu, :ownership, { MenuHandlers.add(:pokemon_debug_menu, :set_discardable, { "name" => _INTL("Set discardable"), "parent" => :main, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| cmd = nil loop do commands = { @@ -992,7 +993,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_egg, { "name" => _INTL("Set egg"), "parent" => :main, "always_show" => false, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| commands = { :make_egg => _INTL("Make egg"), :make_pokemon => _INTL("Make Pokémon"), @@ -1036,7 +1037,7 @@ MenuHandlers.add(:pokemon_debug_menu, :set_egg, { MenuHandlers.add(:pokemon_debug_menu, :shadow_pkmn, { "name" => _INTL("Shadow Pkmn..."), "parent" => :main, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| # TODO: Option to make not a Shadow Pokémon. commands = { :make_shadow => _INTL("Make Shadow"), @@ -1079,7 +1080,7 @@ MenuHandlers.add(:pokemon_debug_menu, :mystery_gift, { "name" => _INTL("Mystery Gift"), "parent" => :main, "always_show" => false, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| pbCreateMysteryGift(0, pkmn) next false } @@ -1089,7 +1090,7 @@ MenuHandlers.add(:pokemon_debug_menu, :duplicate, { "name" => _INTL("Duplicate"), "parent" => :main, "always_show" => false, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| next false if !screen.show_confirm_message(_INTL("Are you sure you want to copy this Pokémon?")) cloned_pkmn = pkmn.clone case screen @@ -1097,9 +1098,9 @@ MenuHandlers.add(:pokemon_debug_menu, :duplicate, { pbStorePokemon(cloned_pkmn) # Add to party, or to storage if party is full screen.refresh_party screen.refresh - when PokemonStorageScreen + when UI::PokemonStorage if screen.storage.pbMoveCaughtToParty(cloned_pkmn) - screen.show_message(_INTL("The duplicated Pokémon was moved to your party.")) if party_index[0] != -1 + screen.show_message(_INTL("The duplicated Pokémon was moved to your party.")) if party_index[0] >= 0 else old_box = screen.storage.currentBox new_box = screen.storage.pbStoreCaught(cloned_pkmn) @@ -1120,15 +1121,15 @@ MenuHandlers.add(:pokemon_debug_menu, :delete, { "name" => _INTL("Delete"), "parent" => :main, "always_show" => false, - "effect" => proc { |pkmn, party_index, held_pkmn, setting_up_battle, screen| + "effect" => proc { |pkmn, party_index, setting_up_battle, screen| next false if !screen.show_confirm_message(_INTL("Are you sure you want to delete this Pokémon?")) case screen when UI::Party screen.party.delete_at(party_index) screen.refresh_party - when PokemonStorageScreen - screen.scene.pbRelease(party_index, held_pkmn) - (held_pkmn) ? screen.heldpkmn = nil : screen.storage.pbDelete(party_index[0], party_index[1]) + when UI::PokemonStorage + screen.visuals.release_pokemon(true) + screen.storage.pbDelete(party_index[0], party_index[1]) if !screen.holding_pokemon? end screen.refresh next true