• Hi, Guest!
    Some images might be missing as we move away from using embedded images, sorry for the mess!
    From now on, you'll be required to use a third party to host images. You can learn how to add images here, and if your thread is missing images you can request them here.
    Do not use Discord to host any images you post, these links expire quickly!
Resource icon

Resource Storage System Utilities (v20 + v21)! 2023-07-07

Swdfm

Game Developer
Member
Joined
Sep 3, 2018
Posts
18
Swdfm submitted a new resource:

Storage System Utilities (v20 + v21)! - A Script For Storage that allows for Multiple Movement, Mass Release and Swapping Boxes

So, I was wanting to add some add/adapt multiple movement in sotrage scripts from one of my fangames to another, and then I realised that I might as well make the script public, update it, and add a few features to it.

Introducing:

Storage System Utilities!

A useful small plugin that allows you to add a litany of useful features straight to the Storage System!
Works with Essentials Version 20 OR 21.

To install:
Download...​

Read more about this resource...
 

Jangajinx

An Overly Ambitious Developer
Member
Joined
Apr 21, 2023
Posts
213
This is amazing! Thanks for sharing it! As an aspiring game developer myself seeing this is a must have! If you are looking to add more utilities I would love to see the ability to sort mons by national dex number or alphabetical order. Keep up the great work! Much love!
 

Drqiu

Novice
Member
Joined
Jun 6, 2023
Posts
23
Hello! Thank you very much for your work. I tried the plugin and when the hand is green, everything works fine. However, when my hand is white or gold, I try to grab the Pokémon and the game gets stuck. My game version is 20.1 and I wonder if you can solve this problem. Thanks!
 

Jangajinx

An Overly Ambitious Developer
Member
Joined
Apr 21, 2023
Posts
213
To add on top of Drqiu's problem, What key is suppose to activate this plugin? I am also using the BW storage system.
 

Cross Agento

Novice
Member
Joined
Jun 27, 2021
Posts
31
Hello! Thank you very much for your work. I tried the plugin and when the hand is green, everything works fine. However, when my hand is white or gold, I try to grab the Pokémon and the game gets stuck. My game version is 20.1 and I wonder if you can solve this problem. Thanks!
I also have the same issue. When I pick up a Pokemon when the hand is gold, everything freezes.
 

wrigty12

Tester-Coder Hybrid
Member
Joined
Jul 24, 2022
Posts
493
Yeah, it seems this isn't actually compatible with v20. It's using System.uptime in places that isn't checking for version, and since that's not used in v20, that may be part of the problem.

Also, when you mass pick up Pokemon, the sprites disappear, which is an additional visual bug (occurs with v21 too).
 

Leondrea

Trainer
Member
Joined
Jul 26, 2020
Posts
95
Holy Miltank! That will make the games feel more like gen 8/9 I love this so much, thank you!
This is revolutionary, you're a legend!
 

SomebodyRandom

Trainer
Member
Joined
Feb 13, 2022
Posts
61
I'm getting this error when trying to compile my game, it works without this plugin
 

Attachments

  • 1689643848347.png
    1689643848347.png
    17.7 KB · Views: 102

REALMUGEN

Trainer
Member
Joined
Jan 23, 2020
Posts
69
I'm getting this error when trying to compile my game, it works without this plugin

It seems to have to do with a repeated code fragment.

If you remove this fragment taking care to leave the original one it should work...

Ruby:
  #===============================================================================
  # Additional methods: Tension
  # Used For Multiple Grabbing
  #===============================================================================
  def set_tension
    @tension = :Selecting # 1
  end
 
  def start_tension
    @tension = :Moving # 2
  end
 
  def release_tension
    @tension = :None # 0
  end
end
 

wrigty12

Tester-Coder Hybrid
Member
Joined
Jul 24, 2022
Posts
493
Yeah, it seems this isn't actually compatible with v20. It's using System.uptime in places that isn't checking for version, and since that's not used in v20, that may be part of the problem.

Also, when you mass pick up Pokemon, the sprites disappear, which is an additional visual bug (occurs with v21 too).
@Swdfm , when can we expect fixes to the freezing issue some us are facing with v20, and the disappearing sprites issue when picking up multiple?

I was able to play with the code myself and fix the freezing easily, but the disappearing sprites issues (which is a deal breaker for me using this script) has been more difficult due to the way you are deleting Pokemon as soon as you pick them up :/
 

Swdfm

Game Developer
Member
Joined
Sep 3, 2018
Posts
18
@wrigty12 @REALMUGEN @SomebodyRandom @Jangajinx

Sorry, I didn't see any of these replies until just now! Apologies!
New download link up fixing almost all of the issues raised.

The Pokemon disappearing is part of the design, but I am happy to not have that be the case. The easiest way would probably be for it to have a number representing the amount of Pokemon held, or have it hold the "pivot" Pokemon. Which do you think would be better?
I have not tested this with the BW Storage System. I'm happy to conduct further tests in the near future
 
Last edited:

wrigty12

Tester-Coder Hybrid
Member
Joined
Jul 24, 2022
Posts
493
@wrigty12 @REALMUGEN @SomebodyRandom @Jangajinx

Sorry, I didn't see any of these replies until just now! Apologies!
New download link up fixing almost all of the issues raised.

The Pokemon disappearing is part of the design, but I am happy to not have that be the case. The easiest way would probably be for it to have a number representing the amount of Pokemon held, or have it hold the "pivot" Pokemon. Which do you think would be better?
I have not tested this with the BW Storage System. I'm happy to conduct further tests in the near future
I feel like it's important to keep a visual of what exact Pokemon and in which position they are in when moving Pokemon en mass like this, so it's clear if there is room to set them down. Pretty much exactly like it occurs in the mainline games: https://youtube.com/shorts/IjheE9YwiiE?feature=share

A number representing how many you're holding doesn't feel like it would mean much. As for the pivot Pokemon, do you mean the last Pokemon you selected, and it would only show that one Pokemon?

Also another bug: When you use the pour feature, it's putting the pokemon in the boxes in reverse order of what you picked them up in (so if I multi selected Bulbasaur, Ivysaur, and Venasaur in that order, it's pouring them into the box in Venasaur, Ivysaur, Bulbasaur order instead of the original order).
 

