累计送礼: 0 个 累计收礼: 1 个 TA的每日心情 开心 2026-7-12 04:10
签到天数: 209 天
连续签到: 2 天
[LV.7]常住居民III
管理员
VIP
7
卡币
25563
OK点
16
推广点
0
同能卷
50
积分 32235
Crafting Minigame
by
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
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 [0, 1, 2].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[i] when 0 if $game_party.item_number(@ingredients[i]) < 1 have_all = false end when 1 if $game_party.armor_number(@ingredients[i]) < 1 have_all = false end when 2 if $game_party.weapon_number(@ingredients[i]) < 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[i] when 0 $game_party.lose_item(@ingredients[i], 1) when 1 $game_party.lose_armor(@ingredients[i], 1) when 2 $game_party.lose_weapon(@ingredients[i], 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[self.index] 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[recipe_id] 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[index] 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[self.recipe.result].description when 1 description = $data_armors[self.recipe.result].description when 2 description = $data_weapons[self.recipe.result].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[i][0] stat_amount = stats[i][1].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([HP_RECOVERY_AMOUNT, @item.recover_hp]) end if @item.recover_hp < 0 stats.push([HP_DAMAGE_AMOUNT, @item.recover_hp]) end if @item.recover_hp_rate > 0 stats.push([HP_RECOVERY_PERCENT, @item.recover_hp_rate]) end if @item.recover_hp_rate < 0 stats.push([HP_DAMAGE_PERCENT, @item.recover_hp_rate]) end if @item.recover_sp > 0 stats.push([SP_RECOVERY_AMOUNT, @item.recover_sp]) end if @item.recover_sp < 0 stats.push([SP_DAMAGE_AMOUNT, @item.recover_sp]) end if @item.recover_sp_rate > 0 stats.push([SP_RECOVERY_PERCENT, @item.recover_sp_rate]) end if @item.recover_sp_rate < 0 stats.push([SP_DAMAGE_PERCENT, @item.recover_sp_rate]) 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([HIT_RATE, @item.hit]) 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([EVASION, @item.eva]) 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[i] case recipe.ingredient_types[i] when 0 item = $data_items[ingredient] count = $game_party.item_number(ingredient) when 1 item = $data_armors[ingredient] count = $game_party.armor_number(ingredient) when 2 item = $data_weapons[ingredient] 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[i] count = @counts[i] 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[i].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 = [0, 0, 0] 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[0] += 1 elsif Input.press?(Input::Y) @combined_percentages[1] += 1 elsif Input.press?(Input::Z) @combined_percentages[2] += 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_BUTTON_ICON, Y_BUTTON_ICON, Z_BUTTON_ICON][index] 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[0] * 2) y_percent = (@combined_percentages[1] * 2) z_percent = (@combined_percentages[2] * 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[i] - ERROR_TOLERANCE max = @combined_percentages[i] + ERROR_TOLERANCE range = min..max unless range.include?(correct_percentages[i]) 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[id] item_type = @recipe.ingredient_types[id] case item_type when 0 # item item = $data_items[item_id] when 1 # weapon item = $data_weapons[item_id] when 2 # armor item = $data_armors[item_id] 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 = [nil] 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 = [30, 31, 32] # Specify what types the ingredients are (0 = Item, 1 = Armor, 2 = Weapon) ingredient_types = [0, 0, 0] # Specify how much of each ingredient # 20% of ingredient #1, 30% of ingredient #2, 50% of ingredient #3 quantities = [20, 30, 50] # 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 = [1, 2, 32] ingredient_types = [0, 0, 0] quantities = [20, 30, 50] 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 = [30, 31, 32] ingredient_types = [0, 0, 0] quantities = [20, 30, 50] 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 = [4, 5, 32] ingredient_types = [0, 0, 0] quantities = [45, 45, 10] 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 = [3, 6, 32] ingredient_types = [0, 0, 0] quantities = [40, 40, 20] 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 = [3, 6, 7] ingredient_types = [0, 0, 0] quantities = [40, 40, 20] 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 = [30, 31, 32] ingredient_types = [0, 0, 0] quantities = [40, 40, 20] 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 = [30, 31, 32] ingredient_types = [0, 0, 0] quantities = [40, 40, 20] 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 = [30, 31, 32] ingredient_types = [0, 0, 0] quantities = [30, 30, 40] 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 = [30, 31, 32] ingredient_types = [0, 0, 0] quantities = [30, 30, 40] 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 = [30, 31, 32] ingredient_types = [0, 0, 0] quantities = [30, 30, 40] 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 = [30, 31, 32] ingredient_types = [0, 0, 0] quantities = [30, 30, 40] 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/
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x