[XP] Item Storage

Started by G_G, May 01, 2009, 08:50:28 pm

Previous topic - Next topic

G_G

May 01, 2009, 08:50:28 pm Last Edit: July 17, 2012, 10:00:21 pm by game_guy
Item Storage
Authors: game_guy
Version: 1.42
Type: Item Storage
Key Term: Misc System



Introduction

If you've ever played any of the Elder Scrolls series or Fallout series than of
course then you would have noticed the awesome item storage. This script does that


Features


  • Store and Take Items Out of Chests, Closets, ect
  • Have Seperate Chests, Closets, ect
  • Easy to use
  • Stores Chests into Game System Instead of Variables
  • Have Max Amount of Items In Chest
  • Set Default Items in Chest
  • Add/Remove items to chests In Game!
  • Empty inventory into chests
  • Take all items from a chest
  • Mark items as "Key Items" to prevent removal from inventory. (e.g. "Quest Items")



Screenshots

Spoiler: ShowHide
Chest 1

Chest 1 Storage

Chest 2

Chest 2 Storage



Demo

(Outdated!)
MediaFire


Script

Spoiler: ShowHide

#===============================================================================
# Item Storage
# Author game_guy
# Version 1.42
#-------------------------------------------------------------------------------
# Intro:
# Okay. Well if you've played the Elder Scrolls Series or Fallout then you'd
# know that it has an item storage system. What it does is lets you open up
# closets, chests, ect and store and take items out of it.
#
# Features:
# Store and Take Items Out of Chests, Closets, ect
# Have Seperate Chests, Closets, ect
# Easy to Use
# Stores Chests into Game System Instead of Variables
# Have Max Amount of Items In Chest
# Set Default Items in Chest
# Mark Items as "Key Items" to prevent removal from inventory (e.g. "Quest Items")
# Take All/Store All Items in Chest (Not built into scene)
#
# Instructions:
# First lets go over the syntaxes.
#
# Calling the Item Storage:
# $scene = Scene_Chest.new(chest_id, max_items)
# chest_id is the number chest you want open
# max_items is the max amount of any item the chest can hold
# you can just use this to
# $scene = Scene_Chest.new(chest_id)
# because in the config this ChestMaxItems is the default so if you dont use
# the long one, it'll use the default.
#
# New Syntaxes:
# You can now take all items from a chest and empty your entire inventory
# into a chest. While this isn't built into the scene, you'll have to do this
# through a script call.
# -Take All
#   chest = $game_system.chests(chest_id)
#   chest.take_all
# -Empty Inventory
#   chest = $game_system.chests(chest_id)
#   chest.empty_all
#
# You can now add/remove items to and from chests.
#   chest = $game_system.chests(chest_id)
#   chest.aaa_bbb(ccc, ddd)
#   aaa = add/take
#   bbb = item/weapon/armor
#   ccc = item/weapon/armor id
#   ddd = amount
#
# Okay so thats done with the syntaxes. Now onto the configuration.
# Go down to Begin Config and do all your configuration there.
#
# Credits:
# game_guy ~ for making it
# MightyLink ~ requesting the system
#===============================================================================
module GameGuy
  #============================================================================
  # KeyItemId       = Element ID for non removable items.
  #                   Items/weapons/armors with marked with this element
  #                   cannot be removed.
  #============================================================================
  KeyItemId         = 17
  #============================================================================
  # ChestMaxItems   = The max amount of any item a chest can hold. So example
  #                   Its 9999 so it can have 9999 of any item.
  #============================================================================
  ChestMaxItems     = 9999
  def self.chest_items(id)
    case id
    #==========================================================================
    # Config Chest Items
    # Use this
    # when chest_id then return [[id, amount, type], [id, amount, type]]
    # id = item, weapon, or armor id
    # amount = the amount
    # type = 0, 1, or 2 0 = item, 1 = weapon, 2 = armor
    # Example:
    # when 1 then return [[1, 3, 0], [1, 1, 1]]
    # This has 3 potions, and 1 bronze sword. So when this is called
    # $scene = Scene_Chest.new(1)
    # it will have those items in the chest already.
    #==========================================================================
    when 1 then return [[1, 999, 0], [1, 1, 1]]
    when 2 then return [[1, 10, 0], [1, 1, 2], [1, 2, 1]]
    when 3 then return [[1, 10, 2], [3, 1, 1], [9, 1, 1]]
    end
    return []
  end
end