Swdfm

Game Developer
Member
Joined
Sep 3, 2018
Posts
18
I feel like it's important to keep a visual of what exact Pokemon and in which position they are in when moving Pokemon en mass like this, so it's clear if there is room to set them down. Pretty much exactly like it occurs in the mainline games: https://youtube.com/shorts/IjheE9YwiiE?feature=share

A number representing how many you're holding doesn't feel like it would mean much. As for the pivot Pokemon, do you mean the last Pokemon you selected, and it would only show that one Pokemon?

Also another bug: When you use the pour feature, it's putting the pokemon in the boxes in reverse order of what you picked them up in (so if I multi selected Bulbasaur, Ivysaur, and Venasaur in that order, it's pouring them into the box in Venasaur, Ivysaur, Bulbasaur order instead of the original order).
I'll have a look on Unbound and see how it works. Quite surprsed this has not been done before if someone already figured out how to do it!

The "bug" is more of a necessary evil. I tried to get it to work normally, but it just would not work. I'll take another look at it
 

wrigty12

Tester-Coder Hybrid
Member
Joined
Jul 24, 2022
Posts
493
I'll have a look on Unbound and see how it works. Quite surprsed this has not been done before if someone already figured out how to do it!

The "bug" is more of a necessary evil. I tried to get it to work normally, but it just would not work. I'll take another look at it
I fixed the pour bug, you just need to use .shift instead of .pop (green highlighted section)

While I was in there, I also fixed an issue where if there were spots that were empty, those were still being poured; now they wont be (pink highlighted section)

I also added in the Sound Effect of placing a Pokemon down, so it's consistent with the other functions (blue highlighted section)
1690034179603.png
 

Swdfm

Game Developer
Member
Joined
Sep 3, 2018
Posts
18
I fixed the pour bug, you just need to use .shift instead of .pop (green highlighted section)

While I was in there, I also fixed an issue where if there were spots that were empty, those were still being poured; now they wont be (pink highlighted section)

I also added in the Sound Effect of placing a Pokemon down, so it's consistent with the other functions (blue highlighted section)
View attachment 19326
Thanks. I'll make sure to credit you on the next update!
 

PDM20

Coder of Chaos!
Member
Joined
Apr 5, 2019
Posts
58
Found a bug, I've done some modifications on my version of the script to iron out some other bugs, but this one is beyond me. the issue is as followed:
Select one pokemon, move it (using either white or gold) to any empty space, turn the cursor green and try and grab it. it will cause the crash described in the picture. I'll also include my modified code if you can't replicate it on your end.
crash.png

Ruby:
#===============================================================================
# Storage System Utilities
# By Swdfm
# Works For Both Essentials Version 20 and 21
#===============================================================================
STORAGE_ARROW_PATH = "Graphics/Pictures/Storage/"

# Can Boxes be quickly swapped by selecting "Swap" from the Box Heading?
CAN_SWAP_BOXES   = true

# Can multiple Pokemon be selected/moved at the same time using the green hand?
CAN_MULTI_SELECT = true

# Can Pokemon be mass released by pressing the Action Key while having multiple Pokemon grabed?
# Need to have CAN_MULTI_SELECT selected
CAN_MASS_RELEASE = true

# Can one "pour" Pokemon into a box?
# This lets you quickly store held Pokemon into a box by clicking Use button on page header while moving held Pokemon
CAN_BOX_POUR     = false

#===============================================================================
# Using Version 21 or not?
#===============================================================================
def pbVersion21?
  return Essentials::VERSION.include?("21")
end

#===============================================================================
# Nitty Gritty below here!
# Don't touch unless you knwo what you're doing!
#===============================================================================
# PokemonBoxIcon Overrides
#===============================================================================
class PokemonBoxIcon < IconSprite
  #===============================================================================
  # Turns the sprite(s) into a certain colour
  #===============================================================================
  def make_clear
    @type = :Clear
  end
  def make_green
    @type = :Green
  end
  def make_grey
    @type = :Grey
  end
 
  #===============================================================================
  # update Override
  #===============================================================================
  def update
    super
    @type = :Clear if !@type
    return update_21 if pbVersion21?
    @release.update
    do_colours
    dispose if @startRelease && !releasing?
  end
 
  def update_21
    do_colours
    if releasing?
      time_now = System.uptime
      self.zoom_x = lerp(1.0, 0.0, 1.5, @release_timer_start, System.uptime)
      self.zoom_y = self.zoom_x
      self.opacity = lerp(255, 0, 1.5, @release_timer_start, System.uptime)
      if self.opacity == 0
        @release_timer_start = nil
        dispose
      end
    end
  end
 
  def do_colours
    case @type
    when :Clear
      self.color = Color.new(0, 0, 0, 0)
    when :Green
      self.color = Color.new(0, 128, 0, 192)
    when :Grey
      self.color = Color.new(128, 128, 128, 255)
    end
  end
end

