Save-Point
KChest XP - Printable Version

+- Save-Point (https://www.save-point.org)
+-- Forum: Material Development (https://www.save-point.org/forum-8.html)
+--- Forum: Scripts Database (https://www.save-point.org/forum-39.html)
+---- Forum: RPGMaker XP (RGSS) Engine (https://www.save-point.org/forum-116.html)
+---- Thread: KChest XP (/thread-4352.html)



KChest XP - kyonides - 09-05-2012

KChest XP
Version: 1.0.3

by Kyonides (Kyonides-Arkanthos)


Introduction

This script lets you easily create chests to store your items, weapons or armors or just all of your stuff. Of course you may take whatever is in those lonely and long forgotten chests. You are not supposed to animate the chests, it is already taken care of by the script.


Demo

No demo needed, just paste the script between Scene_Debug and Main and edit the Constants to get the results you want to get from it.


Instructions

Pick an empty slot to store any kind of item or weapon or armor. If you pick a chest item, it will automatically disappear and will be added to your team's "bag". And now please read the built-in instructions.

Script

Code:
#   KChest XP
#   v 1.0.3 - 2012-09-08
#   v 1.0.0 - 2012-09-04
#   Scripter:  Kyonides aka Kyonides-Arkanthos

#   Create chests to retrieve or leave items, weapons, armors. There is no need
#   to animate the chest by yourself, it is already taken care of.

#   It may be used as a safe at a bank, too. Of course, you would need to create
#   the engine and later ask the player for a (numeric) password.

#   script calls:

#     open_chest(variable_id)

#     open_chest(variable_id, 'i10', 'w20', 'a8')

#     opt=%w{i10 i22 w20 w40 a8 a27}
#     open_chest(variable_id, opt)

#   If you call the script by using the open_chest(variable_id), it will create
#   a new chest with no contents. This is only valid for the very first time
#   you use it. Thereafter the system will just get the contents of the
#   $game_variables[variable_id] for you.

#   GameSys module Constants will let you define the maximum slots per chest.

module GameSys
  # String : The empty slot icon filename
  EmptySlot = 'emptyslot'
  # Integer : Starting $game_variables ID to be used to store chest contents
  StartChestVarID = 5
  # Integer : How many slots per row would like to be displayed on screen?
  SlotPerRow = 5
  # Boolean : Use the automatic variable ID conversion or not
  ConvertVarID = true
  # Integer => Integer : Variable ID => Maximum Slots for this chest
  #   If ConvertVarID is true, then start from number 1 as your first var ID
  #   Otherwise pick any variable ID at will but you would need to remember the
  #   exact variable ID you pick for your chest event.
  ChestInfo = {1 => 1, 2 => 2, 3 => 4, 4 => 2, 5 => 5, 6 => 12}
  def self.get_size_offset
    s = RPG::Cache.icon(EmptySlot).rect
    i = RPG::Cache.icon('021-Potion01').rect
    @height, @width = s.height, s.width
    @x_offset, @y_offset = @height - i.height, @width - i.width
    RPG::Cache.clear
  end

  def self.slot_height; @height end
  def self.slot_width; @width end
  def self.slot_x_offset; @x_offset end
  def self.slot_y_offset; @y_offset end
  self.get_size_offset
end

module SpriteMod
  def dispose; self.bitmap.dispose if self.bitmap != nil; super end
end

class Game_System
  attr_reader :chest_sizes
  alias kyon_use_chest_gm_sys_init initialize
  def initialize
    @chest_sizes = {}
    GameSys::ChestInfo.each {|key, val|
      key = GameSys::StartChestVarID + key - 1 if GameSys::ConvertVarID
      @chest_sizes[key] = val
      change_chest_size(@chest_sizes[key].size, key) }
    kyon_use_chest_gm_sys_init
  end

  def change_chest_size(size, *vars)
    vars.each {|var| next if @chest_sizes[var].size == size
      @chest_sizes[var] = size
      $game_variables[var] = [0] if $game_variables[var].is_a?(Fixnum)
      size -= $game_variables[var].size - 1 if $game_variables[var].is_a?(Array)
      $game_variables[var] += [[nil, nil]] * size }
  end
end

class Game_Party
  def all_items; @items + @weapons + @armors end
end
  
class Window_ChestItem < Window_Item
  def initialize
    super
    @column_max = 2
    self.index = 0
  end

  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    for i in 1...$data_items.size
      @data.push($data_items[i]) if $game_party.item_number(i) > 0
    end
    for i in 1...$data_weapons.size
      @data.push($data_weapons[i]) if $game_party.weapon_number(i) > 0
    end
    for i in 1...$data_armors.size
      @data.push($data_armors[i]) if $game_party.armor_number(i) > 0
    end
    @item_max = @data.size
  end

  def items_size; @data.size end

  def delete_at(index) @data.delete_at(index) end

  def redraw_items
    self.contents = Bitmap.new(width - 32, row_max * 32)
    (0...@item_max).each {|i| draw_item(i)} if @data.size > 0
  end

  def draw_item(index)
    item = @data[index]
    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 % 2 * (288 + 32)
    y = index / 2 * 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 + 240, y, 16, 32, ":", 1)
    self.contents.draw_text(x + 256, y, 24, 32, number.to_s, 2)
  end
end

class Arrow_Chest < Sprite
  attr_accessor :index, :row_max, :item_max, :item_width, :x_y
  def initialize(viewport, x=0, y=0)
    super(viewport)
    self.bitmap = RPG::Cache.windowskin($game_system.windowskin_name)
    self.src_rect.set(128, 96, 32, 32)
    self.z = 5000
    self.x, self.y = x + 16, y
    self.angle -= 90
    @blink_count = 0
    @index = 0
    @row_max = 1
    @item_max = 0
    @item_width = 16
    @x_y = nil
    @name, @last_name = '', nil
    @color = Color.new(120, 120, 120, 120)
  end

  def update
    @blink_count = (@blink_count + 1) % 16
    index = @blink_count < 8 ? 128 : 160
    self.src_rect.set(index, 96, 32, 32)
    if @last_name != @name
      @name_sprite.bitmap.dispose unless @name_sprite.nil?
      @name_sprite.bitmap = Bitmap.new(180, 28)
      @name_sprite.bitmap.fill_rect(0, 0, 180, 28, @color)
      @name_sprite.bitmap.draw_text(0, 0, 180, 28, @name, 1)
      @last_name = @name
    end
    return if @item_max == 0
    if Input.repeat?(Input::RIGHT)
      $game_system.se_play($data_system.cursor_se)
      @index = @index < @x_y.size - 1 ? @index + 1 : 0
      self.x, self.y = @x_y[@index][0] + 16, @x_y[@index][1]
    elsif Input.repeat?(Input::LEFT)
      $game_system.se_play($data_system.cursor_se)
      @index = @index > 0 ? @index - 1 : @x_y.size - 1
      self.x, self.y = @x_y[@index][0] + 16, @x_y[@index][1]
    end
  end

  def item_name=(name) @name = name; update end
  def name_sprite=(sprite) @name_sprite = sprite end
end

class Interpreter
  alias kyon_use_chest_int_up update
  def update
    kyon_use_chest_int_up
    if @opened_chest and @wait_count == 0
      $scene = Scene_KChest.new(@var_id, @items)
      @opened_chest = @var_id = @items = nil
      return
    end
  end

  def open_chest(var, *items)
    @wait_count = 20
    @opened_chest = true
    @var_id, @items = var, items
    set_move_route_by_script(:open)
  end

  def set_move_route_by_script(move=:open)
    $game_player.straighten
    event = get_character(0)
    if move == :open
      event.turn_left
      event.turn_right
      event.turn_up
    else
      event.turn_right
      event.turn_left
      event.turn_down
    end
  end
end

class Spriteset_KChest
  attr_reader :cursor, :spaces, :goods, :good_sprites
  def initialize(var, *items)
    if !items.nil?
      index = -1
      items.flatten.each {|item|kind = item[0,1]=='i'? 0 : item[0,1]=='w'? 1 : 2
      item = item.sub(/\w/, '').to_i
      name = case kind
      when 0; $data_items[item].name
      when 1; $data_weapons[item].name
      when 2; $data_armors[item].name
      end
      items[index+=1] = [kind, item, name] }
    end
    var = GameSys::StartChestVarID + var - 1 if GameSys::ConvertVarID
    @var_id = var
    @spaces = $game_system.chest_sizes[@var_id]
    @var = $game_variables[@var_id]
    @goods = @var.is_a?(Array)? @var[0, @spaces] : items[0, @spaces]
    @height, @width = GameSys.slot_height, GameSys.slot_width
    @x_offset, @y_offset = GameSys.slot_x_offset, GameSys.slot_y_offset
    @slot_sprites, @good_sprites = [], []
    make_slot_sprites
    make_good_sprites
    @viewport = Viewport.new(0, 0, 640, 480)
    @viewport.z = 5000
    @cursor = Arrow_Chest.new(@viewport, @slot_sprites[0].x, @slot_sprites[0].y)
    @cursor.row_max = GameSys::SlotPerRow
    @cursor.item_max = @good_sprites.size + 1
    @cursor.item_width = @slot_sprites[0].src_rect.width
    update_cursor_coordinates
    @name_sprite = Sprite.new
    @name_sprite.bitmap = Bitmap.new(180, 28)
    @name_sprite.x, @name_sprite.y = 230, @slot_sprites[0].y - 4 - @height
    @cursor.name_sprite = @name_sprite
    @cursor.item_name = item.nil? ? '' : item[2]
  end

  def item() @goods[@cursor.index] end

  def make_slot_sprites
    row_max = GameSys::SlotPerRow
    free_space_x = (640 - ((@spaces < row_max ? @spaces : row_max)*@width)) / 2
    free_space_y = (480 - @height - (@spaces /(row_max+1) * @height)) / 2
    @spaces.times {|n| @slot_sprites << Sprite.new
      @slot_sprites[n].extend SpriteMod
      @slot_sprites[n].bitmap = RPG::Cache.icon(GameSys::EmptySlot)
      h, w = @slot_sprites[n].bitmap.height, @slot_sprites[n].bitmap.width
      @slot_sprites[n].x = free_space_x + (n % row_max * w)
      @slot_sprites[n].y = free_space_y + (n / row_max * h)
      @slot_sprites[n].opacity = 140 }
  end

  def make_good_sprites
    @spaces.times {|n| kind, id = @goods[n]
      break unless kind.is_a?(Integer)
      i=kind==0? $data_items[id] : kind==1? $data_weapons[id] : $data_armors[id]
      @good_sprites[n] = Sprite.new
      @good_sprites[n].extend SpriteMod
      @good_sprites[n].bitmap = RPG::Cache.icon(i.icon_name)
      @good_sprites[n].x = @slot_sprites[n].x + (@x_offset / 2)
      @good_sprites[n].y = @slot_sprites[n].y + (@y_offset / 2) }
  end

  def update
    @cursor.item_name = item.nil? ? '' : item[2]
    @name_sprite.update
    @slot_sprites.each {|sprite| sprite.update}
    @good_sprites.each {|sprite| sprite.update} unless @good_sprites.nil?
  end

  def update_cursor_coordinates
    @cursor.item_max = @good_sprites.size
    size = @good_sprites.size > 0 ? 1 : 0
    @cursor.x_y = @slot_sprites.map {|s| [s.x, s.y]}[0, @good_sprites.size+size]
  end

  def update_goods(simple=false)
    @goods.delete_at @cursor.index unless simple
    $game_variables[@var_id] = @goods
  end

  def update_goods_all_sprites
    $game_system.se_play($data_system.decision_se)
    update_goods
    dispose_good_sprites
    make_good_sprites
    update_cursor_coordinates
  end

  def dispose
    @name_sprite.dispose
    @slot_sprites.each {|s| s.dispose}
    @slot_sprites.clear
    dispose_good_sprites unless @good_sprites.nil?
    update_goods(true)
    @cursor.dispose
  end

  def dispose_good_sprites
    @good_sprites.each {|s| s.dispose}
    @good_sprites.clear
  end
end

class Scene_KChest
  def initialize(var, *items) @var, @items = var, items end
  def main
    start
    Graphics.transition
    loop do
      Graphics.update
      Input.update
      update
      break if $scene != self
    end
    Graphics.freeze
    terminate
  end

  def start
    @map_spriteset = Spriteset_Map.new
    @spriteset = Spriteset_KChest.new(@var, @items)
    @help_window = Window_Help.new
    @help_window.visible = false
    @item_window = Window_ChestItem.new
    @item_window.active = @item_window.visible = false
    @item_window.help_window = @help_window
  end

  def terminate
    @spriteset.dispose
    @map_spriteset.dispose
    dispose_all_instance_variables
  end

  def update
    @spriteset.update
    (update_cursor_slots; return) unless @item_window.active
    (update_item; return) if @item_window.active
  end

  def update_cursor_slots
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Scene_Map.new
      $game_system.map_interpreter.set_move_route_by_script(:close)
      return
    elsif Input.trigger?(Input::C)
      if (@spriteset.good_sprites.nil? and $game_party.all_items.keys.size == 0)
        $game_system.se_play($data_system.buzzer_se)
        return
      end
      item = @spriteset.item
      if item.nil?
        @item_window.refresh
        return if @item_window.items_size == 0
        @item_window.redraw_items
        @spriteset.cursor.visible = false
        @help_window.visible = @item_window.visible = @item_window.active = true
        return
      end
      case item[0]
      when 0; return if $game_party.item_number(item[1]) == 99
        $game_party.gain_item(item[1], 1)
        @spriteset.update_goods_all_sprites
        @item_window.refresh
      when 1; return if $game_party.weapon_number(item[1]) == 99
        $game_party.gain_weapon(item[1], 1)
        @spriteset.update_goods_all_sprites
        @item_window.refresh
      when 2; return if $game_party.armor_number(item[1]) == 99
        $game_party.gain_armor(item[1], 1)
        @spriteset.update_goods_all_sprites
        @item_window.refresh
      end
      return
    end
  end

  def update_item
    @item_window.update
    @help_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @spriteset.cursor.visible = true
      @help_window.visible = @item_window.visible = @item_window.active = false
      return
    elsif Input.trigger?(Input::C)
      if @spriteset.goods.size + 1 == @spriteset.spaces
        $game_system.se_play($data_system.buzzer_se)
        return
      end
      $game_system.se_play($data_system.decision_se)
      @item = @item_window.item
      case @item
      when RPG::Item;   $game_party.lose_item(@item.id, 1)
      when RPG::Weapon; $game_party.lose_weapon(@item.id, 1)
      when RPG::Armor;  $game_party.lose_armor(@item.id, 1)
      when nil; $game_system.se_play($data_system.buzzer_se); return
      end
      @item_window.delete_at @item_window.index
      @item_window.redraw_items
      kind = @item.is_a?(RPG::Item)? 0 : @item.is_a?(RPG::Weapon)? 1 : 2
      @spriteset.goods << [kind, @item.id]
      @spriteset.dispose_good_sprites
      @spriteset.make_good_sprites
      @spriteset.update_cursor_coordinates
    end
  end

  def update_all_instance_variables
    instance_variables.each {|var| ivar = instance_variable_get(var)
      ivar.update if [Window, Sprite].include?(ivar) }
  end

  def dispose_all_instance_variables
    instance_variables.each {|var| ivar = instance_variable_get(var)
      ivar.dispose if [Window, Sprite, Viewport].include?(ivar) }
  end
end

FAQ

Version 1.0.0 - Keep in mind that you may need to create a 36*36 pixel icon for the script to work properly.

Version 1.0.1 and later - Now you may use an icon of any size >= 24 * 24 pixels for the script to work properly.

As for now the icon should be named emptyslot.png but you can edit this by changing the EmptySlot filename string inside the GameSys module section of the script.


Compatibility

Designed for RPG Maker XP.


Terms and Conditions

Free for use but not meant for commercial projects. Due credit is not optional but a must.


RE: KChest XP - kyonides - 09-07-2012

Small Update!

Version 1.0.3 - Now you may use an icon of any size >= 24 * 24 pixels for the script to work properly. The filename should be emptyslot.png but you may edit it in the GameSys module section of the script at any time. Now you can also read the chosen item name right above the chest slots sprites.


RE: KChest XP - Narzew - 09-10-2012

Small, but good script. I'm used it to simplify my work with project :-)