Mobius's Crafting Minigame
Crafting Minigameby
MobiusXVI
Release Notes
May 2014 - v. 1.0 Initial Release
Mar 2024 - v. 2.0 Script refactored; updated database; bug fixes
Apr 2024 - v. 2.1 Add additional customization options
Introduction
So a long time ago, I made this script to fulfill a request here. It then sat neglected for many years. After some prompting, I decided to clean it up, fix some bugs, and re-post it here for all to use.
Features
- Create as many recipes as you like
- Create unlimited recipe types
- Players play a minigame to craft items
- Easily call the crafting screen from the menu using my Menu Command Manager
Screenshots
Spoiler
https://forums.rpgmakerweb.com/attachments/1711742859919-png.300202/
Spoiler
How to Use
Instructions are in the script. Download the demo, and open the script editor for more information.
Demo
Download the demo from the attached files.
Script
I recommend you download the demo as this won't work right out of the box, but if you really just want the script and don't mind fiddling with it to get it to work then here you go.
Spoiler: Main Script Ruby:
#===============================================================================
# Mobius' Crafting Program
# Authors: Mobius XVI, Deke
# Version: 2.1
# Date: 14 APR 2024
#===============================================================================
#
# Introduction:
#
# This script allows you to add crafting to your game which includes a
# crafting minigame where the player tries to match a given recipe for
# a particular item in order to create it successfully. Failures result
# in wasted components and a junk item.
#
# Instructions:
#
# Place this script below all the default scripts but above main.
#
# Add the database section below the crafting script
# Create your recipes in the database section; think of it like an
# extension of the built-in database.
#
# Each recipe needs the following:
# - Three ingredients -- These can be any item, weapon, or armor
# - Three ingredient quantites -- These can be any positive, whole numbers
# less than 100 but the sum of all three should add up to 100 exactly
# - A result -- this can be an item, weapon, or armor
# - A recipe type -- this is an arbitrary tag of your choosing, such as
# "Cooking", "Baking", "Smelting". This allows recipes to be grouped
# by their type. This will make it so that you can limit baking recipes
# to only work when using an oven for example.
#
# To have the player learn recipes, simply make an event with this script call
# $game_party.learn_recipe(1) -- Replace 1 with the recipe's ID in the database
#
# To call the crafting screen, simply make an event with this script call
# $scene = Scene_Craft.new("Cooking") -- Will only have cooking recipes
# $scene = Scene_Craft.new -- Will have all recipes
# $scene = Scene_Craft.new(nil, "menu") -- Will exit to the menu
# $scene = Scene_Craft.new("Cooking", "menu") -- Only cooking; exit to menu
#
# The crafting minigame works by asking the player to add the three ingredients
# in the correct proportions (with an error tolerance of 10% by default).
# If the player successfully combines the items in the right portions
# then they will craft the intended item.
# If not, they'll receive a junk item of your choosing.
#
# The minigame itself uses the X, Y, and Z "buttons" to add the ingredients.
# Check F1 to see what keyboard keys these are mapped to on your computer.
# By default, they 're mapped to A, S, and D.
#
# Issues/Bugs/Possible Bugs:
#
# - None
#
#Credits/Thanks:
# - Deke, author of underlying crafting script
# - Mobius XVI, author of minigame portion
# - sutorumie, for the idea/request
#
#License
#
# This script is available in its entirety for commercial and non-commercial
# use. View the specific license terms below.
#
# The portions of this script written by me are licensed under the MIT License:
#
# The MIT License (MIT)
#
# Copyright (c) 2024 darmes
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Further, if you do decide to use this script in a commercial product,
# I'd ask that you let me know via a forum post or a PM. Thanks.
#
#==============================================================================
# ** CUSTOMIZATION START
#==============================================================================
module Mobius
module Crafting
# Set the following value to false if you don' t want the game
# to check whether your recipes are properly formatted
# Note that data checking only works in playtest mode
# and so will not function in any final release
DATA_CHECK = true
# Set the item ID for the waste item. This must be an item that exists.
WASTE_ITEM_ID = 1
# Do you have a custom menu system? When the crafting scene ends we can
# return to the menu with a chosen menu index selected.
MENU_INDEX = 0
# Set the icons to use for the X, Y, and Z buttons.
# The icons should be about 24x24, but the script will auto-adjust them
# if they are slightly larger/smaller. Don't expect miracles though.
# This is a filename without extension within the icon folder.
X_BUTTON_ICON = "A"
Y_BUTTON_ICON = "S"
Z_BUTTON_ICON = "D"
# Set the picture to use for the progress bar.
# Picture should be exactly 204x20 pixels
# This is a filename without extension within the pictures folder.
BAR_PIC = "Bar"
# This lets you set pictures to use for window dressing.
# Pictures should be about 256x128 pixels
# You can set a different picture depending on the recipe type.
# If you'd rather just use a single picture then you can set a
# default picture below and it will always use that.
CRAFTING_PICTURES = {
# Recipe Type => picture filename without extension
"Smithing" => "Blacksmith",
# Start with recipe type then make this symbol '=>' then put a
# picture filename without extension within the pictures folder.
# End each entry with a comma ',' to separate them from each other.
}
# You can set a default picture here.
CRAFTING_PICTURES.default = "Laboratory"
# This lets you set sound effects for success and failure
# These are filenames without extension within the sound effects (SE) folder
# You can set a different SE depending on the recipe type.
# If you'd rather just use a single SE then you can set a default
# SE below and it will always use that.
CRAFT_SUCCESS_SE = {
# Recipe Type => SE filename without extension
"Smithing" => "055-Right01",
# Start with recipe type then make this symbol '=>' then put a
# SE filename without extension within the SE folder.
# End each entry with a comma ',' to separate them from each other.
}
# You can set a default success SE here.
CRAFT_SUCCESS_SE.default = "056-Right02"
CRAFT_FAILURE_SE = {
# Recipe Type => SE filename without extension
"Smithing" => "057-Wrong01",
# Start with recipe type then make this symbol '=>' then put a
# SE filename without extension within the SE folder.
# End each entry with a comma ',' to separate them from each other.
}
# You can set a default failure SE here.
CRAFT_FAILURE_SE.default = "058-Wrong02"
# Set the error tolerance for recipes, this is a percentage value
# i.e. the player needs to mix the ingredients according to the
# recipe within +/- 10%. Given the inherent inaccuracies, I
# recommend being fairly generous with this.
ERROR_TOLERANCE = 10
# Set the color to use for the outlines drawn around the ingredients
# and the finish/cancel buttons.
# Black by default. Colors are RGB.
OUTLINE_COLOR = Color.new(0, 0, 0) # Black
# Set the colors to use for filling the mixing bar. The colors show
# how much of each ingredient has been added, and can be set independently.
X_BUTTON_FILL_COLOR = Color.new(255, 0, 0) # Red
Y_BUTTON_FILL_COLOR = Color.new(0, 255, 0) # Green
Z_BUTTON_FILL_COLOR = Color.new(0, 0, 255) # Blue
# The following words are used for various displays
# Think of these as additional database words
HP_RECOVERY_AMOUNT = "HP Heal"
HP_DAMAGE_AMOUNT = "Damage"
HP_RECOVERY_PERCENT = "HP Heal %"
HP_DAMAGE_PERCENT = "Damage %"
SP_RECOVERY_AMOUNT = "SP Restore"
SP_DAMAGE_AMOUNT = "SP Drain"
SP_RECOVERY_PERCENT = "SP Restore %"
SP_DAMAGE_PERCENT = "SP Drain %"
HIT_RATE = "Accuracy"
EVASION = "EVA"
QUANTITY_OWNED = "Quantity currently owned:"
HAVE = "Have"
REQUIRED = "Req %"
FINISH = "Finish"
CANCEL = "Cancel"
end
end
#==============================================================================
# ** CUSTOMIZATION END
#------------------------------------------------------------------------------
# ** EDIT BELOW THIS LINE AT OWN RISK!!!
#==============================================================================
#==============================================================================
# ** Game_Party
#==============================================================================
class Game_Party
attr_accessor :known_recipe_ids
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
alias crafting_party_initialize initialize
def initialize
crafting_party_initialize
@known_recipe_ids=[]
end
#--------------------------------------------------------------------------
# * Know
#--------------------------------------------------------------------------
def know_recipe?(recipe_id)
return $game_party.known_recipe_ids.include?(recipe_id)
end
#--------------------------------------------------------------------------
# * Learn Recipe
#--------------------------------------------------------------------------
def learn_recipe(recipe_id)
# Don't learn recipes that aren't in the database
return if recipe_id <= 0
return if recipe_id >= Mobius::Recipes::RECIPES.size
# Don't learn recipes that we already know
return if know_recipe?(recipe_id)
@known_recipe_ids.push(recipe_id)
end
#--------------------------------------------------------------------------
# * Forget Recipe
#--------------------------------------------------------------------------
def forget_recipe(recipe_id)
@known_recipe_ids.delete(recipe_id)
end
end
#==============================================================================
# ** Game_Recipe
#==============================================================================
class Game_Recipe
include Mobius::Crafting
attr_reader :ingredients
attr_reader :quantities
attr_reader :result
attr_reader :result_type
attr_reader :ingredient_types
attr_reader :recipe_type
attr_reader :result
attr_reader :result_type
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize(ingredients, ingredient_types, quantities, result,
result_type, recipe_type = nil)
@ingredients = ingredients
@ingredient_types = ingredient_types
@quantities = quantities
@result = result
@result_type = result_type
@recipe_type = recipe_type
data_check if $DEBUG and DATA_CHECK
end
#--------------------------------------------------------------------------
# * Data_Check - Checks recipes for errors and reports them to user
#--------------------------------------------------------------------------
def data_check
unless @ingredients.size == 3
text = "WARNING:\n The recipe for \'#{name}\' does not have 3 ingredients."
text << "\nScript may not function as intended."
print(text)
end
unless @ingredient_types.size == 3
text = "WARNING:\n The recipe for \'#{name}\' does not have 3 ingredient"
text << " types.\nScript may not function as intended."
print(text)
end
unless @quantities.size == 3
text = "WARNING:\n The recipe for \'#{name}\' does not have 3 entries for"
text << " quantities.\nScript may not function as intended."
print(text)
end
unless @quantities.inject {|sum, n| sum + n } == 100
text = "WARNING:\n The recipe for \'#{name}\' has quantites which do not"
text << " equal 100%.\nScript may not function as intended."
print(text)
end
unless @result.is_a?(Integer)
text = "WARNING:\n The recipe for \'#{name}\' has a result which is not"
text << " a integer.\nScript may not function as intended."
print(text)
end
unless .include?(@result_type)
text = "WARNING:\n The recipe for \'#{name}\' has a result_type which is"
text << " not 0, 1, or 2.\nScript may not function as intended."
print(text)
end
unless @recipe_type.is_a?(String)
text = "WARNING:\n The recipe for \'#{name}\' has a recipe_type which is"
text << " not a String.\nScript may not function as intended."
print(text)
end
end
#--------------------------------------------------------------------------
# * Name - Returns the name of the item the recipe makes
#--------------------------------------------------------------------------
def name
case @result_type
when 0
name = $data_items[@result].name
when 1
name = $data_armors[@result].name
when 2
name = $data_weapons[@result].name
end
return name
end
#--------------------------------------------------------------------------
# * Have - Checks that the party has all the ingredients for this recipe
#--------------------------------------------------------------------------
def have
have_all = true
for i in 0...@ingredients.size
case @ingredient_types
when 0
if $game_party.item_number(@ingredients) < 1
have_all = false
end
when 1
if $game_party.armor_number(@ingredients) < 1
have_all = false
end
when 2
if $game_party.weapon_number(@ingredients) < 1
have_all = false
end
end
end
return have_all
end
#--------------------------------------------------------------------------
# * Decrement - Removes the recipe's ingredients from the party's inventory
#--------------------------------------------------------------------------
def decrement
for i in 0...@ingredients.size
case @ingredient_types
when 0
$game_party.lose_item(@ingredients, 1)
when 1
$game_party.lose_armor(@ingredients, 1)
when 2
$game_party.lose_weapon(@ingredients, 1)
end
end
end
#--------------------------------------------------------------------------
# * Make - Adds the recipe's result to the party's inventory
#--------------------------------------------------------------------------
def make
if have
case @result_type
when 0
$game_party.gain_item(@result, 1)
when 1
$game_party.gain_armor(@result, 1)
when 2
$game_party.gain_weapon(@result, 1)
end
decrement
end
end
#--------------------------------------------------------------------------
# * Make Waste - Adds the waste item to the party's inventory
#--------------------------------------------------------------------------
def make_waste
if have
$game_party.gain_item(WASTE_ITEM_ID, 1)
decrement
end
end
#--------------------------------------------------------------------------
# * == - Compares two recipes for equality
#--------------------------------------------------------------------------
def == (recipe)
if recipe.is_a?(Game_Recipe)
equal = true
if recipe.ingredients != self.ingredients
equal = false
end
if recipe.ingredient_types != self.ingredient_types
equal = false
end
if recipe.quantities != self.quantities
equal = false
end
if recipe.result != self.result
equal=false
end
if recipe.result_type != self.result_type
equal = false
end
if recipe.recipe_type != self.recipe_type
equal = false
end
else
equal = false
end
return equal
end
end
#==============================================================================
# ** Window_Base
#==============================================================================
class Window_Base
#--------------------------------------------------------------------------
# * Draw Icon - draws icons on "x, y"
# icon_name : filename of the icon ("String")
# x : draw spot x-coordinate
# y : draw spot y-coordinate
#--------------------------------------------------------------------------
def draw_icon(icon_name, x, y)
bitmap = RPG::Cache.icon(icon_name)
src_rect = Rect.new(0, 0, bitmap.width, bitmap.height)
self.contents.blt(x, y, bitmap, src_rect)
end
#--------------------------------------------------------------------------
# * Draw Icon Centered- draws icons centered on "x, y"
# icon_name : filename of the icon ("String")
# x : draw spot x-coordinate
# y : draw spot y-coordinate
#--------------------------------------------------------------------------
def draw_icon_centered(icon_name, x, y)
bitmap = RPG::Cache.icon(icon_name)
src_rect = Rect.new(0, 0, bitmap.width, bitmap.height)
draw_x = x - (bitmap.width / 2)
draw_y = y - (bitmap.height / 2)
self.contents.blt(draw_x, draw_y, bitmap, src_rect)
end
#--------------------------------------------------------------------------
# * Draw Pic - draws pic on "x, y"
# pic_name: filename of the pic ("String")
# x : draw spot x-coordinate
# y : draw spot y-coordinate
#--------------------------------------------------------------------------
def draw_pic(pic_name, x, y)
bitmap = RPG::Cache.picture(pic_name)
src_rect = Rect.new(0, 0, bitmap.width, bitmap.height)
self.contents.blt(x, y, bitmap, src_rect)
end
end
#==============================================================================
# ** Window_Craft - Displays the list of recipes
#==============================================================================
class Window_Craft < Window_Selectable
attr_reader :data
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize(recipe_type = nil)
super(0, 64, 240, 416)
@recipe_type = recipe_type
@column_max = 1
@data = []
self.index = 0
get_recipes
refresh
end
#--------------------------------------------------------------------------
# * Recipe - Returns the recipe currently selected
#--------------------------------------------------------------------------
def recipe
return @data
end
#--------------------------------------------------------------------------
# * Get Recipes - Gets the party's known recipes
#--------------------------------------------------------------------------
def get_recipes
for recipe_id in $game_party.known_recipe_ids.sort
recipe = Mobius::Recipes::RECIPES
next if !recipe # If we didn't get a recipe, skip
if @recipe_type # If not nil
@data.push(recipe) if recipe.recipe_type == @recipe_type
else
@data.push(recipe)
end
end
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
# Dispose old contents
if self.contents != nil
self.contents.dispose
self.contents = nil
end
# Draw all recipes
@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
#--------------------------------------------------------------------------
# * Draw Item - Draws a single recipe to the screen
#--------------------------------------------------------------------------
def draw_item(index)
recipe = @data
self.contents.font.color = recipe.have ? normal_color : disabled_color
x = 16
y = index * 32
w = self.width - 32
h = 32
self.contents.draw_text(x, y, w, h, recipe.name, 0)
end
#--------------------------------------------------------------------------
# * Update Help - Updates the help window with the recipe's description
#--------------------------------------------------------------------------
def update_help
if self.recipe.is_a?(Game_Recipe)
case self.recipe.result_type
when 0
description = $data_items.description
when 1
description = $data_armors.description
when 2
description = $data_weapons.description
end
else
description = ""
end
@help_window.set_text(description)
end
end
#==============================================================================
# ** Window_CraftResult - Displays the result of the chosen recipe
#==============================================================================
class Window_CraftResult < Window_Base
include Mobius::Crafting
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
super(240, 64, 400, 192)
self.contents = Bitmap.new(width - 32, height - 32)
@result = nil
@type = nil
@item = nil
@item_count = nil
end
#--------------------------------------------------------------------------
# * Set Result - Sets the recipe result to display
#--------------------------------------------------------------------------
def set_result(recipe)
@result = recipe.result
@type = recipe.result_type
case @type
when 0
@item = $data_items[@result]
@item_count = $game_party.item_number(@result)
when 1
@item = $data_armors[@result]
@item_count = $game_party.armor_number(@result)
when 2
@item = $data_weapons[@result]
@item_count = $game_party.weapon_number(@result)
end
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
self.contents.clear
# Draw recipe icon and quantity owned
self.draw_icon(@item.icon_name, 0, 0)
self.contents.font.color = normal_color
self.contents.draw_text(40, 0, 300, 32, QUANTITY_OWNED)
self.contents.font.color = system_color
self.contents.draw_text(294, 0, 45, 32,@item_count.to_s)
# Analyze Item
case @type
when 0
stats = analyze_item
when 1
stats = analyze_armor
when 2
stats = analyze_weapon
end
# Draw item's stats
for i in 0...stats.size
x = i % 2 * 184
y = i / 2 * 32 + 32
stat_label = stats
stat_amount = stats.to_s
self.contents.font.color = normal_color
self.contents.draw_text(x, y, 100, 32, stat_label)
self.contents.font.color = system_color
self.contents.draw_text(x + 110, y, 45, 32, stat_amount)
end
end
#--------------------------------------------------------------------------
# * Analyze Item - Gets the item's relevant stats
#--------------------------------------------------------------------------
def analyze_item
stats = []
# For each stat, include it for display only if it's non-zero
if @item.recover_hp > 0
stats.push()
end
if @item.recover_hp < 0
stats.push()
end
if @item.recover_hp_rate > 0
stats.push()
end
if @item.recover_hp_rate < 0
stats.push()
end
if @item.recover_sp > 0
stats.push()
end
if @item.recover_sp < 0
stats.push()
end
if @item.recover_sp_rate > 0
stats.push()
end
if @item.recover_sp_rate < 0
stats.push()
end
if @item.parameter_type > 0 and @item.parameter_points != 0
case @item.parameter_type
when 1# Max HP
stats.push(["Max " + $data_system.words.hp, @item.parameter_points])
when 2# Max SP
stats.push(["Max " + $data_system.words.sp, @item.parameter_points])
when 3# Strength
stats.push([$data_system.words.str, @item.parameter_points])
when 4# Dexterity
stats.push([$data_system.words.dex, @item.parameter_points])
when 5# Agility
stats.push([$data_system.words.agi, @item.parameter_points])
when 6# Intelligence
stats.push([$data_system.words.int, @item.parameter_points])
end
end
if @item.hit < 0
stats.push()
end
return stats
end
#--------------------------------------------------------------------------
# * Analyze Armor - Gets the armor's relevant stats
#--------------------------------------------------------------------------
def analyze_armor
stats = []
# For each stat, include it for display only if it's non-zero
if @item.pdef != 0
stats.push([$data_system.words.pdef, @item.pdef])
end
if @item.mdef != 0
stats.push([$data_system.words.mdef, @item.mdef])
end
if @item.eva != 0
stats.push()
end
if @item.str_plus != 0
stats.push([$data_system.words.str, @item.str_plus])
end
if @item.dex_plus != 0
stats.push([$data_system.words.dex, @item.dex_plus])
end
if @item.agi_plus != 0
stats.push([$data_system.words.agi, @item.agi_plus])
end
if @item.int_plus != 0
stats.push([$data_system.words.int, @item.int_plus])
end
return stats
end
#--------------------------------------------------------------------------
# * Analyze Weapon - Gets the weapon's relevant stats
#--------------------------------------------------------------------------
def analyze_weapon
stats = []
# For each stat, include it for display only if it's non-zero
if @item.atk != 0
stats.push([$data_system.words.atk, @item.atk])
end
if @item.pdef != 0
stats.push([$data_system.words.pdef, @item.pdef])
end
if @item.mdef != 0
stats.push([$data_system.words.mdef, @item.mdef])
end
if @item.str_plus != 0
stats.push([$data_system.words.str, @item.str_plus])
end
if @item.dex_plus != 0
stats.push([$data_system.words.dex, @item.dex_plus])
end
if @item.agi_plus != 0
stats.push([$data_system.words.agi, @item.agi_plus])
end
if @item.int_plus != 0
stats.push([$data_system.words.int, @item.int_plus])
end
return stats
end
end
#==============================================================================
# ** Window_CraftIngredients - Displays the ingredients of the chosen recipe
#==============================================================================
class Window_CraftIngredients < Window_Base
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
super(240, 256, 400, 224)
self.contents = Bitmap.new(width - 32, height - 32)
@ingredients = []
@counts = []
@percentages = []
end
#--------------------------------------------------------------------------
# * Set Ingredients - Sets the recipe ingredients to display
#--------------------------------------------------------------------------
def set_ingredients(recipe)
@ingredients = []
@counts = []
@percentages = recipe.quantities
for i in 0...recipe.ingredients.size
ingredient = recipe.ingredients
case recipe.ingredient_types
when 0
item = $data_items
count = $game_party.item_number(ingredient)
when 1
item = $data_armors
count = $game_party.armor_number(ingredient)
when 2
item = $data_weapons
count = $game_party.weapon_number(ingredient)
end
@ingredients.push(item)
@counts.push(count)
end
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
self.contents.clear
for i in 0...@ingredients.size
ingredient = @ingredients
count = @counts
y = i * 32
self.draw_icon(ingredient.icon_name, 0, y)
self.contents.font.color = count >= 1 ? normal_color : disabled_color
self.contents.draw_text(30, y, 280, 28, ingredient.name)
self.contents.font.color = normal_color
self.contents.draw_text(300, y, 45, 28, @percentages.to_s + "%")
self.contents.font.color = system_color
self.contents.draw_text(245, y, 45, 28, count.to_s )
end
end
end
#==============================================================================
# ** Window_CraftIngredientsLabel - Displays the labels above the ingredients
#==============================================================================
class Window_CraftIngredientsLabel < Window_Base
include Mobius::Crafting
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
super(440, 224, 196, 48)
# Weird hack so that this window can have smaller borders than normal
@bitmap = Bitmap.new(width - 16, height - 16)
@sprite = RPG::Sprite.new(self.viewport)
@sprite.bitmap = @bitmap
@sprite.visible = true
@sprite.x = self.x + 16
@sprite.y = self.y + 8
@sprite.z = self.z + 1
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
@bitmap.clear
@bitmap.draw_text(4, 0, 82, 32, HAVE)
@bitmap.draw_text(86, 0, 82, 32, REQUIRED)
end
#--------------------------------------------------------------------------
# * Dispose
#--------------------------------------------------------------------------
def dispose
@sprite.bitmap = nil
@sprite.dispose
@bitmap.dispose
super
end
end
#==============================================================================
# ** Window_CraftCombine - Displays the crafting minigame
#==============================================================================
class Window_CraftCombine < Window_Selectable
include Mobius::Crafting
TEMP_COLOR = Color.new(0, 0, 0) # Black
CLEAR_COLOR = Color.new(0, 0, 0, 0) # Clear
#---------------------------------------------------------------------------
# Object Initialization
#---------------------------------------------------------------------------
def initialize(recipe)
super(176, 78, 256 + 32, 288 + 32)
self.contents = Bitmap.new(width - 32, height - 32)
@recipe = recipe
@combined_percentages =
self.z = 1000
@item_max = 2
@column_max = 2
@index = 0
refresh
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
super
# Check if percentage bar is maxed out
unless @combined_percentages.inject {|sum, n| sum += n } >= 100
# If it isn't, allow additional adding
if Input.press?(Input::X)
@combined_percentages += 1
elsif Input.press?(Input::Y)
@combined_percentages += 1
elsif Input.press?(Input::Z)
@combined_percentages += 1
end
draw_bar
# If it is full, don't allow adding
else
if Input.trigger?(Input::X) or
Input.trigger?(Input::Y) or
Input.trigger?(Input::Z)
$game_system.se_play($data_system.buzzer_se)
end
end
end
#---------------------------------------------------------------------------
# Refresh
#---------------------------------------------------------------------------
def refresh
# Dispose old contents
self.contents.clear
# Draws the window dressing
draw_picture
# Draw the ingredient icons
draw_ingredient(0)
draw_ingredient(1)
draw_ingredient(2)
# Draw the ingredient button icons
draw_ingredient_button(0)
draw_ingredient_button(1)
draw_ingredient_button(2)
# Draw the progress bar
draw_bar
# Draw the finish / cancel buttons
draw_action_buttons
end
#--------------------------------------------------------------------------
# * Draw picture
#--------------------------------------------------------------------------
def draw_picture
picture_name = CRAFTING_PICTURES[@recipe.recipe_type]
if picture_name == ""
self.contents.fill_rect(0, 0, 256, 128, TEMP_COLOR)
else
draw_pic(picture_name, 0, 0)
end
end
#--------------------------------------------------------------------------
# * Draw Ingredient
#--------------------------------------------------------------------------
def draw_ingredient(index)
x = 22 + 80 * index
y, w, h = 132, 52, 52
self.contents.fill_rect(x, y, w, h, OUTLINE_COLOR)
self.contents.fill_rect(x + 2, y + 2, w - 4, h - 4, CLEAR_COLOR)
ingredient = get_ingredient(index)
draw_icon_centered(ingredient.icon_name, x + w/2, y + h/2)
end
#--------------------------------------------------------------------------
# * Draw Ingredient Button
#--------------------------------------------------------------------------
def draw_ingredient_button(index)
button =
x = 22 + 80 * index
y, w, h = 184, 52, 32
if button == ""
self.contents.fill_rect(x, y, 18, 18, TEMP_COLOR)
else
draw_icon_centered(button, x + w/2, y + h/2)
end
end
#--------------------------------------------------------------------------
# * Draw Bar
#--------------------------------------------------------------------------
def draw_bar
x, y, h = 28, 218, 16
# Draw inner bar background fill first
self.contents.fill_rect(x, y, 200, 16, Color.new(255,255,255))
# Draw inner bar ingredient fills
x_percent = (@combined_percentages * 2)
y_percent = (@combined_percentages * 2)
z_percent = (@combined_percentages * 2)
self.contents.fill_rect(x, y, x_percent, h, X_BUTTON_FILL_COLOR)
self.contents.fill_rect(x + x_percent, y, y_percent, h, Y_BUTTON_FILL_COLOR)
self.contents.fill_rect(x + x_percent + y_percent, y, z_percent, h, Z_BUTTON_FILL_COLOR)
# Draw the outer bar outline with tick marks over the top
draw_pic(BAR_PIC, x - 2, y - 2)
end
#--------------------------------------------------------------------------
# * Draw Action Button
#--------------------------------------------------------------------------
def draw_action_buttons
x1, x2 = 36, 138
y, w, h = 254, 82, 22
# Finish Button
self.contents.fill_rect(x1 - 2, y - 2, w + 4, h + 4, OUTLINE_COLOR)
self.contents.fill_rect(x1, y, w, h, CLEAR_COLOR)
self.contents.draw_text(x1, y, w, h, FINISH, 1)
# Cancel Button
self.contents.fill_rect(x2 - 2, y - 2, w + 4, h + 4, OUTLINE_COLOR)
self.contents.fill_rect(x2, y, w, h, CLEAR_COLOR)
self.contents.draw_text(x2, y, w, h, CANCEL, 1)
end
#--------------------------------------------------------------------------
# * Update Cursor Rectangle
#--------------------------------------------------------------------------
def update_cursor_rect
x1, x2 = 36, 138
y, w, h = 254, 82, 22
# If cursor position is less than 0
if @index < 0
self.cursor_rect.empty
return
end
if @index == 0
self.cursor_rect.set(x1, y, w, h)
elsif @index == 1
self.cursor_rect.set(x2, y, w, h)
end
end
#--------------------------------------------------------------------------
# * Judge Craft - Determines if crafting was successful
#--------------------------------------------------------------------------
def judge_craft
craft = true
correct_percentages = @recipe.quantities
for i in 0...correct_percentages.size
min = @combined_percentages - ERROR_TOLERANCE
max = @combined_percentages + ERROR_TOLERANCE
range = min..max
unless range.include?(correct_percentages)
craft = false
break
end
end
# If successful
if craft
# Play succes SE
success_name = CRAFT_SUCCESS_SE[@recipe.recipe_type]
Audio.se_play("Audio/SE/" + success_name)
# Make result
@recipe.make
else
# Play failure SE
failure_name = CRAFT_FAILURE_SE[@recipe.recipe_type]
Audio.se_play("Audio/SE/" + failure_name)
# Make waste
@recipe.make_waste
end
end
#--------------------------------------------------------------------------
# * Get ingredient - returns item/weapon/armor
# id : 0, 1, or 2
#--------------------------------------------------------------------------
def get_ingredient(id)
item_id = @recipe.ingredients
item_type = @recipe.ingredient_types
case item_type
when 0 # item
item = $data_items
when 1 # weapon
item = $data_weapons
when 2 # armor
item = $data_armors
end
return item
end
end
#==============================================================================
# ** Scene_Craft
#==============================================================================
class Scene_Craft
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize(recipe_type = nil, return_scene = nil)
@craft_index = -1
@return_scene = return_scene
@recipe_type = recipe_type
end
#--------------------------------------------------------------------------
# * Create Windows
#--------------------------------------------------------------------------
def create_windows
@craft_window = Window_Craft.new(@recipe_type)
@help_window = Window_Help.new
@craft_window.help_window = @help_window
@result_window = Window_CraftResult.new
@ingredients_window = Window_CraftIngredients.new
@label_window = Window_CraftIngredientsLabel.new
# If there's at least one known recipe
if @craft_window.data.size > 0
@craft_index = 0
@craft_window.index = 0
@result_window.set_result(@craft_window.recipe)
@ingredients_window.set_ingredients(@craft_window.recipe)
end
end
#--------------------------------------------------------------------------
# * Dispose Windows
#--------------------------------------------------------------------------
def dispose_windows
@craft_window.dispose
@help_window.dispose
@result_window.dispose
@ingredients_window.dispose
@label_window.dispose
end
#--------------------------------------------------------------------------
# * Main
#--------------------------------------------------------------------------
def main
create_windows
Graphics.transition
loop do
Graphics.update
Input.update
update
if $scene != self
break
end
end
Graphics.freeze
dispose_windows
end
#--------------------------------------------------------------------------
# * Update
#--------------------------------------------------------------------------
def update
@craft_window.update
# If there's a selectable recipe and we've changed selection
if @craft_index >= 0 and @craft_index != @craft_window.index
@craft_index = @craft_window.index
set_recipe_in_windows
end
# If we're selecting a recipe
if @craft_window.active
update_craft
return
end
# If we're in the crafting mini-game
if @craft_combine_window
update_craft_combine
return
end
end
#--------------------------------------------------------------------------
# * Set Recipe in Windows
#--------------------------------------------------------------------------
def set_recipe_in_windows
@result_window.set_result(@craft_window.recipe)
@ingredients_window.set_ingredients(@craft_window.recipe)
end
#--------------------------------------------------------------------------
# * Update Craft - Updates the selection of a recipe
#--------------------------------------------------------------------------
def update_craft
if Input.trigger?(Input::B)
$game_system.se_play($data_system.cancel_se)
if @return_scene == "menu"
$scene = Scene_Menu.new(Mobius::Crafting::MENU_INDEX)
else
$scene = Scene_Map.new
end
return
end
if Input.trigger?(Input::C) and @craft_window.data.size > 0
@recipe = @craft_window.recipe
if @recipe.have
$game_system.se_play($data_system.decision_se)
@craft_window.active = false
@craft_combine_window = Window_CraftCombine.new(@recipe)
else
$game_system.se_play($data_system.buzzer_se)
return
end
end
end
#---------------------------------------------------------------------------
# * Update Craft Combine - Updates the crafting minigame
#---------------------------------------------------------------------------
def update_craft_combine
@craft_combine_window.update
# If cancel button is pressed
if Input.trigger?(Input::B)
# Play cancel SE
$game_system.se_play($data_system.cancel_se)
@craft_window.active = true
@craft_combine_window.dispose
end
# If confirm button is pressed
if Input.trigger?(Input::C)
# If finish is chosen
if @craft_combine_window.index == 0
@craft_combine_window.judge_craft
@craft_window.active = true
@craft_combine_window.dispose
# Refresh item counts
@craft_window.refresh
set_recipe_in_windows
# If cancel is chosen
elsif @craft_combine_window.index == 1
$game_system.se_play($data_system.cancel_se)
@craft_window.active = true
@craft_combine_window.dispose
end
end
end
end
Spoiler: Database Section Ruby:
# This is the database section for storing your recipes
# Follow the instructions below for how to create recipes
module Mobius
module Recipes
#===== Don't touch this block =====
RECIPES =
def Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
RECIPES.push(
Game_Recipe.new(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
)
end
#===== You can edit below this line =====
# This is how you create a new recipe
# Specify the ingredient IDs (Item/Armor/Weapon) from the database
ingredients =
# Specify what types the ingredients are (0 = Item, 1 = Armor, 2 = Weapon)
ingredient_types =
# Specify how much of each ingredient
# 20% of ingredient #1, 30% of ingredient #2, 50% of ingredient #3
quantities =
# Specify what the recipe makes (Item/Armor/Weapon) from the database
result = 1
# Specify what type the result is (0 = Item, 1 = Armor, 2 = Weapon)
result_type = 0
# Specify the recipe type.
# The tag must be in quotes, and capitalization does matter.
recipe_type = "Brewing"
# Add the recipe to the database by doing this
# (the first recipe added will be recipe with ID = 1)
# This will be a potion in the default project
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a full potion in the default project
# Because this is the second recipe added it will have ID = 2
ingredients =
ingredient_types =
quantities =
result = 3
result_type = 0
recipe_type = "Brewing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a perfume in the default project
ingredients =
ingredient_types =
quantities =
result = 4
result_type = 0
recipe_type = "Brewing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a full perfume in the default project
ingredients =
ingredient_types =
quantities =
result = 6
result_type = 0
recipe_type = "Brewing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be an elixir in the default project
ingredients =
ingredient_types =
quantities =
result = 7
result_type = 0
recipe_type = "Brewing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a full elixir in the default project
ingredients =
ingredient_types =
quantities =
result = 8
result_type = 0
recipe_type = "Brewing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a seed of life in the default project
ingredients =
ingredient_types =
quantities =
result = 17
result_type = 0
recipe_type = "Brewing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a seed of strength in the default project
ingredients =
ingredient_types =
quantities =
result = 19
result_type = 0
recipe_type = "Brewing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a bronze sword in the default project
ingredients =
ingredient_types =
quantities =
result = 1
result_type = 2
recipe_type = "Smithing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a mythril sword in the default project
ingredients =
ingredient_types =
quantities =
result = 4
result_type = 2
recipe_type = "Smithing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a bronze shield in the default project
ingredients =
ingredient_types =
quantities =
result = 1
result_type = 1
recipe_type = "Smithing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
# This will be a mythril shield in the default project
ingredients =
ingredient_types =
quantities =
result = 4
result_type = 1
recipe_type = "Smithing"
Recipes.add_receipe_to_database(
ingredients,
ingredient_types,
quantities,
result,
result_type,
recipe_type
)
end
end
FAQ
Q. Can I disable the minigame?
A. Not with this version. I'd like to make an easy way to do that. You can always grab Deke's original version though if that's what you want.
Q. I used the old version you made; will this work with that?
A. No, I made enough changes "under the hood" that if you had been using the 1.0 version you can't simply drop this in to replace it.
Credit and Thanks
- Deke, author of underlying crafting script
- Mobius XVI, author of minigame portion
- sutorumie, for the idea/request
Author's Notes
This script is available in its entirety for commercial and non-commercial use. View the full license terms in the script header.
本贴来自国际rpgmaker官方论坛作者:MobiusXVI处,因国际论坛即将永久关站,为了存档多年珍贵资料,署名转载到本论坛存档,由于官方帖子为英文原帖,需要中文翻译请点击论坛顶部切换语言为中文就可以将帖子翻译成中文浏览,方便大家随时查看,原文地址:https://forums.rpgmakerweb.com/threads/mobiuss-crafting-minigame.167296/
页:
[1]