#===============================================================================
# PokemonBoxArrow Override
#===============================================================================
class PokemonBoxArrow < Sprite
  attr_accessor :multi
 
  #===============================================================================
  # initialize Add On
  #===============================================================================
  alias swdfm_init initialize
  def initialize(viewport = nil)
    swdfm_init(viewport)
    @path  = STORAGE_ARROW_PATH
    if @path == ""
      @path  = "Graphics/Pictures/Storage/"
      @path  = "Graphics/UI/Storage/" if pbVersion21?
    end
    @multi = false
    @handsprite.addBitmap("point1g", @path + "cursor_point_1_g")
    @handsprite.addBitmap("point2g", @path + "cursor_point_2_g")
    @handsprite.addBitmap("grabg", @path + "cursor_grab_g")
    @handsprite.addBitmap("fistg", @path + "cursor_fist_g")
  end
 
  #===============================================================================
  # update Override (v20)
  #===============================================================================
  def update
    @updating = true
    super
    return update_21 if pbVersion21?
    heldpkmn = heldPokemon
    heldpkmn&.update
    @handsprite.update
    @holding = false if !heldpkmn
    t = @tension
    b = @multi ? "g" : (@quickswap ? "q" : "")
    if @grabbingState > 0
      if @grabbingState <= 4 * Graphics.frame_rate / 20
        @handsprite.changeBitmap("grab" + b)
        self.y = @spriteY + (4.0 * @grabbingState * 20 / Graphics.frame_rate)
        @grabbingState += 1
      elsif @grabbingState <= 8 * Graphics.frame_rate / 20
        @holding = true
        @handsprite.changeBitmap("fist" + b)
        self.y = @spriteY + (4 * ((8 * Graphics.frame_rate / 20) - @grabbingState) * 20 / Graphics.frame_rate)
        @grabbingState += 1
      else
        @grabbingState = 0
      end
    elsif @placingState > 0
      if @placingState <= 4 * Graphics.frame_rate / 20
        @handsprite.changeBitmap("fist" + b)
        self.y = @spriteY + (4.0 * @placingState * 20 / Graphics.frame_rate)
        @placingState += 1
      elsif @placingState <= 8 * Graphics.frame_rate / 20
        @holding = false
        @heldpkmn = nil
        @handsprite.changeBitmap("grab" + b)
        self.y = @spriteY + (4 * ((8 * Graphics.frame_rate / 20) - @placingState) * 20 / Graphics.frame_rate)
        @placingState += 1
      else
        @placingState = 0
      end
    elsif holding?
      @handsprite.changeBitmap("fist" + b)
    elsif t == :Selecting
      @handsprite.changeBitmap("grab" + b)
    elsif t == :Moving
      @handsprite.changeBitmap("fist" + b)
    else   # Idling
      self.x = @spriteX
      self.y = @spriteY
      if @frame < Graphics.frame_rate / 2
        @handsprite.changeBitmap("point1" + b)
      else
        @handsprite.changeBitmap("point2" + b)
      end
    end
    @frame += 1
    @frame = 0 if @frame >= Graphics.frame_rate
    @updating = false
  end
 
  #===============================================================================
  # update Override (v21)
  #===============================================================================
  def update_21
    heldpkmn = heldPokemon
    heldpkmn&.update
    @handsprite.update
    @holding = false if !heldpkmn
    t = @tension
    b = @multi ? "g" : (@quickswap ? "q" : "")
    if @grabbing_timer_start
      if System.uptime - @grabbing_timer_start <= GRAB_TIME / 2
        @handsprite.changeBitmap("grab" + b)
        self.y = @spriteY + lerp(0, 16, GRAB_TIME / 2, @grabbing_timer_start, System.uptime)
      else
        @holding = true
        @handsprite.changeBitmap("fist" + b)
        delta_y = lerp(16, 0, GRAB_TIME / 2, @grabbing_timer_start + (GRAB_TIME / 2), System.uptime)
        self.y = @spriteY + delta_y
        @grabbing_timer_start = nil if delta_y == 0
      end
    elsif @placing_timer_start
      if System.uptime - @placing_timer_start <= GRAB_TIME / 2
        @handsprite.changeBitmap("fist" + b)
        self.y = @spriteY + lerp(0, 16, GRAB_TIME / 2, @placing_timer_start, System.uptime)
      else
        @holding = false
        @heldpkmn = nil
        @handsprite.changeBitmap("grab" + b)
        delta_y = lerp(16, 0, GRAB_TIME / 2, @placing_timer_start + (GRAB_TIME / 2), System.uptime)
        self.y = @spriteY + delta_y
        @placing_timer_start = nil if delta_y == 0
      end
    elsif holding?
      @handsprite.changeBitmap("fist" + b)
    elsif t == :Selecting
      @handsprite.changeBitmap("grab" + b)
    elsif t == :Moving
      @handsprite.changeBitmap("fist" + b)
    else   # Idling
      self.x = @spriteX
      self.y = @spriteY
      if (System.uptime / 0.5).to_i.even?   # Changes every 0.5 seconds
        @handsprite.changeBitmap("point1" + b)
      else
        @handsprite.changeBitmap("point2" + b)
      end
    end
    @updating = false
  end
 
  #===============================================================================
  # Additional methods: Tension
  # Used For Multiple Grabbing
  #===============================================================================
  def set_tension
    @tension = :Selecting # 1
  end
 
  def start_tension
    @tension = :Moving # 2
  end
 
  def release_tension
    @tension = :None # 0
  end
end

