# =============================================================================
# TheoAllen - 仓库系统
# Version : 1.2
# Contact : www.rpgmakerid.com (or) http://theolized.blogspot.com
# (This script is translated by AbsoluteIce)
# =============================================================================
($imported ||= {})[:Theo_ChestSystem] = true
# =============================================================================
# CHANGE LOGS:
# -----------------------------------------------------------------------------
# 2013.08.19 - Compatibility Patch with Limited Inventory
# 2013.06.28 - Add custom chest name
# 2013.06.01 - Adjust control and GUI
# 2013.05.24 - Finished script
# 2013.05.23 - Started Script
# =============================================================================
=begin
介绍 :
本脚本可以设定一个仓库,允许玩家存放或取出物品.
使用方法 :
本脚本放在插件脚本之下,main之上
在使用脚本打开仓库前,使用以下事件注释:
<item: id, 数量>
<weapon: id, 数量>
<armor: id, 数量>
解释 :
id >> 物品/武器/护甲id
数量 >> 数量多少
使用以上注释后, 使用脚本 :
open_chest
对于自定义名称的仓库, 则可以 :
open_chest("小仓库")
open_chest("Eric的宝箱")
注意 : 所有事件中的所有注释都会读取一次,请确保在使用脚本之前使用了注释。
使用规定 :
署名脚本作者, TheoAllen. 你可以自由编辑此脚本,只要你不声明你是脚本的原作者
如果你想用此脚本于商业游戏,请和我共享收益.别忘了给我一份免费的游戏拷贝.
=end
# =============================================================================
# 设定 :
# =============================================================================
module THEO
module CHEST
# =========================================================================
# Vocabs
# -------------------------------------------------------------------------
AMOUNT_VOCAB = "数量 :" # 数量.
ALL_VOCAB = "全部" # 全部类别.
INV_VOCAB = "背包" # 背包.
ST_VOCAB = "库存" # 库存.
# =========================================================================
# =========================================================================
TRIGGER_GAIN_ALL = :CTRL
# -------------------------------------------------------------------------
# 全部取出的按钮. 如果你设定为 :CTRL, 则在玩家按下CTRL和确定键 (z)后会取出
# 全部物品
# =========================================================================
# =========================================================================
SHOW_AMOUNT_MIN = 10
# -------------------------------------------------------------------------
# 显示窗口数量的最小值.
# =========================================================================
end
end
# =============================================================================
# 设定结束 (除非清除你在干什么,否则以下内容勿动)
# =============================================================================
module THEO
module CHEST
module REGEXP
ITEM_REGEX = /<(?:ITEM|item):[ ]*[ ]*(\d+\s*,\s*\d*)>/i
WEAPON_REGEX = /<(?:WEAPON|weapon):[ ]*[ ]*(\d+\s*,\s*\d*)>/i
ARMOR_REGEX = /<(?:ARMOR|armor):[ ]*[ ]*(\d+\s*,\s*\d*)>/i
end
end
end
class Scene_Chest < Scene_MenuBase
include THEO::CHEST
def initialize(key,st_vocab)
$game_party.init_chest_cursors
@last_active = :stash
@key = key
@st_vocab = st_vocab
end
def start
super
create_header_windows
create_footer_window
create_main_windows
create_amount_window
prepare
end
def create_header_windows
create_help_window
create_category_window
end
def create_main_windows
create_inventory_window
create_stash_window
end
def create_help_window
@help = Window_Help.new
@help.viewport = @viewport
end
def create_category_window
@category = Window_ChestCategory.new
@category.viewport = @viewport
@category.y = @help.height
@category.set_handler(:ok, method(:on_category_ok))
@category.set_handler(:cancel, method(:return_scene))
end
def create_footer_window
create_inv_footer
create_st_footer
end
def create_inv_footer
if $imported[:Theo_LimInventory]
x = 0
y = Graphics.height - 48
w = Graphics.width/2
@inv_footer = Window_ChestFreeSlot.new(x,y,w)
@inv_footer.viewport = @viewport
else
@inv_footer = Window_ChestFooter.new(INV_VOCAB,$game_party,0)
@inv_footer.viewport = @viewport
end
end
def create_st_footer
@st_footer = Window_ChestFooter.new(@st_vocab,$game_chests[@key],1)
@st_footer.viewport = @viewport
end
def create_inventory_window
x = 0
y = @help.height + @category.height
w = Graphics.width/2
h = Graphics.height - y - @inv_footer.height
@inventory = Window_Inventory.new(x,y,w,h)
@inventory.viewport = @viewport
@inventory.set_handler(:ok, method(:item_inventory_ok))
@inventory.set_handler(:cancel, method(:on_inventory_cancel))
@inventory.help_window = @help
@category.item_window = @inventory
end
def create_stash_window
x = Graphics.width / 2
y = @inventory.y
w = x
h = @inventory.height
@stash = Window_Stash.new(x,y,w,h,@key)
@stash.viewport = @viewport
@stash.set_handler(:ok, method(:item_stash_ok))
@stash.set_handler(:cancel, method(:on_stash_cancel))
@stash.help_window = @help
@category.stash_window = @stash
end
def create_amount_window
@amount = Window_ChestAmount.new
@amount.viewport = @viewport
@amount.inv_window = @inv_footer if $imported[:Theo_LimInventory]
end
# for future plan ~
def refresh_all_footers
@inv_footer.refresh
@st_footer.refresh
end
def prepare
unselect_all
@category.show
@category.activate
@item_phase = false
deactivate_item_windows
hide_amount
end
def deactivate_item_windows
@inventory.deactivate
@stash.deactivate
end
def on_category_ok
@category.deactivate
activate_itemlist
@item_phase = true
end
def item_inventory_ok
unless @inventory.item
@inventory.activate
return
end
if @inventory.item_number < SHOW_AMOUNT_MIN
store_items(1)
@inventory.activate
refresh_itemlist
else
@last_active = :inventory
input_amount(@inventory)
end
end
def item_stash_ok
unless @stash.item
@stash.activate
return
end
if @stash.item_number < SHOW_AMOUNT_MIN
gain_items(1)
@stash.activate
refresh_itemlist
else
@last_active = :stash
input_amount(@stash)
end
end
def on_stash_cancel
@last_active = :stash
memorize_st
prepare
end
def on_inventory_cancel
@last_active = :inventory
memorize_inv
prepare
end
def input_amount(window)
memorize_all
if window.equal?(@stash)
@inventory.unselect
else
@stash.unselect
end
@amount.open
@amount.item_window = window
deactivate_item_windows
end
def hide_amount
Sound.play_cancel
@amount.close
@amount.reset_amount
end
def update
super
@amount.mode = @last_active
@inv_footer.mode = @last_active if $imported[:Theo_LimInventory]
select_item_phase if @item_phase
input_amount_phase if @amount.open?
end
def select_item_phase
gain_all_items if trigger_gain_all_item?
switch_window if Input.repeat?(:RIGHT) || Input.repeat?(:LEFT)
end
def input_amount_phase
activate_itemlist if Input.trigger?(:B)
if @amount.item_window.equal?(@stash) && Input.trigger?(:C)
gain_items(@amount.amount)
elsif @amount.item_window.equal?(@inventory) && Input.trigger?(:C)
store_items(@amount.amount)
end
end
def switch_window
if @inventory.active
switch_stash
elsif @stash.active
switch_inventory
end
end
def switch_inventory
memorize_st
@stash.deactivate
@stash.unselect
@inventory.activate
inv_select
end
def switch_stash
@stash.activate
st_select
memorize_inv
@inventory.deactivate
@inventory.unselect
end
def gain_all_items
if @stash.active
@stash.data.each do |item|
gain_items(@stash.item_number(item),item)
end
@stash.select(0)
else
@inventory.data.each do |item|
store_items(@inventory.item_number(item),item)
end
@inventory.select(0)
end
refresh_itemlist
refresh_all_footers
end
def trigger_gain_all_item?
Input.press?(THEO::CHEST::TRIGGER_GAIN_ALL) && Input.trigger?(:C)
end
def gain_items(amount, item = @stash.item)
if $imported[:Theo_LimInventory]
amount = [[amount,0].max,$game_party.inv_max_item(item)].min
end
$game_party.gain_item(item,amount)
$game_chests[@key].lose_item(item,amount)
on_amount_confirm if @amount.open?
end
def store_items(amount, item = @inventory.item)
$game_chests[@key].gain_item(item,amount)
$game_party.lose_item(item,amount)
on_amount_confirm if @amount.open?
end
def refresh_itemlist
@stash.refresh
@inventory.refresh
end
def on_amount_confirm
Sound.play_ok
refresh_itemlist
unselect_all
activate_itemlist
end
def activate_itemlist
hide_amount
case @last_active
when :stash
activate_stash
when :inventory
activate_inventory
end
@item_phase = true
end
def activate_inventory
@inventory.activate
@stash.unselect
inv_select
end
def activate_stash
@stash.activate
@inventory.unselect
st_select
end
def memorize_inv
$game_party.last_inv = @inventory.index
end
def memorize_st
$game_party.last_st = @stash.index
end
def inv_select
@inventory.index = [[$game_party.last_inv,@inventory.item_max-1].min,0].max
end
def st_select
@stash.index = [[$game_party.last_st,@stash.item_max-1].min,0].max
end
def unselect_all
@inventory.unselect
@stash.unselect
end
def memorize_all
memorize_inv
memorize_st
end
end
if $imported[:Theo_LimInventory]
class Window_ChestFreeSlot < Window_FreeSlot
attr_accessor :item
attr_accessor :mode
def initialize(x,y,w)
@add_number = 0
@mode = :stash
super(x,y,w)
end
def add_number=(number)
temp = @add_number
@add_number = number
refresh if temp != number
end
def draw_inv_slot(x,y,width = contents.width,align = 2)
item_size = @item.nil? ? 0 : @item.inv_size
item_size = -item_size if @mode == :inventory
txt = sprintf("%d/%d",$game_party.total_inv_size + @add_number *
item_size, $game_party.inv_max)
color = Theo::LimInv::NearMaxed_Color
near_max = ($game_party.total_inv_size + @add_number * item_size).to_f /
$game_party.inv_max >= (100 - Theo::LimInv::NearMaxed_Percent)/100.0
if near_max
change_color(text_color(color))
else
change_color(normal_color)
end
draw_text(x,y,width,line_height,txt,align)
change_color(normal_color)
end
end
end
class Window_ChestCategory < Window_ItemCategory
attr_reader :stash_window
def col_max
return 4
end
def update
super
@stash_window.category = current_symbol if @stash_window
end
def make_command_list
add_command(THEO::CHEST::ALL_VOCAB, :all)
add_command(Vocab::item, :item)
add_command(Vocab::weapon, :weapon)
add_command(Vocab::armor, :armor)
end
def stash_window=(stash_window)
@stash_window = stash_window
update
end
end
class Window_Inventory < Window_ItemList
attr_reader :data
def col_max
return 1
end
def current_item_enabled?
return true
end
def include?(item)
case @category
when :item
item.is_a?(RPG::Item) && !item.key_item?
when :weapon
item.is_a?(RPG::Weapon)
when :armor
item.is_a?(RPG::Armor)
when :all
item.is_a?(RPG::Armor) || item.is_a?(RPG::Weapon) || item.is_a?(RPG::Item)
else
false
end
end
def draw_item(index)
item = @data[index]
if item
rect = item_rect(index)
rect.width -= 4
draw_item_name(item, rect.x, rect.y, true,contents.width)
draw_item_number(rect, item)
end
end
def item_number(item = @data[index])
$game_party.item_number(item)
end
def process_ok
return if Input.press?(THEO::CHEST::TRIGGER_GAIN_ALL)
super
end
end
class Window_Stash < Window_ItemList
attr_reader :data
def initialize(x, y, width, height, key)
@key = key
super(x,y,width,height)
@category = :none
@data = []
end
def col_max
return 1
end
def current_item_enabled?
enable?(item)
end
def enable?(item)
return true unless $imported[:Theo_LimInventory]
return $game_party.inv_max_item(item) > 0
end
def include?(item)
case @category
when :item
item.is_a?(RPG::Item) && !item.key_item?
when :weapon
item.is_a?(RPG::Weapon)
when :armor
item.is_a?(RPG::Armor)
when :all
item.is_a?(RPG::Armor) || item.is_a?(RPG::Weapon) || item.is_a?(RPG::Item)
else
false
end
end
def make_item_list
@data = $game_chests[@key].all_items.select {|item| include?(item) }
@data.push(nil) if include?(nil)
end
def draw_item(index)
item = @data[index]
if item
rect = item_rect(index)
rect.width -= 4
draw_item_name(item, rect.x, rect.y, enable?(item),contents.width)
draw_item_number(rect, item)
end
end
def draw_item_number(rect, item)
draw_text(rect, sprintf(":%2d", $game_chests[@key].item_number(item)), 2)
end
def item_number(item = @data[index])
$game_chests[@key].item_number(item)
end
def process_ok
return if Input.press?(THEO::CHEST::TRIGGER_GAIN_ALL)
super
end
end
class Window_ChestAmount < Window_Base
attr_accessor :item_window
attr_accessor :mode
attr_reader :amount
def initialize
super(0,0,window_width,window_height)
self.openness = 0
@mode = :stash
reset_amount
update_position
refresh
end
def inv_window=(window)
@inv_window = window
end
def reset_amount
@amount = 0
refresh
end
def open
super
reset_amount
end
def update_position
self.x = (Graphics.width / 2) - (self.width / 2)
self.y = (Graphics.height / 2) - (self.height / 2)
end
def refresh
contents.clear
draw_text(0,0,contents.width,24,THEO::CHEST::AMOUNT_VOCAB,)
draw_text(0,0,contents.width,24,@amount,2)
end
def window_width
return 200
end
def window_height
return 24+24
end
def update
super
if @inv_window
@inv_window.add_number = @amount
@inv_window.item = @item_window.item if @item_window
end
if open?
increment if Input.repeat?(:RIGHT)
decrement if Input.repeat?(:LEFT)
ten_increment if Input.repeat?(:UP)
ten_decrement if Input.repeat?(:DOWN)
end
end
def increment
change_amount(1)
end
def decrement
change_amount(-1)
end
def ten_increment
change_amount(10)
end
def ten_decrement
change_amount(-10)
end
def change_amount(modifier)
@amount = [[@amount+modifier,0].max,max_amount].min
refresh
end
def show
super
reset_amount
end
def max_amount
if $imported[:Theo_LimInventory]
if @mode == :inventory
@item_window.item_number rescue 0
elsif @mode == :stash
[@item_window.item_number,$game_party.inv_max_item(@item_window.item)].min
end
else
@item_window.item_number rescue 0
end
end
end
class Window_ChestFooter < Window_Base
include THEO::CHEST
def initialize(vocab,object,x)
w = Graphics.width/2
h = fitting_height(1)
y = Graphics.height - h
x = (Graphics.width/2) * x
@vocab = vocab
super(x,y,w,h)
@object = object
refresh
end
def refresh
contents.clear
cx = text_size(@vocab).width
draw_text(0,0,contents.width,line_height,@vocab,1)
end
end
module DataManager
class << self
alias pre_create_chest create_game_objects
alias pre_chest_save_contents make_save_contents
alias pre_extract_chests extract_save_contents
end
def self.create_game_objects
pre_create_chest
create_chest_object
end
def self.create_chest_object
$game_chests = Game_Chest.new
end
def self.make_save_contents
contents = pre_chest_save_contents
contents[:chest] = $game_chests
contents
end
def extract_save_contents(contents)
pre_extract_chests(contents)
$game_chests = contents[:chest]
end
end
class Game_Chest
def initialize
@data = {}
@explored = {}
end
def[](key)
(@data[key] ||= Game_Stash.new)
end
def explored
@explored
end
end
class Game_Stash
attr_accessor :items_stash
attr_accessor :weapons_stash
attr_accessor :armors_stash
def initialize
@items_stash = {}
@weapons_stash = {}
@armors_stash = {}
end
def refresh
evaluate(@items_stash)
evaluate(@weapons_stash)
evaluate(@armors_stash)
end
def evaluate(stash)
stash.keys.each do |key|
stash.delete(key) if stash[key] <= 0
end
end
def items
@items_stash.keys.collect {|id| $data_items[id] }
end
def weapons
@weapons_stash.keys.collect {|id| $data_weapons[id] }
end
def armors
@armors_stash.keys.collect {|id| $data_armors[id] }
end
def all_items
items + weapons + armors
end
def item_number(item)
if item.is_a?(RPG::Item)
return @items_stash[item.id] ||= 0
elsif item.is_a?(RPG::Weapon)
return @weapons_stash[item.id] ||= 0
elsif item.is_a?(RPG::Armor)
return @armors_stash[item.id] ||= 0
end
refresh
end
def gain_item(item, amount)
return unless item
stash = pick_stash(item)
stash[item.id] = 0 if stash[item.id].nil?
stash[item.id] += amount
refresh
end
def lose_item(item,amount)
gain_item(item,-amount)
end
def pick_stash(item)
if item.is_a?(RPG::Item)
return @items_stash
elsif item.is_a?(RPG::Weapon)
return @weapons_stash
elsif item.is_a?(RPG::Armor)
return @armors_stash
end
end
end
class Game_Party
attr_accessor :last_inv
attr_accessor :last_st
alias pre_chest_init initialize
def initialize
pre_chest_init
init_chest_cursors
end
def init_chest_cursors
@last_inv = 0
@last_st = 0
end
end
class Game_Interpreter
def open_chest(st_vocab = THEO::CHEST::ST_VOCAB,key = [@map_id,@event_id])
if st_vocab.is_a?(Numeric)
key = st_vocab
st_vocab = THEO::CHEST::ST_VOCAB
end
SceneManager.call_chest(key,st_vocab)
end
alias pre_chest_command_108 command_108
def command_108
pre_chest_command_108
read_chest_comments
end
def read_chest_comments
map = @map_id
event = @event_id
key = [map,event]
return if $game_chests.explored[key]
@comments.each do |comment|
case comment
when THEO::CHEST::REGEXP::ITEM_REGEX
x = $1.scan(/\d+/)
$game_chests[key].items_stash[x[0].to_i] = x[1].to_i
when THEO::CHEST::REGEXP::WEAPON_REGEX
x = $1.scan(/\d+/)
$game_chests[key].weapons_stash[x[0].to_i] = x[1].to_i
when THEO::CHEST::REGEXP::ARMOR_REGEX
x = $1.scan(/\d+/)
$game_chests[key].armors_stash[x[0].to_i] = x[1].to_i
end
end
$game_chests.explored[key] = next_event_code != 108
end
end
module SceneManager
def self.call_chest(key,st_vocab = THEO::CHEST::ST_VOCAB)
@stack.push(@scene)
@scene = Scene_Chest.new(key,st_vocab)
end
end