#=============================================================================== # The Bag object, which actually contains all the items. #=============================================================================== class PokemonBag attr_reader :pockets attr_accessor :last_viewed_pocket attr_accessor :last_pocket_selections attr_reader :registered_items attr_reader :ready_menu_selection def self.pocket_names return Settings.bag_pocket_names end def self.pocket_count return self.pocket_names.length end def initialize @pockets = [] (0..PokemonBag.pocket_count).each { |i| @pockets[i] = [] } reset_last_selections @registered_items = [] @ready_menu_selection = [0, 0, 1] # Used by the Ready Menu to remember cursor positions end def reset_last_selections @last_viewed_pocket = 1 @last_pocket_selections ||= [] (0..PokemonBag.pocket_count).each { |i| @last_pocket_selections[i] = 0 } end def clear @pockets.each { |pocket| pocket.clear } (PokemonBag.pocket_count + 1).times { |i| @last_pocket_selections[i] = 0 } end #----------------------------------------------------------------------------- # Gets the index of the current selected item in the pocket def last_viewed_index(pocket) if pocket <= 0 || pocket > PokemonBag.pocket_count raise ArgumentError.new(_INTL("Invalid pocket: {1}", pocket.inspect)) end return [@last_pocket_selections[pocket], @pockets[pocket].length].min || 0 end # Sets the index of the current selected item in the pocket def set_last_viewed_index(pocket, value) if pocket <= 0 || pocket > PokemonBag.pocket_count raise ArgumentError.new(_INTL("Invalid pocket: {1}", pocket.inspect)) end @last_pocket_selections[pocket] = value if value <= @pockets[pocket].length end #----------------------------------------------------------------------------- def quantity(item) item_data = GameData::Item.try_get(item) return 0 if !item_data pocket = item_data.pocket return ItemStorageHelper.quantity(@pockets[pocket], item_data.id) end def has?(item, qty = 1) return quantity(item) >= qty end alias can_remove? has? def can_add?(item, qty = 1) item_data = GameData::Item.try_get(item) return false if !item_data pocket = item_data.pocket max_size = max_pocket_size(pocket) max_size = @pockets[pocket].length + 1 if max_size < 0 # Infinite size return ItemStorageHelper.can_add?( @pockets[pocket], max_size, Settings::BAG_MAX_PER_SLOT, item_data.id, qty ) end def add(item, qty = 1) item_data = GameData::Item.try_get(item) return false if !item_data pocket = item_data.pocket max_size = max_pocket_size(pocket) max_size = @pockets[pocket].length + 1 if max_size < 0 # Infinite size ret = ItemStorageHelper.add(@pockets[pocket], max_size, Settings::BAG_MAX_PER_SLOT, item_data.id, qty) if ret && Settings::BAG_POCKET_AUTO_SORT[pocket - 1] @pockets[pocket].sort! { |a, b| GameData::Item.keys.index(a[0]) <=> GameData::Item.keys.index(b[0]) } end return ret end # Adds qty number of item. Doesn't add anything if it can't add all of them. def add_all(item, qty = 1) return false if !can_add?(item, qty) return add(item, qty) end # Deletes as many of item as possible (up to qty), and returns whether it # managed to delete qty of them. def remove(item, qty = 1) item_data = GameData::Item.try_get(item) return false if !item_data pocket = item_data.pocket return ItemStorageHelper.remove(@pockets[pocket], item_data.id, qty) end # Deletes qty number of item. Doesn't delete anything if there are less than # qty of the item in the Bag. def remove_all(item, qty = 1) return false if !can_remove?(item, qty) return remove(item, qty) end # This only works if the old and new items are in the same pocket. Used for # switching on/off certain Key Items. Replaces all old_item in its pocket with # new_item. def replace_item(old_item, new_item) old_item_data = GameData::Item.try_get(old_item) new_item_data = GameData::Item.try_get(new_item) return false if !old_item_data || !new_item_data pocket = old_item_data.pocket old_id = old_item_data.id new_id = new_item_data.id ret = false @pockets[pocket].each do |item| next if !item || item[0] != old_id item[0] = new_id ret = true end return ret end #----------------------------------------------------------------------------- # Returns whether item has been registered for quick access in the Ready Menu. def registered?(item) item_data = GameData::Item.try_get(item) return false if !item_data return @registered_items.include?(item_data.id) end # Registers the item in the Ready Menu. def register(item) item_data = GameData::Item.try_get(item) return if !item_data @registered_items.push(item_data.id) if !@registered_items.include?(item_data.id) end # Unregisters the item from the Ready Menu. def unregister(item) item_data = GameData::Item.try_get(item) @registered_items.delete(item_data.id) if item_data end #----------------------------------------------------------------------------- private def max_pocket_size(pocket) return Settings::BAG_MAX_POCKET_SIZE[pocket - 1] || -1 end end #=============================================================================== # The PC item storage object, which actually contains all the items. #=============================================================================== class PCItemStorage attr_reader :items MAX_SIZE = 999 # Number of different slots in storage MAX_PER_SLOT = 999 # Max. number of items per slot def initialize @items = [] # Start storage with initial items (e.g. a Potion) GameData::Metadata.get.start_item_storage.each do |item| add(item) if GameData::Item.exists?(item) end end def [](i) return @items[i] end def length return @items.length end def empty? return @items.length == 0 end def clear @items.clear end # Unused def get_item(index) return (index < 0 || index >= @items.length) ? nil : @items[index][0] end # Number of the item in the given index # Unused def get_item_count(index) return (index < 0 || index >= @items.length) ? 0 : @items[index][1] end def quantity(item) item = GameData::Item.get(item).id return ItemStorageHelper.quantity(@items, item) end def can_add?(item, qty = 1) item = GameData::Item.get(item).id return ItemStorageHelper.can_add?(@items, MAX_SIZE, MAX_PER_SLOT, item, qty) end def add(item, qty = 1) item = GameData::Item.get(item).id return ItemStorageHelper.add(@items, MAX_SIZE, MAX_PER_SLOT, item, qty) end def remove(item, qty = 1) item = GameData::Item.get(item).id return ItemStorageHelper.remove(@items, item, qty) end end #=============================================================================== # Implements methods that act on arrays of items. Each element in an item array # is itself an array of [itemID, itemCount]. # Used by the Bag, PC item storage, and Triple Triad. #=============================================================================== module ItemStorageHelper module_function # Returns the quantity of item in items. def quantity(items, item) ret = 0 items.each { |i| ret += i[1] if i && i[0] == item } return ret end def can_add?(items, max_slots, max_per_slot, item, qty) raise "Invalid value for qty: #{qty}" if qty < 0 return true if qty == 0 max_slots.times do |i| item_slot = items[i] if !item_slot qty -= [qty, max_per_slot].min return true if qty == 0 elsif item_slot[0] == item && item_slot[1] < max_per_slot new_amt = item_slot[1] new_amt = [new_amt + qty, max_per_slot].min qty -= (new_amt - item_slot[1]) return true if qty == 0 end end return false end def add(items, max_slots, max_per_slot, item, qty) raise "Invalid value for qty: #{qty}" if qty < 0 return true if qty == 0 max_slots.times do |i| item_slot = items[i] if !item_slot items[i] = [item, [qty, max_per_slot].min] qty -= items[i][1] return true if qty == 0 elsif item_slot[0] == item && item_slot[1] < max_per_slot new_amt = item_slot[1] new_amt = [new_amt + qty, max_per_slot].min qty -= (new_amt - item_slot[1]) item_slot[1] = new_amt return true if qty == 0 end end return false end # Deletes an item (items array, max. size per slot, item, no. of items to delete). def remove(items, item, qty) raise "Invalid value for qty: #{qty}" if qty < 0 return true if qty == 0 ret = false items.each_with_index do |item_slot, i| next if !item_slot || item_slot[0] != item amount = [qty, item_slot[1]].min item_slot[1] -= amount qty -= amount items[i] = nil if item_slot[1] == 0 next if qty > 0 ret = true break end items.compact! return ret end end