#===============================================================================
# PokemonStorageScene Override
#===============================================================================
class PokemonStorageScene
  attr_reader :multi
 
  #===============================================================================
  # pbStartBox Addition
  #===============================================================================
  alias swdfm_start_box pbStartBox
  def pbStartBox(*args)
    @grabber = StorageGrabber.new
    swdfm_start_box(*args)
  end
 
  #===============================================================================
  # pbSetArrow Addition
  #===============================================================================
  alias swdfm_set_arrow pbSetArrow
  def pbSetArrow(arrow, selection)
    swdfm_set_arrow(arrow, selection)
    return unless selection >= 0
    t = @multi && @grabber.holding_anything? && !@grabber.carrying
    return unless t
    @grabber.do_with(selection)
    do_green
  end
 
  #===============================================================================
  # pbChangeSelection Addition
  #===============================================================================
  alias swdfm_change_sel pbChangeSelection
  def pbChangeSelection(key, selection)
    skip = @multi && @grabber.holding_anything? && !@grabber.carrying
    case key
    when Input::UP
      case selection
      when -1   # Box name
        selection = -2
      when -2   # Party
        selection = PokemonBox::BOX_SIZE - 1 - (PokemonBox::BOX_WIDTH * 2 / 3)   # 25
      when -3   # Close Box
        selection = PokemonBox::BOX_SIZE - (PokemonBox::BOX_WIDTH / 3)   # 28
      else
        selection -= PokemonBox::BOX_WIDTH
        if skip && selection < 0
          selection += PokemonBox::BOX_SIZE
        elsif selection < 0
          selection = -1
        end
      end
    when Input::DOWN
      case selection
      when -1   # Box name
        selection = PokemonBox::BOX_WIDTH / 3   # 2
      when -2   # Party
        selection = -1
      when -3   # Close Box
        selection = -1
      else
        selection += PokemonBox::BOX_WIDTH
        if skip && selection >= PokemonBox::BOX_SIZE
          selection -= PokemonBox::BOX_SIZE
        elsif selection >= PokemonBox::BOX_SIZE
          if selection < PokemonBox::BOX_SIZE + (PokemonBox::BOX_WIDTH / 2)
            selection = -2   # Party
          else
            selection = -3   # Close Box
          end
        end
      end
    when Input::LEFT, Input::RIGHT
      selection = swdfm_change_sel(key, selection)
    end
    return selection
  end

  #===============================================================================
  # pbSelectBoxInternal Override
  #===============================================================================
  def pbSelectBoxInternal(_party)
    selection = @selection
    pbSetArrow(@sprites["arrow"], selection)
    pbUpdateOverlay(selection)
    pbSetMosaic(selection)
    loop do
      Graphics.update
      Input.update
      key = -1
      key = Input::DOWN if Input.repeat?(Input::DOWN)
      key = Input::RIGHT if Input.repeat?(Input::RIGHT)
      key = Input::LEFT if Input.repeat?(Input::LEFT)
      key = Input::UP if Input.repeat?(Input::UP)
      if key >= 0
        pbPlayCursorSE
        selection = pbChangeSelection(key, selection)
        pbSetArrow(@sprites["arrow"], selection)
        case selection
        when -4
          nextbox = (@storage.currentBox + @storage.maxBoxes - 1) % @storage.maxBoxes
          pbSwitchBoxToLeft(nextbox)
          @storage.currentBox = nextbox
        when -5
          nextbox = (@storage.currentBox + 1) % @storage.maxBoxes
          pbSwitchBoxToRight(nextbox)
          @storage.currentBox = nextbox
        end
        selection = -1 if [-4, -5].include?(selection)
        pbUpdateOverlay(selection)
        pbSetMosaic(selection)
      end
      self.update
      t = @grabber.holding_anything? && !@grabber.carrying
      if Input.trigger?(Input::JUMPUP) && !t
        pbPlayCursorSE
        nextbox = (@storage.currentBox + @storage.maxBoxes - 1) % @storage.maxBoxes
        pbSwitchBoxToLeft(nextbox)
        @storage.currentBox = nextbox
        pbUpdateOverlay(selection)
        pbSetMosaic(selection)
      elsif Input.trigger?(Input::JUMPDOWN) && !t
        pbPlayCursorSE
        nextbox = (@storage.currentBox + 1) % @storage.maxBoxes
        pbSwitchBoxToRight(nextbox)
        @storage.currentBox = nextbox
        pbUpdateOverlay(selection)
        pbSetMosaic(selection)
      elsif Input.trigger?(Input::SPECIAL) && !t   # Jump to box name
        if selection != -1
          pbPlayCursorSE
          selection = -1
          pbSetArrow(@sprites["arrow"], selection)
          pbUpdateOverlay(selection)
          pbSetMosaic(selection)
        end
      elsif Input.trigger?(Input::ACTION) && @command == 0   # Organize only
        if !t && !@grabber.carrying
          pbPlayDecisionSE
          pbSetQuickSwap(!@quickswap)
        elsif @grabber.carrying && CAN_MASS_RELEASE
          pbMassRelease
        end
      elsif Input.trigger?(Input::BACK)
        @selection = selection
        return nil
      elsif Input.trigger?(Input::USE)
        @selection = selection
        if selection >= 0
          return [@storage.currentBox, selection]
        elsif selection == -1   # Box name
          return [-4, -1]
        elsif selection == -2   # Party Pokémon         
          return [-2, -1] if !@multi
          pbMassRelease if @grabber.carrying && @multi
        elsif selection == -3   # Close Box
          return [-3, -1]
        end
      end
    end
  end

  #===============================================================================
  # pbSelectPartyInternal Override
  #===============================================================================
  def pbSelectPartyInternal(party, depositing)
    selection = @selection
    pbPartySetArrow(@sprites["arrow"], selection)
    pbUpdateOverlay(selection, party)
    pbSetMosaic(selection)
    lastsel = 1
    loop do
      Graphics.update
      Input.update
      key = -1
      key = Input::DOWN if Input.repeat?(Input::DOWN)
      key = Input::RIGHT if Input.repeat?(Input::RIGHT)
      key = Input::LEFT if Input.repeat?(Input::LEFT)
      key = Input::UP if Input.repeat?(Input::UP)
      if key >= 0
        pbPlayCursorSE
        newselection = pbPartyChangeSelection(key, selection)
        case newselection
        when -1
          return -1 if !depositing
        when -2
          selection = lastsel
        else
          selection = newselection
        end
        pbPartySetArrow(@sprites["arrow"], selection)
        lastsel = selection if selection > 0
        pbUpdateOverlay(selection, party)
        pbSetMosaic(selection)
      end
      self.update
      if Input.trigger?(Input::ACTION) && @command == 0   # Organize only
        pbPlayDecisionSE
        pbSetQuickSwap(!@quickswap, true)
      elsif Input.trigger?(Input::BACK)
        @selection = selection
        return -1
      elsif Input.trigger?(Input::USE)
        if selection >= 0 && selection < Settings::MAX_PARTY_SIZE
          @selection = selection
          return selection
        elsif selection == Settings::MAX_PARTY_SIZE   # Close Box
          @selection = selection
          return (depositing) ? -3 : -1
        end
      end
    end
  end
 
  #===============================================================================
  # New Method To Swap Boxes
  #===============================================================================
  def pbSwapBoxes(newbox)
    return if @storage.currentBox == newbox
    @storage.swap(newbox, @storage.currentBox)
    @sprites["box"].update
    refresh_box_sprites
  end
 
  #===============================================================================
  # pbSetQuickSwap Override
  #===============================================================================
  def pbSetQuickSwap(value, ignore_multi = false)
    ignore_multi = true if !CAN_MULTI_SELECT
    #mod me
    # Set to Quickswap
    if @screen.pbHeldPokemon
     if !@quickswap
      @quickswap = true
     else
      @quickswap = false
     end
    else
     if !@quickswap && !@multi
      @quickswap = true
      @multi     = false
     elsif @quickswap && !@multi && !ignore_multi
      @quickswap = false
      @multi     = true
    # Set to white
     else
      @quickswap = false
      @multi     = false
     end
    end
    @sprites["arrow"].quickswap = @quickswap
    @sprites["arrow"].multi = @multi
  end
 
  #===============================================================================
  # pbChooseBox
  #===============================================================================
  def pbChooseBox(msg, swapping = false)
    commands = []
    @storage.maxBoxes.times do |i|
      box = @storage[i]
      if box
        if swapping  && i == @storage.currentBox
          commands.push("Don't Swap")
          next
        end
        commands.push(_INTL("{1} ({2}/{3})", box.name, box.nitems, box.length))
      end
    end
    return pbShowCommands(msg, commands, @storage.currentBox)
  end

  def pbUpdateOverlay(selection, party = nil)
    overlay = @sprites["overlay"].bitmap
    overlay.clear
    buttonbase = Color.new(248, 248, 248)
    buttonshadow = Color.new(80, 80, 80)
    if @grabber.carrying
      pbDrawTextPositions(
        overlay,
        [[_INTL("Release All"), 270, 334, 2, buttonbase, buttonshadow, 1],
         [_INTL("Exit"), 446, 334, 2, buttonbase, buttonshadow, 1]]
      )
      else
      pbDrawTextPositions(
        overlay,
        [[_INTL("Party: {1}", (@storage.party.length rescue 0)), 270, 334, 2, buttonbase, buttonshadow, 1],
         [_INTL("Exit"), 446, 334, 2, buttonbase, buttonshadow, 1]]
      )
      end
    pokemon = nil
    if @screen.pbHeldPokemon
      pokemon = @screen.pbHeldPokemon
    elsif selection >= 0
      pokemon = (party) ? party[selection] : @storage[@storage.currentBox, selection]
    end
    if !pokemon
      @sprites["pokemon"].visible = false
      return
    end
    @sprites["pokemon"].visible = true
    base   = Color.new(88, 88, 80)
    shadow = Color.new(168, 184, 184)
    nonbase   = Color.new(208, 208, 208)
    nonshadow = Color.new(224, 224, 224)
    pokename = pokemon.name
    textstrings = [
      [pokename, 10, 14, false, base, shadow]
    ]
    if !pokemon.egg?
      imagepos = []
      if pokemon.male?
        textstrings.push([_INTL("♂"), 148, 14, false, Color.new(24, 112, 216), Color.new(136, 168, 208)])
      elsif pokemon.female?
        textstrings.push([_INTL("♀"), 148, 14, false, Color.new(248, 56, 32), Color.new(224, 152, 144)])
      end
      imagepos.push(["Graphics/Pictures/Storage/overlay_lv", 6, 246])
      textstrings.push([pokemon.level.to_s, 28, 240, false, base, shadow])
      if pokemon.ability
        textstrings.push([pokemon.ability.name, 86, 312, 2, base, shadow])
      else
        textstrings.push([_INTL("No ability"), 86, 312, 2, nonbase, nonshadow])
      end
      if pokemon.item
        textstrings.push([pokemon.item.name, 86, 348, 2, base, shadow])
      else
        textstrings.push([_INTL("No item"), 86, 348, 2, nonbase, nonshadow])
      end
      if pokemon.shiny?
        imagepos.push(["Graphics/Pictures/shiny", 156, 198])
      end
      typebitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/types"))
      pokemon.types.each_with_index do |type, i|
        type_number = GameData::Type.get(type).icon_position
        type_rect = Rect.new(0, type_number * 28, 64, 28)
        type_x = (pokemon.types.length == 1) ? 52 : 18 + (70 * i)
        overlay.blt(type_x, 272, typebitmap.bitmap, type_rect)
      end
      drawMarkings(overlay, 70, 240, 128, 20, pokemon.markings)
      pbDrawImagePositions(overlay, imagepos)
    end
    pbDrawTextPositions(overlay, textstrings)
    @sprites["pokemon"].setPokemonBitmap(pokemon)
  end
 
  #===============================================================================
  # Additional methods
  #=============================================================================== 
  # Tension: Used For Multiple Grabbing
  #===============================================================================
  def grabber
    return @grabber
  end
 
  def set_tension
    @sprites["arrow"].set_tension
  end
 
  def start_tension
    @sprites["arrow"].start_tension
  end
 
  def release_tension
    @sprites["arrow"].release_tension
  end
 
  #===============================================================================
  # Sets all necessary sprites to green
  #===============================================================================
  def do_green
    piv   = @grabber.mock_pivot
    piv_x = piv % PokemonBox::BOX_WIDTH
    piv_y = (piv / PokemonBox::BOX_WIDTH).floor
    sels = []
    for i in @grabber.mons
      x = i[0] + piv_x
      y = i[1] + piv_y
      sel = x + PokemonBox::BOX_WIDTH * y
      sels.push(sel)
    end
    for i in 0...PokemonBox::BOX_SIZE
      boxpokesprite = @sprites["box"].getPokemon(i)
      if sels.include?(i)
        boxpokesprite.make_green
      else
        boxpokesprite.make_clear
      end
    end
  end
 
  #===============================================================================
  # Method to refresh all box sprites
  #===============================================================================
  def refresh_box_sprites
    @sprites["box"].refreshSprites = true
    @sprites["box"].refreshBox = true
    pbHardRefresh
  end
 
  #===============================================================================
  # Changes from wherever the anchor is to the top left of the selection
  #===============================================================================
  def quick_change(selection)
    pbSetArrow(@sprites["arrow"], selection)
    pbUpdateOverlay(selection)
    pbSetMosaic(selection)
    @selection = selection
  end
 
  #===============================================================================
  # Shortcut to mass release
  #===============================================================================
  def pbMassRelease
    @screen.pbMassRelease
  end
 
  #===============================================================================
  # Greys all necessary sprites
  #===============================================================================
  def do_greys(ableProc = nil)
    return if !ableProc
    for i in 0...(PokemonBox::BOX_SIZE + PokemonBox::BOX_WIDTH)
      if i < PokemonBox::BOX_SIZE
        boxpokesprite = @sprites["box"].getPokemon(i)
      else
        boxpokesprite = @sprites["boxparty"].getPokemon(i-30)
      end
      next if !boxpokesprite
      next if !boxpokesprite.getPokemon
      if ableProc.call(boxpokesprite.getPokemon)
        boxpokesprite.make_clear
      else
        boxpokesprite.make_grey
      end
    end
  end