#==============================================================================
# Game_System
#------------------------------------------------------------------------------
# Modded it so it makes it store every chest.
#==============================================================================
class Game_System
  alias gg_add_item_storage initialize
  def initialize
    @chests = []
    return gg_add_item_storage
  end
  def chests(n)
    if @chests[n] == nil
      @chests[n] = Game_Chest.new(GameGuy::ChestMaxItems)
      items = GameGuy.chest_items(n)
      for i in 0...items.size
        item = items[i][2]
        case item
        when 0
          @chests[n].add_item(items[i][0], items[i][1])
        when 1
          @chests[n].add_weapon(items[i][0], items[i][1])
        when 2
          @chests[n].add_armor(items[i][0], items[i][1])
        else
          @chests[n].add_item(items[i][0], items[i][1])
        end
      end
    end
    return @chests[n]
  end
end

#==============================================================================
# Game_Chest
#------------------------------------------------------------------------------
# Holds all the data for a single chest.
#==============================================================================
class Game_Chest
  attr_accessor :max
  def initialize(max = GameGuy::ChestMaxItems)
    @max = max
    @items = {}
    @weapons = {}
    @armors = {}
  end
  def item_amount(item_id)
    return @items.include?(item_id) ? @items[item_id] : 0
  end
  def weapon_amount(weapon_id)
    return @weapons.include?(weapon_id) ? @weapons[weapon_id] : 0
  end
  def armor_amount(armor_id)
    return @armors.include?(armor_id) ? @armors[armor_id] : 0
  end
  def add_item(item_id, n)
    if item_id > 0
      @items[item_id] = [[item_amount(item_id) + n, 0].max, @max].min
    end
  end
  def add_weapon(weapon_id, n)
    if weapon_id > 0
      @weapons[weapon_id] = [[weapon_amount(weapon_id) + n, 0].max, @max].min
    end
  end
  def add_armor(armor_id, n)
    if armor_id > 0
      @armors[armor_id] = [[armor_amount(armor_id) + n, 0].max, @max].min
    end
  end
  def take_item(item_id, n)
    add_item(item_id, -n)
  end
  def take_weapon(weapon_id, n)
    add_weapon(weapon_id, -n)
  end
  def take_armor(armor_id, n)
    add_armor(armor_id, -n)
  end
  def empty_all
    for i in 1...$data_items.size
      if $game_party.item_number(i) > 0
        add_item(i, $game_party.item_number(i))
        $game_party.lose_item(i, $game_party.item_number(i))
      end
    end
    for i in 1...$data_weapons.size
      if $game_party.weapon_number(i) > 0
        add_weapon(i, $game_party.weapon_number(i))
        $game_party.lose_weapon(i, $game_party.weapon_number(i))
      end
    end
    for i in 1...$data_armors.size
      if $game_party.armor_number(i) > 0
       add_armor(i, $game_party.armor_number(i))
       $game_party.lose_armor(i, $game_party.armor_number(i))
      end
    end
  end
  def take_all
    for i in 1...$data_items.size
      if item_amount(i) > 0
        n = [99, ($game_party.item_number(i) - item_amount(i)).abs].min
        $game_party.gain_item(i, n)
        take_item(i, n)
      end
    end
    for i in 1...$data_weapons.size
      if weapon_amount(i) > 0
        n = [99, ($game_party.weapon_number(i) - weapon_amount(i)).abs].min
        $game_party.gain_weapon(i, n)
        take_weapon(i, n)
      end
    end
    for i in 1...$data_armors.size
      if armor_amount(i) > 0
         n = [99, ($game_party.armor_number(i) - armor_amount(i)).abs].min
        $game_party.gain_armor(i, n)
        take_armor(i, n)
      end
    end
  end
end

