자세한 기능 : http://rpgmaker.net/scripts/319/
#==============================================================================
# Coelocanth's item crafting system
# Version: 0.9.4 (beta)
#==============================================================================
# License Information:
# Free for non commercial use.
# Please give attribution in your credits file.
#
# Commercial use is permitted in exchange for a free copy of the full game,
# and attribution in your credits file and any in game credits.
#
#==============================================================================
# Crafting system
#
# Concept:
#
# Crafting assembles a new item by consuming ingredients.
# If you don't have the required ingredients, the item will be
# disabled in the crafting interface
#
# A recipe may be required to know how to craft an item
# One recipe can cover any number of items
# (e.g. a blacksmithing for beginners book could be the recipe for
# tier 1-2 weapons and armors in your game)
# If you don't have the recipe, the item won't even show up in the
# crafting interface.
#
# A tool may be required to craft an item.
# Tools are like ingredients but not consumed.
# (e.g. you need an alchemist's still to craft elixirs)
# If you don't have the tool, the item will be disabled in the
# crafting interface
#
# Ingredients to craft an item are specified by notetags
# on the item that can be crafted.
#
# <craft item:id> - consume 1 item in crafting
# <craft item:id:quantity> - consume (quantity) of item in crafting
# <craft weapon:id> - consume 1 item in crafting
# <craft weapon:id:quantity> - consume (quantity) of item in crafting
# <craft armor:id> - consume 1 item in crafting
# <craft armor:id:quantity> - consume (quantity) of item in crafting
# <craft gold:quantity> - price to craft this recipe
# <craft recipe:id> - item id required to be able to see this
# craftable item in the interface
# <craft switch:id> - game switch must be ON to see this recipe
# <craft tool:id> - item id is required to craft this item,
# but is not consumed
#
# Additionally, there are tags to allow items to be broken down
# into ingredients.
#
# <craft break item:id> - give 1 item in breakdown
# <craft break item:id:quantity> - give (quantity) of item in breakdown
# <craft break weapon:id> - give 1 item in breakdown
# <craft break weapon:id:quantity> - give (quantity) of item in breakdown
# <craft break armor:id> - give 1 item in breakdown
# <craft break armor:id:quantity> - give (quantity) of item in breakdown
# <craft break gold:quantity> - price to perform this breakdown
# <craft break recipe:id> - item id required to be able to see this
# breakable item in the interface
# <craft break switch:id> - game switch must be ON to see this recipe
# <craft break tool:id> - item id is required to break this item.
#
# example: crafting a partisan requires 3 iron bars and a spear.
# And it can be broken down to give 2 iron bars back.
# <craft item:72:3>
# <craft weapon: 13>
# <craft break item:72:2>
#
# example: crafting spicy soup requires potato, meat and chilli
# as well as a cauldron tool to cook it in.
# <craft item: 74>
# <craft item: 75>
# <craft item: 76>
# <craft tool: 80>
#
# Integration:
#
# By default, "Crafting" and "Breakdown" commands are added to the menu.
# To change this, or control when the commands are available, set the
# configuration variables in the section below.
#
# To call the crafting system from an event, use a script item:
# SceneManager.call(Scene_Crafting)
# Fiber.yield
#
# To call the breakdown system from an event, use a script item:
# SceneManager.call(Scene_Craft_Breakdown)
# Fiber.yield
#
#==============================================================================
# Version History
# 0.9.4: Crafting shop features:
# - gold price to craft
# - switch to allow different shops to enable different recipes
# 0.9.3: Fixed script error on OK key when recipe window is empty
# 0.9.2: Added breakdown system and title texts
# 0.9.1: Fixed capturing of item counts in craft tags
# Visual improvements to ingredient window
# 0.9.0: Initial release
#==============================================================================
#
# Script configuration
#
module CRAFTING
# Should crafting be available from the menu?
# If not, set to false.
MENU_COMMAND = true
# Label for the menu command
MENU_COMMAND_TEXT = "Crafting"
# Menu command is always enabled?
MENU_COMMAND_ENABLE = true
# Menu command enabled by switch?
# set to the switch number to use that switch.
MENU_COMMAND_SWITCH = 0
# Menu command enabled when specific actor ID in party?
MENU_COMMAND_ACTOR = 0
# Menu command enabled when specific class ID in party?
MENU_COMMAND_CLASS = 0
# Text for ingredients panel, note \\ is needed in ruby where \ is used in DB
TEXT_INGREDIENTS_TITLE = "\\c[6]Ingredients:"
TEXT_INGREDIENTS_TOOLS = "\\c[6]Tools:"
TEXT_INGREDIENTS_PRICE = "\\c[6]Price:"
end
module CRAFT_BREAK
# Should breakdown be available from the menu?
# If not, set to false.
MENU_COMMAND = true
# Label for the menu command
MENU_COMMAND_TEXT = "Breakdown"
# Menu command is always enabled?
MENU_COMMAND_ENABLE = true
# Menu command enabled by switch?
# set to the switch number to use that switch.
MENU_COMMAND_SWITCH = 0
# Menu command enabled when specific actor ID in party?
MENU_COMMAND_ACTOR = 0
# Menu command enabled when specific class ID in party?
MENU_COMMAND_CLASS = 0
# Text for ingredients panel, note \\ is needed in ruby where \ is used in DB
TEXT_INGREDIENTS_TITLE = "\\c[2]Breakdown Results:"
TEXT_INGREDIENTS_TOOLS = "\\c[2]Tools:"
TEXT_INGREDIENTS_PRICE = "\\c[6]Price:"
end
#==============================================================================
# Here be dragons...
#==============================================================================
#==============================================================================
# DataManager
# Hook to read notetags after database load
#==============================================================================
module DataManager
#--------------------------------------------------------------------------
# alias method: load_database
#--------------------------------------------------------------------------
class <<self; alias load_database_crafting load_database; end
def self.load_database
load_database_crafting
load_notetags_crafting
end
#--------------------------------------------------------------------------
# new method: load_notetags_crafting
#--------------------------------------------------------------------------
def self.load_notetags_crafting
groups = [$data_items, $data_weapons, $data_armors]
for group in groups
for obj in group
next if obj.nil?
obj.load_notetags_crafting
end
end
end
end # DataManager
#==============================================================================
# RPG::BaseItem
# Parse notetags when loading items from the database.
# Adds readable properties for the ingredient lists.
#==============================================================================
class RPG::BaseItem
#--------------------------------------------------------------------------
# public instance variables
#--------------------------------------------------------------------------
attr_reader :crafting_items
attr_reader :crafting_weapons
attr_reader :crafting_armors
attr_reader :crafting_recipes
attr_reader :crafting_tools
attr_reader :crafting_gold
attr_reader :crafting_switches
attr_reader :craft_break_items
attr_reader :craft_break_weapons
attr_reader :craft_break_armors
attr_reader :craft_break_recipes
attr_reader :craft_break_tools
attr_reader :craft_break_gold
attr_reader :craft_break_switches
#--------------------------------------------------------------------------
# common cache: load_notetags_crafting
#--------------------------------------------------------------------------
#<craft item:68>
#<craft item:68:3>
def load_notetags_crafting
@crafting_items = {}
@crafting_weapons = {}
@crafting_armors = {}
@crafting_recipes = {}
@crafting_tools = {}
@crafting_switches = []
@crafting_gold = 0
@craft_break_items = {}
@craft_break_weapons = {}
@craft_break_armors = {}
@craft_break_recipes = {}
@craft_break_tools = {}
@craft_break_switches = []
@craft_break_gold = 0
#---
self.note.split(/[\r\n]+/).each { |line|
case line
#---
when /<craft item:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@crafting_items[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft weapon:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@crafting_weapons[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft armor:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@crafting_armors[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft recipe:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@crafting_recipes[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft tool:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@crafting_tools[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft switch:[[:space:]]*(\d+)>/i
@crafting_switches.push($1.to_i)
when /<craft gold:[[:space:]]*(\d+)>/i
@crafting_gold = $1.to_i
when /<craft break item:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@craft_break_items[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft break weapon:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@craft_break_weapons[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft break armor:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@craft_break_armors[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft break recipe:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@craft_break_recipes[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft break tool:[[:space:]]*(\d+(?:[[:space:]]*:[[:space:]]*(\d+)){0,1})>/i
@craft_break_tools[$1.to_i] = ($2 ? $2.to_i : 1)
when /<craft break switch:[[:space:]]*(\d+)>/i
@crafting_switches.push($1.to_i)
when /<craft break gold:[[:space:]]*(\d+)>/i
@craft_break_gold = $1.to_i
end
} # self.note.split
#---
end
def is_craftable?
!(@crafting_items.empty? && \
@crafting_weapons.empty? && \
@crafting_armors.empty? && \
@crafting_recipes.empty? && \
@crafting_tools.empty? && \
@crafting_switches.empty? && \
@crafting_gold == 0)
end
def is_craft_breakable?
!(@craft_break_items.empty? && \
@craft_break_weapons.empty? && \
@craft_break_armors.empty? && \
@craft_break_recipes.empty? && \
@craft_break_tools.empty? && \
@craft_break_switches.empty? && \
@craft_break_gold == 0)
end
end # RPG::BaseItem
#==============================================================================
# Window_MenuCommand
# Integrate crafting command
#==============================================================================
class Window_MenuCommand < Window_Command
alias add_original_commands_crafting add_original_commands
def add_original_commands
add_original_commands_crafting
if (CRAFTING::MENU_COMMAND)
enable = CRAFTING::MENU_COMMAND_ENABLE
if (!enable && CRAFTING::MENU_COMMAND_SWITCH)
enable = $game_switches[CRAFTING::MENU_COMMAND_SWITCH]
end
if (!enable && CRAFTING::MENU_COMMAND_ACTOR)
required = $game_actors[CRAFTING::MENU_COMMAND_ACTOR]
enable = $game_party.members.include?(required)
end
if (!enable && CRAFTING::MENU_COMMAND_CLASS)
enable = $game_party.members.map { |a| a.class_id }\
.include?(CRAFTING::MENU_COMMAND_CLASS)
end
add_command(CRAFTING::MENU_COMMAND_TEXT, :crafting, enable)
end
if (CRAFT_BREAK::MENU_COMMAND)
enable = CRAFT_BREAK::MENU_COMMAND_ENABLE
if (!enable && CRAFT_BREAK::MENU_COMMAND_SWITCH)
enable = $game_switches[CRAFT_BREAK::MENU_COMMAND_SWITCH]
end
if (!enable && CRAFT_BREAK::MENU_COMMAND_ACTOR)
required = $game_actors[CRAFT_BREAK::MENU_COMMAND_ACTOR]
enable = $game_party.members.include?(required)
end
if (!enable && CRAFT_BREAK::MENU_COMMAND_CLASS)
enable = $game_party.members.map { |a| a.class_id }\
.include?(CRAFT_BREAK::MENU_COMMAND_CLASS)
end
add_command(CRAFT_BREAK::MENU_COMMAND_TEXT, :craft_break, enable)
end
end
end
class Scene_Menu < Scene_MenuBase
def command_crafting
SceneManager.call(Scene_Crafting)
end
def command_craft_break
SceneManager.call(Scene_Craft_Breakdown)
end
alias create_command_window_crafting create_command_window
def create_command_window
create_command_window_crafting
@command_window.set_handler(:crafting, method(:command_crafting))
@command_window.set_handler(:craft_break, method(:command_craft_break))
end
end
#==============================================================================
# Recipe list window, for the crafting scene.
# It's based on the item list, but populated with items the player
# knows the crafting recipe for, rather than current inventory
#==============================================================================
class Window_RecipeList < Window_ItemList
attr_accessor :ingredient_window
def initialize(x,y,width, height)
super(x, y, width, height)
@data = []
refresh
end
def refresh
make_item_list
create_contents
draw_all_items
end
def make_item_list
tdata = $data_items.compact + $data_weapons.compact + $data_armors.compact
@data = tdata.select { |item| include?(item) }
end
def item_max
@data ? @data.size : 1
end
def col_max
1
end
def include?(item)
ok = super && item && item.is_craftable?
if ok
item.crafting_recipes.each \
{ |key,value| ok &= $game_party.item_number($data_items[key]) >= value }
item.crafting_switches.each { |id| ok &= $game_switches[id] }
end
ok
end
def enable?(item)
ok = false
if item
ok = ($game_party.gold >= item.crafting_gold)
item.crafting_items.each \
{ |key,value| ok &= $game_party.item_number($data_items[key]) >= value }
item.crafting_weapons.each \
{ |key,value| ok &= $game_party.item_number($data_weapons[key]) >= value }
item.crafting_armors.each \
{ |key,value| ok &= $game_party.item_number($data_armors[key]) >= value }
item.crafting_recipes.each \
{ |key,value| ok &= $game_party.item_number($data_items[key]) >= value }
item.crafting_tools.each \
{ |key,value| ok &= $game_party.item_number($data_items[key]) >= value }
end
ok
end
def update_help
@help_window.set_item(item)
@ingredient_window.set_item(item)
end
end
#==============================================================================
# Base ingredient list window
# common to crafting ingredients and breakdown results.
#==============================================================================
class Window_IngredientListBase < Window_Base
def initialize(x,y,width, height)
super(x, y, width, height)
@ingredients_title = "Ingredients:"
@ingredients = []
@tools_title = "Tools:"
@tools = []
@price_title = "Price:"
@gold = 0
@recipe_item = nil
refresh
end
def set_item(item)
@recipe_item = item
refresh
end
def refresh
make_item_list
create_contents
draw_all_items
end
def make_metadata(item, need)
metadata = {item: item}
metadata[:got] = $game_party.item_number(item)
metadata[:need] = need
metadata
end
def make_item_list
@ingredients = []
@tools = []
@gold = 0
end
def draw_all_items
# title text
ypos = calc_line_height(@ingredients_title)
draw_text_ex(0,0, @ingredients_title)
reset_font_settings
# ingredient list
@ingredients.each {|item| draw_item(item, ypos); ypos += line_height }
# tools separator text
if (@tools.size > 0)
draw_text_ex(0,ypos, @tools_title)
ypos += calc_line_height(@tools_title)
reset_font_settings
# tools list
@tools.each {|item| draw_item(item, ypos); ypos += line_height }
end
# gold?
if @gold != 0
ypos = draw_gold(ypos)
end
end
def item_max
@data ? @data.size : 1
end
def col_max
1
end
# override - adding enable flag
def draw_currency_value(value, unit, x, y, width, enable = true)
cx = text_size(unit).width
change_color(normal_color, enable)
draw_text(x, y, width - cx - 2, line_height, value, 2)
change_color(system_color)
draw_text(x, y, width, line_height, unit, 2)
end
def draw_gold(ypos)
got = $game_party.gold
have_enough = got >= @gold
draw_text_ex(0, ypos, @price_title)
ypos += calc_line_height(@price_title)
draw_currency_value(@gold, Vocab::currency_unit, 0, ypos, contents_width, have_enough)
ypos += line_height
return ypos
end
def draw_item(item, ypos)
if item
have_enough = item[:got] >= item[:need]
color = have_enough ? normal_color : power_down_color
draw_item_name(item[:item], 0, ypos, have_enough)
draw_current_and_max_values(contents_width - 96, ypos, \
96, item[:got], item[:need], \
color, normal_color)
end
end
def update_help
@help_window.set_item(item)
end
end
#==============================================================================
# ingredient list window
# shows what the player needs to craft an item
#==============================================================================
class Window_IngredientList < Window_IngredientListBase
def initialize(x,y,width, height)
super(x, y, width, height)
@ingredients_title = CRAFTING::TEXT_INGREDIENTS_TITLE
@tools_title = CRAFTING::TEXT_INGREDIENTS_TOOLS
@price_title = CRAFTING::TEXT_INGREDIENTS_PRICE
refresh
end
def make_item_list
super
if @recipe_item
@recipe_item.crafting_items.each \
{ |key,value| @ingredients.push(make_metadata($data_items[key], value)) }
@recipe_item.crafting_weapons.each \
{ |key,value| @ingredients.push(make_metadata($data_weapons[key], value)) }
@recipe_item.crafting_armors.each \
{ |key,value| @ingredients.push(make_metadata($data_armors[key], value)) }
@gold = @recipe_item.crafting_gold
@recipe_item.crafting_recipes.each \
{ |key,value| @tools.push(make_metadata($data_items[key], value)) }
@recipe_item.crafting_tools.each \
{ |key,value| @tools.push(make_metadata($data_items[key], value)) }
end
end
end
#==============================================================================
# Common code for crafting and breakdown scenes.
#==============================================================================
class Scene_CraftBase < Scene_MenuBase
def start
super
create_help_window
create_category_window
create_recipe_list
create_ingredient_list
end
#--------------------------------------------------------------------------
# * Create Category Window
#--------------------------------------------------------------------------
def create_category_window
@category_window = Window_ItemCategory.new
@category_window.viewport = @viewport
@category_window.help_window = @help_window
@category_window.y = @help_window.height
@category_window.set_handler(:ok, method(:on_category_ok))
@category_window.set_handler(:cancel, method(:return_scene))
end
def create_recipe_list
wy = @category_window.y + @category_window.height
wh = Graphics.height - wy
@recipe_window = Window_RecipeList.new(0,wy,Graphics.width / 2, wh)
@recipe_window.help_window = @help_window
@recipe_window.set_handler(:cancel, method(:on_item_cancel))
@recipe_window.set_handler(:ok, method(:on_item_ok))
@category_window.item_window = @recipe_window
end
#--------------------------------------------------------------------------
# * Get Currently Selected Item
#--------------------------------------------------------------------------
def item
@recipe_window.item
end
#--------------------------------------------------------------------------
# * Category [OK]
#--------------------------------------------------------------------------
def on_category_ok
@recipe_window.activate
@recipe_window.select_last
end
#--------------------------------------------------------------------------
# * Item [Cancel]
#--------------------------------------------------------------------------
def on_item_cancel
@recipe_window.unselect
@ingredient_window.set_item(nil)
@category_window.activate
end
end
#==============================================================================
# Crafting scene
#==============================================================================
class Scene_Crafting < Scene_CraftBase
#--------------------------------------------------------------------------
# * Item [OK]
# remove ingredients, add new item to inventory
#--------------------------------------------------------------------------
def on_item_ok
Sound.play_ok
item.crafting_items.each \
{ |key,value| ok &= $game_party.gain_item($data_items[key], -value) }
item.crafting_weapons.each \
{ |key,value| ok &= $game_party.gain_item($data_weapons[key], -value) }
item.crafting_armors.each \
{ |key,value| ok &= $game_party.gain_item($data_armors[key], -value) }
$game_party.gain_item(item, 1)
$game_party.lose_gold(item.crafting_gold)
@recipe_window.refresh
@recipe_window.activate
end
def create_ingredient_list
wx = @recipe_window.x + @recipe_window.width
wy = @category_window.y + @category_window.height
wh = Graphics.height - wy
@ingredient_window = \
Window_IngredientList.new(wx,wy,Graphics.width / 2, wh)
@recipe_window.ingredient_window = @ingredient_window
end
def create_recipe_list
wy = @category_window.y + @category_window.height
wh = Graphics.height - wy
@recipe_window = Window_RecipeList.new(0,wy,Graphics.width / 2, wh)
@recipe_window.help_window = @help_window
@recipe_window.set_handler(:cancel, method(:on_item_cancel))
@recipe_window.set_handler(:ok, method(:on_item_ok))
@category_window.item_window = @recipe_window
end
end
#==============================================================================
# Breakdown "recipe list"
# Uses player inventory, but filters out items that don't have
# a breakdown recipe in their tags.
#==============================================================================
class Window_BreakdownRecipeList < Window_ItemList
attr_accessor :ingredient_window
def initialize(x,y,width, height)
super(x, y, width, height)
@data = []
refresh
end
def refresh
make_item_list
create_contents
draw_all_items
end
def item_max
@data ? @data.size : 1
end
def col_max
1
end
def include?(item)
ok = super && item && item.is_craft_breakable?
if ok
item.craft_break_recipes.each \
{ |key,value| ok &= $game_party.item_number($data_items[key]) >= value }
item.craft_break_switches.each { |id| ok &= $game_switches[id] }
end
ok
end
def enable?(item)
ok = false
if item
ok = ($game_party.gold >= item.craft_break_gold)
item.craft_break_recipes.each \
{ |key,value| ok &= $game_party.item_number($data_items[key]) >= value }
item.craft_break_tools.each \
{ |key,value| ok &= $game_party.item_number($data_items[key]) >= value }
end
ok
end
def update_help
@help_window.set_item(item)
@ingredient_window.set_item(item)
end
end
#==============================================================================
# Breakdown results
# Uses different item tags and title text from ingredients list
#==============================================================================
class Window_BreakdownResultList < Window_IngredientListBase
def initialize(x,y,width, height)
super(x, y, width, height)
@ingredients_title = CRAFT_BREAK::TEXT_INGREDIENTS_TITLE
@tools_title = CRAFT_BREAK::TEXT_INGREDIENTS_TOOLS
@price_title = CRAFT_BREAK::TEXT_INGREDIENTS_PRICE
refresh
end
def make_item_list
super
if @recipe_item
@recipe_item.craft_break_items.each \
{ |key,value| @ingredients.push(make_metadata($data_items[key], value)) }
@recipe_item.craft_break_weapons.each \
{ |key,value| @ingredients.push(make_metadata($data_weapons[key], value)) }
@recipe_item.craft_break_armors.each \
{ |key,value| @ingredients.push(make_metadata($data_armors[key], value)) }
@gold = @recipe_item.craft_break_gold
@recipe_item.craft_break_recipes.each \
{ |key,value| @tools.push(make_metadata($data_items[key], value)) }
@recipe_item.craft_break_tools.each \
{ |key,value| @tools.push(make_metadata($data_items[key], value)) }
end
end
end
#==============================================================================
# Breakdown scene
#==============================================================================
class Scene_Craft_Breakdown < Scene_CraftBase
#--------------------------------------------------------------------------
# * Item [OK]
#--------------------------------------------------------------------------
def on_item_ok
Sound.play_ok
item.craft_break_items.each \
{ |key,value| ok &= $game_party.gain_item($data_items[key], value) }
item.craft_break_weapons.each \
{ |key,value| ok &= $game_party.gain_item($data_weapons[key], value) }
item.craft_break_armors.each \
{ |key,value| ok &= $game_party.gain_item($data_armors[key], value) }
$game_party.gain_item(item, -1)
$game_party.lose_gold(item.craft_break_gold)
@recipe_window.refresh
@recipe_window.activate
end
def create_ingredient_list
wx = @recipe_window.x + @recipe_window.width
wy = @category_window.y + @category_window.height
wh = Graphics.height - wy
@ingredient_window = \
Window_BreakdownResultList.new(wx,wy,Graphics.width / 2, wh)
@recipe_window.ingredient_window = @ingredient_window
end
def create_recipe_list
wy = @category_window.y + @category_window.height
wh = Graphics.height - wy
@recipe_window = Window_BreakdownRecipeList.new(0,wy,Graphics.width / 2, wh)
@recipe_window.help_window = @help_window
@recipe_window.set_handler(:cancel, method(:on_item_cancel))
@recipe_window.set_handler(:ok, method(:on_item_ok))
@category_window.item_window = @recipe_window
end
end