end

#===============================================================================
# PokemonStorageScreen Override
#===============================================================================
class PokemonStorageScreen
  #===============================================================================
  # pbStartScreen Override
  #===============================================================================
  def pbStartScreen(command)
    $game_temp.in_storage = true
    @heldpkmn = nil
    case command
    when 0   # Organise
      @scene.pbStartBox(self, command)
      loop do
        selected = @scene.pbSelectBox(@storage.party)
        if selected.nil?
          if pbHeldPokemon
            pbDisplay(_INTL("You're holding a Pokémon!"))
            next
          elsif @scene.grabber.carrying
            pbDisplay(_INTL("You're holding Pokémon!"))
            next
          end
          next if pbConfirm(_INTL("Continue Box operations?"))
          break
        elsif selected[0] == -3   # Close box
          if pbHeldPokemon
            pbDisplay(_INTL("You're holding a Pokémon!"))
            next
          elsif @scene.grabber.carrying
            pbDisplay(_INTL("You're holding Pokémon!"))
            next
          end
          if pbConfirm(_INTL("Exit from the Box?"))
            pbSEPlay("PC close")
            break
          end
          next
        elsif selected[0] == -4   # Box name
          if @scene.grabber.carrying && CAN_BOX_POUR
            if pbPour(selected)
              @scene.grabber.carrying = false
              @scene.grabber.clear
              @scene.release_tension
            end
          else
            pbBoxCommands
          end
        else
          pokemon = @storage[selected[0], selected[1]]
          heldpoke = pbHeldPokemon
          next if !pokemon && !heldpoke && !@scene.grabber.carrying
          if @scene.quickswap
            if @heldpkmn
              (pokemon) ? pbSwap(selected) : pbPlace(selected)
            else
              pbHold(selected)
            end
          elsif @scene.multi
            if !@scene.grabber.carrying
              if @scene.grabber.holding_anything?
                @scene.grabber.carrying = true
                # Gathers held mons data in @carried_mons in the grabber
                @scene.grabber.pack_up(@storage, selected[0])
                # Deletes mon off storage
                pbHold_Multi(selected)
                @scene.start_tension
                # Moves the hand to mock pivot position
                @scene.quick_change(@scene.grabber.mock_pivot)
                selected[1] = @scene.grabber.mock_pivot
              else
                # Start tension here
                @scene.grabber.setPivot(selected[1])
                @scene.grabber.do_with(selected[1])
                @scene.do_green
                @scene.set_tension
              end
            else
              # Drop Off If Possible
              if @scene.grabber.place_with_positions(@storage, selected[0], selected[1])
                pbPlace_Multi(selected)
                # @scene.grabber.get_new_carried_mons
                @scene.grabber.carrying = false
                @scene.grabber.clear
                @scene.release_tension
              else
                next
              end
            end
          else
            commands = []
            cmdMove     = -1
            cmdSummary  = -1
            cmdWithdraw = -1
            cmdItem     = -1
            cmdMark     = -1
            cmdRelease  = -1
            cmdDebug    = -1
            if heldpoke
              helptext = _INTL("{1} is selected.", heldpoke.name)
              commands[cmdMove = commands.length] = (pokemon) ? _INTL("Shift") : _INTL("Place")
            elsif pokemon
              helptext = _INTL("{1} is selected.", pokemon.name)
              commands[cmdMove = commands.length] = _INTL("Move")
            end
            commands[cmdSummary = commands.length]  = _INTL("Summary")
            commands[cmdWithdraw = commands.length] = (selected[0] == -1) ? _INTL("Store") : _INTL("Withdraw")
            commands[cmdItem = commands.length]     = _INTL("Item")
            commands[cmdMark = commands.length]     = _INTL("Mark")
            commands[cmdRelease = commands.length]  = _INTL("Release")
            commands[cmdDebug = commands.length]    = _INTL("Debug") if $DEBUG
            commands[commands.length]               = _INTL("Cancel")
            command = pbShowCommands(helptext, commands)
            if cmdMove >= 0 && command == cmdMove   # Move/Shift/Place
              if @heldpkmn
                (pokemon) ? pbSwap(selected) : pbPlace(selected)
              else
                pbHold(selected)
              end
            elsif cmdSummary >= 0 && command == cmdSummary   # Summary
              pbSummary(selected, @heldpkmn)
            elsif cmdWithdraw >= 0 && command == cmdWithdraw   # Store/Withdraw
              (selected[0] == -1) ? pbStore(selected, @heldpkmn) : pbWithdraw(selected, @heldpkmn)
            elsif cmdItem >= 0 && command == cmdItem   # Item
              pbItem(selected, @heldpkmn)
            elsif cmdMark >= 0 && command == cmdMark   # Mark
              pbMark(selected, @heldpkmn)
            elsif cmdRelease >= 0 && command == cmdRelease   # Release
              pbRelease(selected, @heldpkmn)
            elsif cmdDebug >= 0 && command == cmdDebug   # Debug
              pbPokemonDebug((@heldpkmn) ? @heldpkmn : pokemon, selected, heldpoke)
            end
          end
        end
      end
      @scene.pbCloseBox
    when 1   # Withdraw
      @scene.pbStartBox(self, command)
      loop do
        selected = @scene.pbSelectBox(@storage.party)
        if selected.nil?
          next if pbConfirm(_INTL("Continue Box operations?"))
          break
        else
          case selected[0]
          when -2   # Party Pokémon
            pbDisplay(_INTL("Which one will you take?"))
            next
          when -3   # Close box
            if pbConfirm(_INTL("Exit from the Box?"))
              pbSEPlay("PC close")
              break
            end
            next
          when -4   # Box name
            pbBoxCommands
            next
          end
          pokemon = @storage[selected[0], selected[1]]
          next if !pokemon
          command = pbShowCommands(_INTL("{1} is selected.", pokemon.name),
                                   [_INTL("Withdraw"),
                                    _INTL("Summary"),
                                    _INTL("Mark"),
                                    _INTL("Release"),
                                    _INTL("Cancel")])
          case command
          when 0 then pbWithdraw(selected, nil)
          when 1 then pbSummary(selected, nil)
          when 2 then pbMark(selected, nil)
          when 3 then pbRelease(selected, nil)
          end
        end
      end
      @scene.pbCloseBox
    when 2   # Deposit
      @scene.pbStartBox(self, command)
      loop do
        selected = @scene.pbSelectParty(@storage.party)
        if selected == -3   # Close box
          if pbConfirm(_INTL("Exit from the Box?"))
            pbSEPlay("PC close")
            break
          end
          next
        elsif selected < 0
          next if pbConfirm(_INTL("Continue Box operations?"))
          break
        else
          pokemon = @storage[-1, selected]
          next if !pokemon
          command = pbShowCommands(_INTL("{1} is selected.", pokemon.name),
                                   [_INTL("Store"),
                                    _INTL("Summary"),
                                    _INTL("Mark"),
                                    _INTL("Release"),
                                    _INTL("Cancel")])
          case command
          when 0 then pbStore([-1, selected], nil)
          when 1 then pbSummary([-1, selected], nil)
          when 2 then pbMark([-1, selected], nil)
          when 3 then pbRelease([-1, selected], nil)
          end
        end
      end
      @scene.pbCloseBox
    when 3
      @scene.pbStartBox(self, command)
      @scene.pbCloseBox
    end
    $game_temp.in_storage = false
  end
 
  #===============================================================================
  # pbBoxCommands Override
  #===============================================================================
  def pbBoxCommands
    c_consts = [:JUMP]
    c_consts.push(:SWAP) if CAN_SWAP_BOXES
    c_consts.push(:WALL, :NAME, :CANCEL)
    commands = [
      _INTL("Jump")
    ]
    commands.push(_INTL("Swap")) if CAN_SWAP_BOXES
    commands.push(
      _INTL("Wallpaper"),
      _INTL("Name"),
      _INTL("Cancel")
    )
    command = pbShowCommands(_INTL("What do you want to do?"), commands)
    case c_consts[command]
    when :JUMP
      destbox = @scene.pbChooseBox(_INTL("Jump to which Box?"))
      @scene.pbJumpToBox(destbox) if destbox >= 0
    when :SWAP
      destbox = @scene.pbChooseBox(_INTL("Swap with which Box?"), true)
      @scene.pbSwapBoxes(destbox) if destbox >= 0
    when :WALL
      papers = @storage.availableWallpapers
      index = 0
      papers[1].length.times do |i|
        if papers[1][i] == @storage[@storage.currentBox].background
          index = i
          break
        end
      end
      wpaper = pbShowCommands(_INTL("Pick the wallpaper."), papers[0], index)
      @scene.pbChangeBackground(papers[1][wpaper]) if wpaper >= 0
    when :NAME
      @scene.pbBoxName(_INTL("Box name?"), 0, 12)
    end
  end
 
  #===============================================================================
  # ***Additional methods***
  #===============================================================================
  def pbHold_Multi(selected)
    box, index = selected
    if box == -1 && pbAble?(@storage[box, index]) && pbAbleCount <= 1
      pbPlayBuzzerSE
      pbDisplay(_INTL("That's your last Pokémon!"))
      return
    end
    for i in @scene.grabber.get_carried_mons
      @storage.pbDelete(box, i)
    end
    index = @scene.grabber.get_carried_mons[0]
    @heldpkmn = @storage[box, index]
    @scene.refresh_box_sprites
    @scene.pbRefresh
  end
 
  def pbPlace_Multi(selected)
    box, index = selected
    for i in @scene.grabber.get_new_carried_mons(index)
      this_index = i[0]
      if @storage[box, this_index]
        raise _INTL("Position {1}, {2} is not empty...", box, this_index)
      end
      if box != -1 && this_index >= @storage.maxPokemon(box)
        pbDisplay("Can't place that there.")
        return
      end
      this_pkmn = i[1]
      if box >= 0 && this_pkmn
        this_pkmn.formTime = nil if this_pkmn.respond_to?("formTime")
        this_pkmn.form     = 0 if this_pkmn.isSpecies?(:SHAYMIN)
        this_pkmn.heal
      end
      @storage[box,this_index] = this_pkmn
      if box==-1
        @storage.party.compact!
      end
    end
    @scene.refresh_box_sprites
    @scene.pbRefresh
    @heldpkmn = nil
  end
 
  #===============================================================================
  # Puts all held Pokemon into available slots in a box
  #===============================================================================
  def pbPour(selected)
    box = @storage.currentBox
    mons_to_place = @scene.grabber.carried_mons.clone
    for m in 0...mons_to_place.size do mons_to_place[m] = nil if mons_to_place[m][0].nil?; end #TXW Added to ignor blanks in the group
    count = 0
    for i in 0...PokemonBox::BOX_SIZE
      next if @storage[box, i]
      m_t_p = mons_to_place.shift
      @storage[box, i] = m_t_p[0]
      count += 1
      break if mons_to_place.empty?
    end
    emptied = mons_to_place.empty?
    @scene.grabber.pour(count)
    @scene.refresh_box_sprites
    @scene.pbRefresh
    pbSEPlay("GUI storage put down") if emptied TXW Added for audio consistancy
    @heldpkmn = nil if emptied
    return emptied
  end
 
  #===============================================================================
  # Releases all held Pokemon
  #===============================================================================
  def pbMassRelease
    if @scene.grabber.contains_an_egg?
      pbDisplay(_INTL("You can't release an Egg!"))
      return false
    end
    # NOTE: No need to stop if last mon because this cannot be done in party!
    command = pbShowCommands(_INTL("Release these Pokémon?"), [_INTL("No"), _INTL("Yes")])
    return unless command == 1
    @scene.grabber.clear
    @scene.pbRefresh
    pbDisplay(_INTL("The Pokémon were released."))
    pbDisplay(_INTL("Bye-bye, Pokémon!"))
    @scene.pbRefresh
    @scene.grabber.carrying = false
    @scene.release_tension
  end