#==============================================================================
# Window_Chest_Choices
#------------------------------------------------------------------------------
# The choices for the chest when the scene is opened.
#==============================================================================
class Window_Chest_Choices < Window_Selectable
  def initialize
    super(0, 0, 640, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
    @item_max = 3
    @column_max = 3
    @commands = ["Store Items", "Take Items", "Exit"]
    self.z = 200
    refresh
    self.index = 0
  end
  def refresh
    self.contents.clear
    for i in 0...@item_max
      draw_item(i)
    end
  end
  def draw_item(index)
    x = 4 + index * 215
    self.contents.draw_text(x, 0, 128, 32, @commands[index], 1)
  end
end

#==============================================================================
# Window_Chest_Item
#------------------------------------------------------------------------------
# Displays all items in the chest.
#==============================================================================
class Window_Chest_Item < Window_Selectable
  def initialize(chest)
    super(320, 64, 320, 416)
    @chest = chest
    @column_max = 1
    refresh
    self.index = 0
    if $game_temp.in_battle
      self.y = 64
      self.height = 256
      self.back_opacity = 160
    end
  end
  def item
    return @data[self.index]
  end
  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    for i in 1...$data_items.size
      if @chest.item_amount(i) > 0
        @data.push($data_items[i])
      end
    end
    unless $game_temp.in_battle
      for i in 1...$data_weapons.size
        if @chest.weapon_amount(i) > 0
          @data.push($data_weapons[i])
        end
      end
      for i in 1...$data_armors.size
        if @chest.armor_amount(i) > 0
          @data.push($data_armors[i])
        end
      end
    end
    @item_max = @data.size
    if @item_max > 0
      self.contents = Bitmap.new(width - 32, row_max * 32)
      for i in 0...@item_max
        draw_item(i)
      end
    end
  end
  def draw_item(index)
    item = @data[index]
    self.contents.font.color = normal_color
    if item.is_a?(RPG::Weapon) || item.is_a?(RPG::Item)
      if item.element_set.include?(GameGuy::KeyItemId)
        self.contents.font.color = disabled_color
      end
    else
      if item.guard_element_set.include?(GameGuy::KeyItemId)
        self.contents.font.color = disabled_color
      end
    end
    case item
    when RPG::Item
      number = @chest.item_amount(item.id)
    when RPG::Weapon
      number = @chest.weapon_amount(item.id)
    when RPG::Armor
      number = @chest.armor_amount(item.id)
    end
    x = 4 + index % @column_max * (288 + 32)
    y = index / @column_max * 32
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(item.icon_name)
    opacity = self.contents.font.color == normal_color ? 255 : 128
    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.draw_text(x + 28, y, 212, 32, item.name, 0)
    self.contents.draw_text(x + 216, y, 16, 32, ":", 1)
    self.contents.draw_text(x + 224, y, 48, 32, number.to_s, 2)
  end
  def update_help
    @help_window.set_text(self.item == nil ? "" : self.item.description)
  end
end

#==============================================================================
# Window_Party_Item
#------------------------------------------------------------------------------
# Displays all items the party has.
#==============================================================================
class Window_Party_Item < Window_Selectable
  def initialize
    super(0, 64, 320, 416)
    @column_max = 1
    refresh
    self.index = 0
    if $game_temp.in_battle
      self.y = 64
      self.height = 256
      self.back_opacity = 160
    end
  end
  def item
    return @data[self.index]
  end
  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    for i in 1...$data_items.size
      if $game_party.item_number(i) > 0
        @data.push($data_items[i])
      end
    end
    unless $game_temp.in_battle
      for i in 1...$data_weapons.size
        if $game_party.weapon_number(i) > 0
          @data.push($data_weapons[i])
        end
      end
      for i in 1...$data_armors.size
        if $game_party.armor_number(i) > 0
          @data.push($data_armors[i])
        end
      end
    end
    @item_max = @data.size
    if @item_max > 0
      self.contents = Bitmap.new(width - 32, row_max * 32)
      for i in 0...@item_max
        draw_item(i)
      end
    end
  end
  def draw_item(index)
    item = @data[index]
    self.contents.font.color = normal_color
    if item.is_a?(RPG::Weapon) || item.is_a?(RPG::Item)
      if item.element_set.include?(GameGuy::KeyItemId)
        self.contents.font.color = disabled_color
      end
    else
      if item.guard_element_set.include?(GameGuy::KeyItemId)
        self.contents.font.color = disabled_color
      end
    end
    case item
    when RPG::Item
      number = $game_party.item_number(item.id)
    when RPG::Weapon
      number = $game_party.weapon_number(item.id)
    when RPG::Armor
      number = $game_party.armor_number(item.id)
    end
    x = 4 + index % @column_max * (288 + 32)
    y = index / @column_max * 32
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(item.icon_name)
    opacity = self.contents.font.color == normal_color ? 255 : 128
    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.draw_text(x + 28, y, 212, 32, item.name, 0)
    self.contents.draw_text(x + 216, y, 16, 32, ":", 1)
    self.contents.draw_text(x + 224, y, 48, 32, number.to_s, 2)
  end
  def update_help
    @help_window.set_text(self.item == nil ? "" : self.item.description)
  end
end

#==============================================================================
# Scene_Chest
#------------------------------------------------------------------------------
# The scene that controls storing and taking items.
#==============================================================================
class Scene_Chest
  def initialize(chest=1, max=GameGuy::ChestMaxItems)
    @chestid = chest
    @chest = $game_system.chests(@chestid)
  end
  def main
    @help_window = Window_Help.new
    @help_window.visible = false
    @command_window = Window_Chest_Choices.new
    @party_window = Window_Party_Item.new
    @party_window.active = false
    @chest_window = Window_Chest_Item.new(@chest)
    @chest_window.active = false
    Graphics.transition
    loop do
      Graphics.update
      Input.update
      update
      if $scene != self
        break
      end
    end
    @help_window.dispose
    @command_window.dispose
    @party_window.dispose
    @chest_window.dispose
  end
  def update
    @help_window.update
    @command_window.update
    @party_window.update
    @chest_window.update
    if @command_window.active
      update_command
      return
    end
    if @party_window.active
      update_party
      return
    end
    if @chest_window.active
      update_chest
      return
    end
  end
  def update_command
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Scene_Map.new
      return
    end
    if Input.trigger?(Input::C)
      case @command_window.index
      when 0
        $game_system.se_play($data_system.decision_se)
        @party_window.active = true
        @party_window.help_window = @help_window
        @command_window.active = false
        @help_window.z = 500
        @help_window.visible = true
      when 1
        $game_system.se_play($data_system.decision_se)
        @chest_window.active = true
        @chest_window.help_window = @help_window
        @command_window.active = false
        @help_window.z = 500
        @help_window.visible = true
      when 2
        $game_system.se_play($data_system.cancel_se)
        $scene = Scene_Map.new
      end
      return
    end
  end
  def update_party
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @command_window.active = true
      @help_window.visible = false
      @party_window.help_window = nil
      @party_window.active = false
      return
    end
    if Input.repeat?(Input::C)
      @item = @party_window.item
      unless @item.is_a?(RPG::Item) or @item.is_a?(RPG::Weapon) or
             @item.is_a?(RPG::Armor)
        $game_system.se_play($data_system.buzzer_se)
        return
      end
  if @item.element_set.include?(GameGuy::KeyItemId)
$game_system.se_play($data_system.buzzer_se)
return
  end
      case @item
      when RPG::Item
        amount = @chest.item_amount(@item.id)
        if amount < @chest.max
          $game_system.se_play($data_system.decision_se)
          @chest.add_item(@item.id, 1)
          $game_party.lose_item(@item.id, 1)
        else
          $game_system.se_play($data_system.buzzer_se)
          return
        end
      when RPG::Weapon
        amount = @chest.weapon_amount(@item.id)
        if amount < @chest.max
          $game_system.se_play($data_system.decision_se)
          @chest.add_weapon(@item.id, 1)
          $game_party.lose_weapon(@item.id, 1)
        else
          $game_system.se_play($data_system.buzzer_se)
          return
        end
      when RPG::Armor
        amount = @chest.armor_amount(@item.id)
        if amount < @chest.max
          $game_system.se_play($data_system.decision_se)
          @chest.add_armor(@item.id, 1)
          $game_party.lose_armor(@item.id, 1)
        else
          $game_system.se_play($data_system.buzzer_se)
          return
        end
      end
      @party_window.refresh
      @chest_window.refresh
      return
    end
  end
  def update_chest
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @command_window.active = true
      @help_window.visible = false
      @chest_window.help_window = nil
      @chest_window.active = false
      return
    end
    if Input.repeat?(Input::C)
      @item = @chest_window.item
      unless @item.is_a?(RPG::Item) or @item.is_a?(RPG::Weapon) or
             @item.is_a?(RPG::Armor)
        $game_system.se_play($data_system.buzzer_se)
        return
      end
      case @item
      when RPG::Item
        amount = $game_party.item_number(@item.id)
        if amount < 99
          $game_system.se_play($data_system.decision_se)
          @chest.take_item(@item.id, 1)
          $game_party.gain_item(@item.id, 1)
        else
          $game_system.se_play($data_system.buzzer_se)
          return
        end
      when RPG::Weapon
        amount = $game_party.weapon_number(@item.id)
        if amount < 99
          $game_system.se_play($data_system.decision_se)
          @chest.take_weapon(@item.id, 1)
          $game_party.gain_weapon(@item.id, 1)
        else
          $game_system.se_play($data_system.buzzer_se)
          return
        end
      when RPG::Armor
        amount = $game_party.armor_number(@item.id)
        if amount < 99
          $game_system.se_play($data_system.decision_se)
          @chest.take_armor(@item.id, 1)
          $game_party.gain_armor(@item.id, 1)
        else
          $game_system.se_play($data_system.buzzer_se)
          return
        end
      end
      @party_window.refresh
      @chest_window.refresh
      return
    end
  end
end

Note:
If you use RMX-OS, include the script above but also place this script below RMX-OS for it to save properly.
module RMXOS
 module Options
   SAVE_DATA[Game_System].push('@chests')
   SAVE_DATA[Game_Chest] = ['@max', '@weapons', '@armors', '@items']
   CREATION_DATA[Game_Chest] = GameGuy::ChestMaxItems.to_s
 end
end



Instructions

New and improved instructions in the script.


Compatibility

Not tested with SDK.
Compatible with RMX-OS (Must use small plugin)


Credits and Thanks


  • game_guy ~ making the system
  • MightyLink ~ requesting the system



Author's Notes

Enjoy and give credits!ll have to do this
# through a script call.
# -Take All
#

Starrodkirby86

I have a request on this sort of script, if you can achieve this.

There was an Indie game I played a long time ago known as the Exile series (Now remade into Avernum), and they had a similar item system to this. However, their item system has its few differences.

For one:

  • You can drop an item anywhere you want. The item dropped will be its respective icon.

  • Monsters drop items when they die, etc. Or there are items on the ground (Like rocks, twigs, gems, etc.)



I think of your screenshot as another mechanism of "Item Pick-up" within this system.

With the case of those item drops and whatever, it can be a serious way of abuse, huh? The developers of Exile moderated it through this way...Even though you can drop items anywhere you want, when leaving the town for a while, the items dropped will be gone. The only exception is at certain special areas, such as the Storage Room or the House on the Hill (In one game).

Can you perhaps make something like this? Of course, I'm not forcing you.

Great script though.

What's osu!? It's a rhythm game. Thought I should have a signature with a working rank. ;P It's now clickable!
Still Aqua's biggest fan (Or am I?).




G_G

I'll try I guess.
The items you pickup are easily evented. Have a player touch event, through is checked, respective graphic, add item, eh you get the point.

Aqua

Star meant that the items that are picked up can be the ones you dropped.

Mightylink

One of my favorite scripts, great job on this one :)