end

class PokemonStorage
  def pbUnlockBox(amount=1,maxPokemon=30)
    amount+=@boxes.length
    for i in @boxes.length...amount
      ip1=i+1
      @boxes[i]=PokemonBox.new(_ISPRINTF("Box {1:d}",ip1),maxPokemon)
      backid=i%40
      @boxes[i].background="box#{backid}"
    end
  end
end

def pbTrainerPCMenu
  command = 0
    loop do
    if $PokemonStorage.boxes.length >= 79
      command = pbMessage(_INTL("What do you want to do?"),[_INTL("Item Storage"),_INTL("Mailbox"),_INTL("Turn Off")], -1, nil, command)
    else
      command = pbMessage(_INTL("What do you want to do?"),[_INTL("Item Storage"),_INTL("Mailbox"),_INTL("Add 5 Boxes"),_INTL("Turn Off")], -1, nil, command)
    end
     case command
     when 0 then pbPCItemStorage
     when 1 then pbPCMailbox
     when 2
      if $PokemonStorage.boxes.length <= 79
       $PokemonStorage.pbUnlockBox(5)
      else
        break
      end
      else        break
   end
  end
end

Ruby:
#===============================================================================
# Storage Grabber
# By Swdfm
# Used For Storage Utilities
#===============================================================================
class StorageGrabber
  def initialize
    clear
  end
 
  #===============================================================================
  # Adds hovered over pokemon to held pokemon
  #===============================================================================
  def add_to(position, position_1)
    @mons.push([position, position_1])
  end

  #===============================================================================
  # Is the grabber holding a Pokemon?
  #===============================================================================
  def holding_anything?
    return !@mons.empty?
  end
 
  #===============================================================================
  # Sets the pivot (top left Pokemon)
  #===============================================================================
  def setPivot(selection)
    @pivot      = selection
    @mock_pivot = selection
  end
 
  #===============================================================================
  # Begins hovering phase
  #===============================================================================
  def do_with(selection)
    p_col = @pivot % PokemonBox::BOX_WIDTH
    p_row = (@pivot / PokemonBox::BOX_WIDTH).floor
    s_col = selection % PokemonBox::BOX_WIDTH
    s_row = (selection / PokemonBox::BOX_WIDTH).floor
    @mons = []
    f_row = [p_row, s_row].min # F stands for flow
    f_col = [p_col, s_col].min
    @mock_pivot = f_col + f_row * PokemonBox::BOX_WIDTH
    for i in 0...PokemonBox::BOX_WIDTH
      next if (i < p_col && i < s_col) || (i > p_col && i > s_col)
      for j in 0...PokemonBox::BOX_HEIGHT
        next if (j < p_row && j < s_row) || (j > p_row && j > s_row)
        add_to(i - f_col,  j - f_row)
      end
    end
  end
 
  #===============================================================================
  # Is the grabber carrying?
  #===============================================================================
  def carrying
    return @carrying
  end
 
  def carrying=(value)
    @carrying = value
  end
 
  #===============================================================================
  # Adds Pokémon and their positions (relative to top left) to @carried_mons
  #===============================================================================
  def pack_up(storage, box_num)
    ret   = []
    p_col = @mock_pivot % PokemonBox::BOX_WIDTH
    p_row = (@mock_pivot / PokemonBox::BOX_WIDTH).floor
    for i in @mons
      x, y = i
      sel  = (p_row + y) * PokemonBox::BOX_WIDTH + (p_col + x)
      pkmn = storage[box_num, sel]
      ret.push([pkmn, x, y])
    end
    @carried_mons = ret
  end
 
  #===============================================================================
  # Gets storage index of carried mons for deletion
  #===============================================================================
  def get_carried_mons
    ret   = []
    p_col = @mock_pivot % PokemonBox::BOX_WIDTH
    p_row = (@mock_pivot / PokemonBox::BOX_WIDTH).floor
    for i in @carried_mons
      x = i[1] + p_col
      y = i[2] + p_row
      ret.push(y * PokemonBox::BOX_WIDTH + x)
    end
    return ret
  end
 
  #===============================================================================
  # Places mons in those positions
  # STOPS IF THERE IS NOT A SPACE FOR EVERY MON
  #===============================================================================
  def place_with_positions(storage, box_num, selection)
    s_col = selection % PokemonBox::BOX_WIDTH
    s_row = (selection / PokemonBox::BOX_WIDTH).floor
    can_place = true
    for i in @carried_mons
      col = s_col + i[1]
      if col >= PokemonBox::BOX_WIDTH
        can_place = false
        next
      end
      row = s_row + i[2]
      if row >= PokemonBox::BOX_HEIGHT
        can_place = false
        next
      end
      pseudo_sel = row * PokemonBox::BOX_WIDTH + col
      can_place = false if storage[box_num, pseudo_sel] # Occupied
    end
    return can_place
  end
 
  #===============================================================================
  # Gets index number of mons proposed to be put in boxes in above def.
  #===============================================================================
  def get_new_carried_mons(selection)
    ret   = []
    s_col = selection % PokemonBox::BOX_WIDTH
    s_row = (selection / PokemonBox::BOX_WIDTH).floor
    for i in @carried_mons
      col = s_col + i[1]
      row = s_row + i[2]
      pseudo_sel = row * PokemonBox::BOX_WIDTH + col
      ret.push([pseudo_sel, i[0]])
    end
    return ret
  end
 
  #===============================================================================
  # Removes any poured Pokemon
  #===============================================================================
  def pour(count)
    return if count == 0
    to_del = get_new_carried_mons(0)
    to_del = to_del.sort{ |a, b| a[0] <=> b[0] }
    ret = @carried_mons.clone
    count.times do
      ret.pop
    end
    @carried_mons = ret
  end
 
  #===============================================================================
  # Clears everything
  #===============================================================================
  def clear
    @mons         = []
    @pivot        = nil
    @mock_pivot   = nil
    @carrying     = false
    @carried_mons = []
  end
 
  #===============================================================================
  # Utilities
  #===============================================================================
  def mons
    return @mons
  end
 
  def mock_pivot
    return @mock_pivot
  end
 
  def contains_an_egg?
    for i in @carried_mons
     if i[0] != nil
      return true if i[0].egg?
     end
    end
    return false
  end
 
  def carried_mons
    return @carried_mons
  end
end

#===============================================================================
# PokemonStorage override
#===============================================================================
class PokemonStorage
  def swap(one, two)
    t = @boxes[one]
    @boxes[one] = @boxes[two]
    @boxes[two] = t
  end
end
 
Back
Top