G_G

Quote from: Elite Four Aqua on May 01, 2009, 09:39:35 pm
Star meant that the items that are picked up can be the ones you dropped.


Either way it'll still require quite of bit of scripting I will see and try to see what I can do but no promises.

Reno-s--Joker

Wow, this is reeeaalllly neat. *instant power up for G_G* Great idea Mightylink too. :)

... Is it kinda like Fat Chocobo?
Wait, I'll DL the demo actually. Might use this in my game.

cstb

I may use this too IF he adds the ability to have items already in a chest.
Chronos: Failed project due to loss of data.
Maybe I could try again...


Which Final Fantasy Character Are You?
Final Fantasy 7

legacyblade

I'm pretty sure he's adding that ability.

Mightylink


G_G

sorta but the way I showed you has to be used before any chest is opened. I'm trying to do what legacy said but I'm still trying to get it.

legacyblade

If you are having trouble, PM me what you're having trouble with, and I'll help you. I always love to help people when I can.

Mightylink

I think its perfect already :P You just need to have a one time condition before opening the chest.

G_G

Thnx mighty, lb I think I almost got it, oh and Link I did update my achievements script in case you never noticed. It needs to be below this scrip thtough.

Mightylink

May 08, 2009, 08:58:05 pm #14 Last Edit: May 08, 2009, 10:18:49 pm by Mightylink
Yes I got it, for those wondering about chests with items already in it, this is the event code to use, at least for now till gi gi updates the script:



All you need to do is pick an unused switch and have your give items run once with that condition, that way the items dont come back when you loot the chest again.

I actually like it this way, you can do all sorts of neat stuff like have respawning chests, chest that add items when certain events happen, or you can even make the same herb chest from oblivion, put an item in and get 10 of that item a week later, its all possible through this event.

Skillzalot

Can you please add to it so you can limit how many items you can store in each bag

Mightylink

Youngster Gi Gi, I dont know why but im getting new problems, it started happening after I updated all of blizzards scripts but I dont know how it could be related.

When I put items in chests (with player) they no longer stay in the chest and I lose those items, errrr i dont know what happend, I never changed anything it was working so perfectly till now.

G_G

Maybe try placing this below all of blizz's scripts and see if it works.

Mightylink


G_G

Place my achievements script and the item storage script below blizz's scripts.