[XP] Blacksmith System (New Configuration Program!)

Started by ForeverZer0, April 21, 2010, 04:50:15 pm

Previous topic - Next topic

ForeverZer0

Blacksmith Shop
Authors: ForeverZer0
Version: 2.0
Type: Custom Shop
Key Term: Custom Shop System



Introduction

Will allow you to create a complete blacksmith system. The player will be able to forge equipment/items by using combinations of weapons, armors, and items in their possession. Also includes a "Enchantment" feature that will allow the player to use special items to add stats, elemental efficiencies, and state altering to weapons and armor. The extraction feature allows for the breaking down of current equipment and items into other ones.


Features


  • Completely configurable item requirements for every item.

  • Configurable blacksmith 'fees' for every weapon/armor/item

  • Can use as many different items, with different quantities for each piece of equipment.

  • Variable "skill" levels for Blacksmith shops, which lets you decide which features the Blacksmith can do.

  • Only have to use a single script call to for the Blacksmith's shop.

  • Can recycle old equipment by extracting items from weapons/armors




Screenshots

Script
Forge Screen: ShowHide

Extract Screen: ShowHide

Enchant Screen: ShowHide


Configuration Application
Spoiler: ShowHide

Spoiler: ShowHide

Spoiler: ShowHide



Configuration Application

I have written a small application that can be used to make your configurations with a user-friendly GUI instead of typing out confusing arrays in the script. If you choose to download the application, you need not get anything else. All the scripts and the demo can be output from the application. Due to the increased file size and possible instability of embedding Ruby or IronRuby in the application to read your game's Marshaled .rxdata files, I left it out, but have included a one-time script to run in your game that will output a file to use with the program so that you need not copy your database into it. Here are the easy instructions:


  • Open application and go to the "Miscellaneous" tab.

  • Click the button to for the BlacksmithCache script, and copy the text anywhere in your script editor.

  • Run the game once, a file will be output.

  • Drag and Drop the file onto the anvil in the bottom-right corner of the application and you are done.



The application requires Microsoft's .NET 2.0 Framework or higher to run. If you do not have it and cannot run the application, you can download it here.

Blacksmith Configuration 1.1  (1.05 MB)



Demo

Demo Link


Script

Click here for the script.
Spoiler: ShowHide
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# Blacksmith Shop
# Author: ForeverZer0
# Type: Custom Shop System
# Date: 4.23.2011
# Version: v.2.0
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
#
# Explanation:
#   Will allow you to create a complete blacksmithing system. The player will be
#   able to forge equipment/items by using combinations of weapons, armors, and
#   items in their possession. Also includes a "Enchantment" feature that will
#   allow the player to use special items to add stats, elementel efficiencies,
#   and state altering to weapons and armor. The extraction feature allows for
#   the breaking down of current equipment and items into other ones.
#
# Features:
#   - Completely configurable item requirements for every item.
#   - Configurable blacksmith 'fees' for every weapon/armor
#   - Can use as many different items, with different quantities for each piece
#     of equipment.
#   - Variable "skill" levels for Blacksmith shops, which lets you decide
#     which features the Blacksmith can do.
#   - Only have to use a single script call to for the Blacksmith's shop.
#   - Can recycle old equipment by extracting items from weapons/armors/items.
#
# Instructions:
#   - Place script below debug and above main
#   - Configuration and instructions for each are below
#   - To call blacksmith shop, this script call:
#
#         w = [ WEAPON_IDS ]    (Use as many as needed, seperate with commas)
#         a = [ ARMOR_IDS ]
#         i = [ ITEM_IDS ]
#         $scene = Scene_BlackSmith.new(w, a, i)
#
#   - All IDs that you included in the script call for items will be be
#     available for forging in that shop.
#   - You can also include a fourth argument to the call to set the Blacksmith's
#     "skill level". Just make an array of true/false elemenets, set up like
#     this:
#
#             [CAN_FORGE?, CAN_EXTRACT?, CAN_ENCHANT?]
#
#     If you are not using the Enchant feature, omit the last option. Just make
#     sure that if you do include this argument that the array has a value for
#     each skill.
#
# Credits/Thanks:
#   - ForeverZer0, for the script.
#   - RoseSkye, huge thanks for beta-testing and demo map.
#
# Author's Notes:
#   Please report any bugs/issues at www.chaos-project.com
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:

module Blacksmith
 
#===============================================================================
#                          BEGIN CONFIGURATION
#===============================================================================

 FORGE_SE = ['006-System06', 80, 100]
 # SE played when an item is forged. ['FILENAME', VOLUME, PITCH]
 EXTRACT_SE = ['020-Teleport03', 80, 100]
 # SE played when an item extraction is performed. ['FILENAME', VOLUME, PITCH]
 ENCHANT_SE = ['020-Teleport03', 80, 100]
 # SE played when an item enchantment is performed. ['FILENAME', VOLUME, PITCH]
 
 USE_ENCHANTMENTS = true
 # Set to true to enable the "Enchant" feature of the system.
 
 NO_ENCHANT_WEAPONS = []
 NO_ENCHANT_ARMORS = []
 # Include IDs of any equipment that cannot be enchanted in the respective
 # arrays, seperating by commas. Ignore these if not using enchant feature.
 
 # Define the colors used for the text in the Blacksmith shop.
 PLUS_COLOR = Color.new(128, 255, 128)
 MINUS_COLOR = Color.new(255, 128, 128)
 
 MAP_BACK = true
 # Set to true if you would like slightly opaque windows with the map showing
 # through.
 
 #-----------------------------------------------------------------------------
 # FORGE DATABASE
 #-----------------------------------------------------------------------------
 # Define the materials used for each weapon/armor/item that can be forged and
 # extracted. They configuration is slightly different than what it was in the
 # first version of the script. You can seperately define materials that are
 # given during extraction if you like, or ignore it and it will simply return
 # the same materials it takes to forge them. It works like this:
 #
 # STEP 1:
 #   Create a new "case" in the appropriate method below for the type of item
 #   you are trying to define. There are three of them, one each for weapons,
 #   armors, and items. Just use this syntax:
 #      
 #          when DATABASE_ID then []
 #
 # STEP 2:
 #   Now you can begin to add materials to forge the item. Each material has
 #   an number which defines what type of item is is. Here is the "key":
 #
 #       0 = Weapon
 #       1 = Armor
 #       2 = Item
 #
 #   To define a material for an item, you simply create a three element array
 #   using this format:
 #                       [ITEM_TYPE, DATABASE_ID, QUANTITY]
 #
 #   ...and add it the appropriate empty array in the case statement you made
 #   in Step 1. You can add as many different items as you please to forge an
 #   weapon/armor/item, simply seperate the material arrays with commas. See
 #   below for a few examples.
 #-----------------------------------------------------------------------------
 def self.weapon_forges(id)
   return case id
   when 1 then [[2, 33, 3], [2, 42, 1]]            # Bronze Sword
   when 2 then [[0, 1, 1], [2, 34, 2], [2, 42, 1]] # Iron Sword
   when 3 then [[0, 2, 1], [2, 34, 10]]            # Steel Sword
   when 4 then [[0, 2, 2], [2, 35, 3], [2, 41, 1]] # Mythril Sword
   when 5 then [[2, 33, 5], [2, 43, 1]]            # Bronze Spear
   when 6 then [[2, 34, 4], [0, 5, 1], [2, 43, 1]] # Iron Spear
   when 7 then [[0, 6, 2], [2, 34, 2], [2, 43, 1]] # Steel Spear
   when 8 then [[2, 35, 8], [2, 43, 1]]            # Mythril Spear
   end
 end
 
 def self.armor_forges(id)
   return case id
   when 1 then []
   when 2 then []
   when 3 then []
   when 4 then []
   when 5 then []
   end
 end
 
 def self.item_forges(id)
   return case id
   when 2 then [[2, 1, 5]]
   when 3 then [[2, 2, 5]]
   when 5 then [[2, 4, 5]]
   when 6 then [[2, 5, 5]]
   end
 end
 
 #-----------------------------------------------------------------------------
 # EXTRACT DATABASE
 #-----------------------------------------------------------------------------
 # Here you can define the items received when a specific item is extracted.
 # It can be setup the same as way as above. Items left undefined will return
 # the same items that are required to forge it. You can define an item with an
 # empty array to have it return no items, though it can still return gold.
 #-----------------------------------------------------------------------------
 def self.weapon_extractions(id)
   return case id
   when 1 then [[2, 33, 1], [2, 42, 1]]
   when 2 then [[2, 34, 1], [2, 41, 1]]
   when 3 then [[2, 34, 2], [0, 1, 1]]
   when 4 then [[2, 33, 5], [2, 34, 5], [2, 41, 1]]
   when 5 then [[2, 33, 1], [2, 43, 1]]
   when 6 then [[2, 34, 1], [2, 43, 1]]
   when 7 then [[2, 34, 2], [0, 5, 1]]
   when 8 then [[2, 33, 5], [2, 34, 5], [2, 43, 1]]
   else
     self.weapon_forges(id)
   end
     
 end
 
 def self.armor_extractions(id)
   return case id
   when 1 then []
   when 2 then []
   when 3 then []
   when 4 then []
   when 5 then []
   else
     self.weapon_forges(id)
   end
 end
 
 def self.item_extractions(id)
   return case id
   when 1 then []                     # Potion
   when 2 then [[2, 1, 2]]            # High Potion
   when 3 then [[2, 2, 2], [2, 1, 2]] # Full Potion
   when 4 then []                     # Perfume
   when 5 then [[2, 4, 2]]            # High Perfume
   when 6 then [[2, 4, 2], [2, 5, 2]] # Full Perfume
   else
     self.item_forges(id)
   end
 end
 
 #-----------------------------------------------------------------------------
 # GOLD DATABASE
 #-----------------------------------------------------------------------------
 # Here you can define the amount of gold that is required to forge an item,
 # and the amount that is given if extracted. There are three methods, one each
 # for weapons, armors, and items. Simply follow this pattern for each
 # category:
 #
 #     when DATABASE_ID then [FORGE_PRICE, EXTRACT_GOLD,]
 #-----------------------------------------------------------------------------
 def self.weapon_gold(id)
   return case id
   when 1 then [200, 50]
   when 2 then [450, 225]
   when 3 then [1000, 525]
   when 4 then [1200, 200]
   when 5 then [300, 75]
   when 6 then [550, 275]
   when 7 then [1200, 600]
   when 8 then [1500, 650]
   else
     [0, 0]
   end
 end
 
 def self.armor_gold(id)
   return case id
   when 1 then []
   when 2 then []
   when 3 then []
   when 4 then []
   when 5 then []
   else
     [0, 0]
   end
 end
 
 def self.item_gold(id)
   return case id
   when 1 then [100, 0]
   when 2 then [50, 25]
   when 3 then [250, 25]
   when 4 then [100, 0]
   when 5 then [50, 25]
   when 6 then [250, 25]
   else
     [0, 0]
   end
 end
 
 #-----------------------------------------------------------------------------
 # ENCHANT DATABASE
 #-----------------------------------------------------------------------------
 
 #-----------------------------------------------------------------------------
 # Here you can define what items will alter stats when used to enchant with.
 # You need to create a two element array, and add it to the respective array
 # below that corresponds with the desired item.
 #
 # ex.
 #     when ITEM_ID then [[KEYWORD, VALUE], [KEYWORD, VALUE]]
 #
 #     KEYWORD: See below for a list of possible keywords. Stat changes that
 #              can affect only weapons will have no effect on armors, and
 #              vice-versa.
 #     VALUE : The amount by which to change the stat. Negative values will
 #             lower the stat.
 #-----------------------------------------------------------------------------
 # KEYWORDS:
 #
 #   'ATK' (Weapon Only)           'DEX'               'PDEF'
 #   'EVA' (Armor Only)            'AGI'               'MDEF'
 #   'STR'                         'INT'    
 #
 #   ** Keywords have to be written EXACTLY as they appear.
 #-----------------------------------------------------------------------------
 def self.enchant_stats(item_id)
   return case item_id
   when 39 then [['AGI', 5]]              # Carrot
   when 40 then [['STR', 15], ['ATK', 5]] # Behemoth Juice
   end
 end
 
 #-----------------------------------------------------------------------------
 # Define state altering enchantments.
 #
 # ex.
 #     when ITEM_ID then [[VALUE, STATE_ID], [VALUE, STATE_ID]]
 #
 #     VALUE: One of three different values to represent states efficiency.
 #              -1 = Minus state (Does nothing on armors)
 #               0 = Neutral
 #               1 = Plus state
 #     STATE_ID: The ID in the database of the state.
 #-----------------------------------------------------------------------------
 def self.enchant_states(item_id)
   return case item_id
   when 38 then [[1, 2], [1, 4], [1, 6]] # Chaos Orb
   end
 end
 
 #-----------------------------------------------------------------------------
 # Define element altering enchantments.
 #
 # ex.
 #     when ITEM_ID then [[VALUE, ELEMENT_ID], [VALUE, ELEMENT_ID]]
 #
 #     VALUE: One of two different values to represent element efficiency.
 #              true  = Uses element
 #              false = Doesn't use element (Negates element if present)
 #     ELEMENT_ID: The ID in the database of the element.
 #-----------------------------------------------------------------------------
 def self.enchant_elements(item_id)
   return case item_id
   when 36 then [[true, 3], [false, 5]] # Amethyst
   when 37 then [[true, 1]]             # Ruby ;)
   end
 end  
 
 #-----------------------------------------------------------------------------
 # Define the amount of gold it takes to enchant a weapon or armor with the
 # item.
 #-----------------------------------------------------------------------------
 def self.enchant_gold(item_id)
   return case item_id
   when 36 then 1500
   when 37 then 1100
   when 38 then 1337
   when 39 then 250
   when 40 then 7500
   else
     0
   end
 end
 
#===============================================================================
#                              END CONFIGURATION
#===============================================================================
 
 def self.materials?(type, id)
   # Get the required materials for the item
   materials = case type
   when 0 then [self.weapon_forges(id), self.weapon_gold(id)]
   when 1 then [self.armor_forges(id), self.armor_gold(id)]
   when 2 then [self.item_forges(id), self.item_gold(id)]
   end
   materials[0] = [] if materials[0] == nil
   # Check gold, skipping item check if there is not enough.
   if $game_party.gold >= materials[1][0]
     # Iterate all required materials, making sure enough are in inventory.
     materials[0].each {|item|
       # Branch by the type of the item.
       result = case item[0]
       when 0 then ($game_party.weapon_number(item[1]) >= item[2])
       when 1 then ($game_party.armor_number(item[1]) >= item[2])
       when 2 then ($game_party.item_number(item[1]) >= item[2])
       end
       # End iteration and return false immidiately if missing required item.
       return false unless result
     }
     return true
   end
   return false
 end
 #-----------------------------------------------------------------------------
 def self.update_database(item)
   # Open the Weapons or Armors .rxdata file and add the created item.
   begin
     if item.is_a?(RPG::Weapon)
       file, data = 'Data/Weapons.rxdata', $data_weapons
     elsif item.is_a?(RPG::Armor)
       file, data = 'Data/Armors.rxdata', $data_armors
     else
       return
     end
     data[item.id] = item
     file = File.open(file, 'wb')
     Marshal.dump(data, file)
     file.close
   rescue
     print "Could not add #{item.name} to Database."
   end
 end
 #-----------------------------------------------------------------------------
 def self.create_item(base_item, enchant_item)
   base = base_item.clone
   # Do to clone only making shallow copies, it is necessary to also create
   # seperate clones of the element and state sets, otherwise the original
   # is affected too.
   if base_item.is_a?(RPG::Weapon)
     elem_set = base_item.element_set.clone
     plus_state_set = base_item.plus_state_set.clone
     minus_state_set = base_item.minus_state_set.clone
   else
     guard_elem_set = base_item.guard_element_set.clone
     guard_state_set = base_item.guard_state_set.clone
   end
   # Gather the enchantment data.
   stats = self.enchant_stats(enchant_item.id)
   states = self.enchant_states(enchant_item.id)
   elements = self.enchant_elements(enchant_item.id)
   # Iterate through stats
   if stats != nil
     stats.each {|stat|
       case stat[0]
       when 'ATK'
         if base.is_a?(RPG::Weapon)
           base.atk += stat[1]
         end
       when 'EVA'
         if base.is?(RPG::Armor)
           base.eva += stat[1]
         end
       when 'STR' then base.str_plus += stat[1]
       when 'DEX' then base.dex_plus += stat[1]
       when 'AGI' then base.agi_plus += stat[1]
       when 'INT' then base.int_plus += stat[1]
       when 'PDEF' then base.pdef_plus += stat[1]
       when 'MDEF' then base.mdef_plus += stat[1]
       end
     }
   end
   # Iterate through states
   if states != nil
     states.each {|state|
       id = state[1]
       if base.is_a?(RPG::Weapon)
         case state[0]
         when -1
           minus_state_set.push(id) unless minus_state_set.include?(id)
           plus_state_set -= [id]
         when 0
           minus_state_set -= [id]
           plus_state_set -= [id]
         when 1
           plus_state_set.push(id) unless plus_state_set.include?(id)
           minus_state_set -= [id]
         end
       elsif base.is_a?(RPG::Armor)
         if state[0] == 0
           guard_state_set -= [id]
         elsif state[0] == 1
           guard_state_set.push(id) unless guard_state_set.inlcude?(id)
         end
       end
     }
   end
   # Iterate through elements
   if elements != nil
     elements.each {|element|
       id = element[1]
       if base.is_a?(RPG::Weapon)
         if element[0] && !elem_set.include?(id)
           elem_set.push(id)
         else
           elem_set -= [id]
         end
       elsif base.is_a?(RPG::Armor)
         if element[0] && !guard_elem_set.include?(id)
           guard_elem_set.push(id)
         else
           guard_elem_set -= [id]
         end
       end
     }
   end
   # Give the weapon a new ID, remove the old item, and add the new one.
   if base.is_a?(RPG::Weapon)
     $game_party.lose_weapon(base_item.id, 1)
     base.id = $data_weapons.size
     base.element_set = elem_set
     base.plus_state_set = plus_state_set
     base.minus_state_set = minus_state_set
     $data_weapons[base.id] = base
     $game_party.gain_weapon(base.id, 1)
   elsif base.is_a?(RPG::Armor)
     $game_party.lose_armor(base_item.id, 1)
     base.id = $data_armors.size
     base.guard_element_set = guard_elem_set
     base.guard_state_set = guard_state_set
     $data_armors[base.id] = base
     $game_party.gain_armor(base.id, 1)
   end
   # Add new item to class equipment
   self.update_class_equipment(base_item, base)
   # Save the new item to the database.
   self.update_database(base)
 end
 #-----------------------------------------------------------------------------
 def self.update_class_equipment(old, new)
   # Adds the created item to class equipment that could equip the original
   $data_classes.each_index {|i|
     next if $data_classes[i] == nil
     if old.is_a?(RPG::Weapon) && $data_classes[i].weapon_set.include?(old.id)
       $data_classes[i].weapon_set.push(new.id)
     elsif old.is_a?(RPG::Armor) && $data_classes[i].armor_set.include?(old.id)
       $data_classes[i].armor_set.push(new.id)
     end
   }
   # Marshal the new data.
   begin
     file = File.open('Data/Classes.rxdata', 'wb')
     Marshal.dump($data_classes, file)
     file.close
   rescue
     print "Could not update RPG::Class database."
   end
 end
end


 $blacksmith = 2.0

#===============================================================================
# ** Window_BlacksmithCommand
#===============================================================================

class Window_BlacksmithCommand < Window_Selectable
 
 def initialize(level)
   super(0, 64, 480, 64)
   @level = level
   if Blacksmith::USE_ENCHANTMENTS
     @item_max = @column_max = 4
     @commands = ['Forge', 'Extract', 'Enchant', 'Exit']
   else
     @item_max = @column_max = 3
     @commands = ['Forge', 'Extract', 'Exit']
   end
   self.contents = Bitmap.new(self.width - 32, self.height - 32)
   refresh
   self.index = 0
 end
 #-----------------------------------------------------------------------------
 def refresh
   self.contents.clear
   (0...@item_max).each {|i| draw_item(i) }
 end
 #-----------------------------------------------------------------------------
 def draw_item(index)
   w = self.width / @item_max
   self.contents.font.color = @level[index] ? normal_color : disabled_color
   self.contents.draw_text(4 + (w * index), 0, w, 32, @commands[index])
 end
end

#===============================================================================
# ** Window_BlacksmithForge
#===============================================================================

class Window_BlacksmithForge < Window_Selectable

 def initialize(shop_goods)
   super(0, 128, 368, 352)
   # Initialize window and create instance variable to store available goods.
   @shop_goods = shop_goods
   self.active = self.visible = false
   refresh
   self.index = 0
 end
 #-----------------------------------------------------------------------------
 def item
   return @data[self.index]
 end
 #-----------------------------------------------------------------------------
 def refresh(enchanting = false)
   # Dispose bitmap and set to nil if not already.
   if self.contents != nil
     self.contents = self.contents.dispose
   end
   # Set flag for enchanting
   @enchanting = enchanting
   # Create array of equipment, depending on flag
   if @enchanting
     @data = []
     # Add weapons
     ($data_weapons - [nil]).each {|weapon|
       if $game_party.weapon_number(weapon.id) > 0 &&
           !Blacksmith::NO_ENCHANT_WEAPONS.include?(weapon.id)
         @data.push(weapon)
       end
     }
     # Add Armor
     ($data_armors - [nil]).each {|armor|
       if $game_party.armor_number(armor.id) > 0 &&
           !Blacksmith::NO_ENCHANT_ARMORS.include?(armor.id)
         @data.push(armor)
       end
     }
   else
     @data = @shop_goods
   end
   # Create a new bitmap, sized for available items
   @item_max = @data.size
   if @item_max > 0
     self.contents = Bitmap.new(width - 32, row_max * 32)
     (0...@item_max).each {|i| draw_item(i) }
   end
 end
 #-----------------------------------------------------------------------------
 def draw_item(index)
   item = @data[index]
   # Set a few local variables depending on the type of item.
   case item
   when RPG::Weapon
     quantity = $game_party.weapon_number(item.id)
     price, type = Blacksmith.weapon_gold(item.id)[0], 0
   when RPG::Armor
     quantity = $game_party.armor_number(item.id)
     price, type = Blacksmith.armor_gold(item.id)[0], 1
   when RPG::Item
     quantity = $game_party.item_number(item.id)
     price, type = Blacksmith.item_gold(item.id)[0], 2
   end
   # Don't check material requirments for forging wjen enchanting
   result = @enchanting ? true : Blacksmith.materials?(type, item.id)
   # Determine the color to use for drawing the item name.
   if quantity < 99 && result
     self.contents.font.color = normal_color
   else
     self.contents.font.color = disabled_color
   end
   # Draw the item name, icon, and price.
   x, y = 4, index * 32
   rect = Rect.new(x, y, self.width - 32, 32)
   self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
   bitmap = RPG::Cache.icon(item.icon_name)
   opacity = self.contents.font.color == normal_color ? 255 : 128
   self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
   self.contents.draw_text(x + 28, y, 212, 32, item.name, 0)
   if !@enchanting
     self.contents.draw_text(x + 240, y, 88, 32, price.to_s, 2)
   end
 end
 #-----------------------------------------------------------------------------
 def update_help
   @help_window.set_text(self.item == nil ? '' : self.item.description)
 end
end

#===============================================================================
# ** Window_BlacksmithExtract
#===============================================================================

class Window_BlacksmithExtract < Window_Selectable

 def initialize
   super(0, 128, 368, 352)
   self.active = self.visible = false
   refresh
   self.index = 0
 end
 #-----------------------------------------------------------------------------
 def item
   return @data[self.index]
 end
 #-----------------------------------------------------------------------------
 def refresh
   # Dispose current bitmap if defined.
   if self.contents != nil
     self.contents = self.contents.dispose
   end
   # Create list of items in inventory
   @data = []
   (1...$data_weapons.size).each {|i|
     result = (Blacksmith.weapon_extractions(i) != nil ||
       Blacksmith.weapon_gold(i)[1] != 0)
     if $game_party.weapon_number(i) > 0 && result
       @data.push($data_weapons[i])  
     end
   }
   (1...$data_armors.size).each {|i|
     result = (Blacksmith.armor_extractions(i) != nil ||
       Blacksmith.armor_gold(i)[1] != 0)
     if $game_party.armor_number(i) > 0 && result
       @data.push($data_armors[i])  
     end
   }
   (1...$data_items.size).each {|i|
     result = (Blacksmith.item_extractions(i) != nil ||
       Blacksmith.item_gold(i)[1] != 0)
     if $game_party.item_number(i) > 0 && result
       @data.push($data_items[i])
     end
   }
   @item_max = @data.size
   # Create a new bitmap that will contain the listed items
   if @item_max > 0
     self.contents = Bitmap.new(width - 32, row_max * 32)
     (0...@item_max).each {|i| draw_item(i) }
   end
 end
 #-----------------------------------------------------------------------------
 def draw_item(index)
   item = @data[index]
   # Set a few local variables depending on the type of item.
   quantity = case item
   when RPG::Weapon then $game_party.weapon_number(item.id)
   when RPG::Armor then $game_party.armor_number(item.id)
   when RPG::Item then $game_party.item_number(item.id)
   end
   # Draw the name, icon, and quantity of the item.
   x, y = 4, index * 32
   rect = Rect.new(x, y, self.width / @column_max - 32, 32)
   self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
   bitmap = RPG::Cache.icon(item.icon_name)
   self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
   self.contents.draw_text(x + 28, y, 212, 32, item.name, 0)
 end
 #-----------------------------------------------------------------------------
 def update_help
   @help_window.set_text(self.item == nil ? '' : self.item.description)
 end
end

#===============================================================================
# ** Window_BlacksmithMaterials
#===============================================================================

class Window_BlacksmithMaterials < Window_Base
 
 attr_accessor :active
 
 def initialize
   # Initialize window size and coordinates.
   super(0, 128, 368, 352)
   self.visible = @active = false
 end
 #-----------------------------------------------------------------------------
 def refresh(item, type = 0)
   # Clear the bitmap and set the new materials.
   if self.contents != nil
     self.contents = self.contents.dispose
   end
   set_materials(item, type)
   # Create a new bitmap, based off the amount of materials
   if @materials != nil && @materials.size > 0
     self.contents = Bitmap.new(self.width - 32, 64 + (@materials.size * 32))
     # Draw each material and quantity required.
     self.contents.font.color = system_color
     word = type == 0 ? 'Cost' : ($data_system.words.gold + ':')
     self.contents.draw_text(4, 0, 212, 32, word, 0)
     text = type == 0 ? 'Required Materials:' : 'Extractable Materials:'
     self.contents.draw_text(4, 32, 368, 32, text, 0)
     self.contents.font.color = normal_color
     self.contents.draw_text(244, 0, 88, 32, @price.to_s, 2)
     # Enumerate through each material.
     @materials.each_index {|i|
       # Set local variable to current item, depending on type.
       case @materials[i][0]
       when 0
         item = $data_weapons[@materials[i][1]]
         enough = $game_party.weapon_number(item.id) >= @materials[i][2]
       when 1
         item = $data_armors[@materials[i][1]]
         enough = $game_party.armor_number(item.id) >= @materials[i][2]
       when 2
         item = $data_items[@materials[i][1]]
         enough = $game_party.item_number(item.id) >= @materials[i][2]
       end
       next if item == nil
       # Set local variable to store required amount of this item.
       required = @materials[i][2]
       # Set color of text, draw grayed if out if forging and not enough.
       self.contents.font.color = normal_color
       if type == 0 && !enough
         self.contents.font.color = disabled_color
       end
       # Set coordinates of current line.
       x, y = 4, 64 + (i * 32)
       # Draw item name, icon, and required amount.
       rect = Rect.new(x, y, self.width - 32, 32)
       self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
       bitmap = RPG::Cache.icon(item.icon_name)
       opacity = self.contents.font.color == normal_color ? 255 : 128
       self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
       self.contents.draw_text(x + 28, y, 212, 32, item.name)
       self.contents.draw_text(x + 272, y, 48, 32, 'x', 0)
       self.contents.draw_text(x + 272, y, 48, 32, required.to_s, 2)
     }
   elsif @price > 0
     self.contents = Bitmap.new(self.width - 32, 64)
     self.contents.font.color = system_color
     self.contents.draw_text(4, 0, 212, 32, $data_system.words.gold + ':')
     self.contents.font.color = normal_color
     self.contents.draw_text(244, 0, 88, 32, @price.to_s, 2)
     self.contents.draw_text(4, 32, 368, 32, 'No Materials')
   end
 end
 #-----------------------------------------------------------------------------
 def set_materials(item, type)
   # Sets the required/extractable items for the passed item.
   id = item.id
   if item.is_a?(RPG::Weapon)
     @materials = type == 0 ? Blacksmith.weapon_forges(id) :
       Blacksmith.weapon_extractions(id)
     @price = Blacksmith.weapon_gold(id)[type]
   elsif item.is_a?(RPG::Armor)
     @materials = type == 0 ? Blacksmith.armor_forges(id) :
       Blacksmith.armor_extractions(id)
     @price = Blacksmith.armor_gold(id)[type]
   else
     if @materials != 2
       @materials = type == 0 ? Blacksmith.item_forges(id) :
         Blacksmith.item_extractions(id)
       @price = Blacksmith.item_gold(id)[type]
     end
   end
 end
 #-----------------------------------------------------------------------------
 def update
   # Allow scrolling of bitmap if materials don't fit in window.
   if @active && self.contents != nil && self.contents.height > 320
     if Input.trigger?(Input::UP)
       if self.oy > 0
         self.oy -= 32
         $game_system.se_play($data_system.cursor_se)
       end
     elsif Input.trigger?(Input::DOWN)
       if (self.oy + 320) < self.contents.height
         self.oy += 32
         $game_system.se_play($data_system.cursor_se)
       end
     end
   end
 end
end

#===============================================================================
# ** Window_BlacksmithStatus
#===============================================================================

class Window_BlacksmithStatus < Window_Base
 
 def initialize
   super(368, 128, 272, 352)
   self.contents = Bitmap.new(width - 32, height - 32)
   # Create array of sprites same size as party
   @sprites = [Sprite.new, Sprite.new, Sprite.new, Sprite.new]
   #@sprites = Array.new($game_party.actors.size, Sprite.new)
   # Set coordinates of each sprite
   @sprites.each_index {|i|
     @sprites[i].x, @sprites[i].y = 380, 194 + (i * 64)#(i * 34)
     @sprites[i].z = self.z + 10
   }
   self.visible = false
   # Array of flags for walking
   @walk = Array.new($game_party.actors.size, false)
   @count, @item = 0, nil
   refresh
 end
 #-----------------------------------------------------------------------------
 def refresh
   # Clear bitmap and turn off visiblity of each sprite.
   self.contents.clear
   @sprites.each {|sprite| sprite.visible = false }
   # Return if selected item index is undefined.
   return if @item == nil
   self.contents.font.size = Font.default_size + 2
   quantity = case @item
   when RPG::Item then $game_party.item_number(@item.id)
   when RPG::Weapon then $game_party.weapon_number(@item.id)
   when RPG::Armor then $game_party.armor_number(@item.id)
   end
   self.contents.font.color = system_color
   self.contents.draw_text(4, 0, 200, 32, 'Possessed:')
   self.contents.font.color = normal_color
   self.contents.draw_text(204, 0, 32, 32, quantity.to_s, 2)
   # Disable walking animation and end method if selected item is a normal item
   if @item.is_a?(RPG::Item)
     @walk.collect! {|value| false }
     return
   end
   # Change the font size.
   self.contents.font.size = Font.default_size - 1
   # Iterate each actor...
   $game_party.actors.each_index {|i|
     chr = $game_party.actors[i]
     # Set local variable to highlighted piece of equipment.
     if @item.is_a?(RPG::Weapon)
       eqp = $data_weapons[chr.weapon_id]
     else
       armors = [chr.armor1_id, chr.armor2_id, chr.armor3_id, chr.armor4_id]
       eqp = $data_armors[armors[@item.kind]]
     end
     # Draw the actor sprite.
     draw_actor_graphic(i, chr.equippable?(@item))
     # Draw message and return if unequippable.
     unless chr.equippable?(@item)
       self.contents.font.color = normal_color
       self.contents.draw_text(32, 54 + (i * 64), 150, 32, 'Cannot Equip')
       next
     else
       # Create array of stat changes.
       # [str, dex, agi, int, pdef, mdef, (atk || eva)]
       stats = [
         (@item == nil ? 0 : @item.str_plus) - (eqp == nil ? 0 : eqp.str_plus),
         (@item == nil ? 0 : @item.dex_plus) - (eqp == nil ? 0 : eqp.dex_plus),
         (@item == nil ? 0 : @item.agi_plus) - (eqp == nil ? 0 : eqp.agi_plus),
         (@item == nil ? 0 : @item.int_plus) - (eqp == nil ? 0 : eqp.int_plus),
         (@item == nil ? 0 : @item.pdef) - (eqp == nil ? 0 : eqp.pdef),
         (@item == nil ? 0 : @item.mdef) - (eqp == nil ? 0 : eqp.mdef)
       ]
       if @item.is_a?(RPG::Weapon)
         stats.push(
           (@item == nil ? 0 : @item.atk) - (eqp == nil ? 0 : eqp.atk))
       elsif @item.is_a?(RPG::Armor)
         stats.push(
           (@item == nil ? 0 : @item.eva) - (eqp == nil ? 0 : eqp.eva))
       end
       # Set local variable to each piece of equipments' name
       current_name = eqp == nil ? '' : eqp.name
       new_name = @item == nil ? '' : @item.name
       # If stats are all equal, show message and end method.
       if stats.all? {|stat| stat == 0 }
         self.contents.font.color = normal_color
         if current_name != new_name
           self.contents.draw_text(32, 54 + (i * 64), 150, 32, 'No Change')
         else
           self.contents.draw_text(32, 54 + (i * 64), 150, 32, 'Equipped')
         end
         next
       end
       # Draw any stat changes, using colors to show plus/minus changes
       self.contents.font.size = (Font.default_size - 1)
       self.contents.font.color = normal_color
       self.contents.draw_text(104, 42 + (64*i), 32, 32, 'STR ') if stats[0] != 0
       self.contents.draw_text(104, 58 + (64*i), 32, 32, 'DEX ') if stats[1] != 0
       self.contents.draw_text(104, 74 + (64*i), 32, 32, 'AGI ') if stats[2] != 0
       self.contents.draw_text(176, 42 + (64*i), 32, 32, 'INT ') if stats[3] != 0
       self.contents.draw_text(32, 58 + (64*i), 32, 32, 'PDF ') if stats[4] != 0
       self.contents.draw_text(32, 74 + (64*i), 32, 32, 'MDF ') if stats[5] != 0
       if stats[-1] != 0
         # Show stats changes for atk/eva, depending on the equipment type
         stat = @item.is_a?(RPG::Weapon) ? 'ATK ' : 'EVA '
         self.contents.draw_text(32, 42 + (64 * i), 32, 32, stat) if stat != 0
       end
       # Show any stat changes
       stats.each_index {|j|
         next if stats[j] == 0
         xy = case j
         when 0 then [132, 42 + (64 * i)]
         when 1 then [132, 58 + (64 * i)]
         when 2 then [132, 74 + (64 * i)]
         when 3 then [198, 42 + (64 * i)]
         when 4 then [60, 58 + (64 * i)]
         when 5 then [60, 74 + (64 * i)]
         when 6 then [60, 42 + (64 * i)]
         end
         # Set color and operator depending on value
         if stats[j] < 0
           self.contents.font.color, sign = Blacksmith::MINUS_COLOR, '-'
         else
           self.contents.font.color, sign = Blacksmith::PLUS_COLOR, '+'
         end
         self.contents.draw_text(xy[0], xy[1], 8, 32, sign, 1)
         self.contents.draw_text(xy[0] + 10, xy[1], 24, 32, stats[j].abs.to_s)
       }
     end
   }
 end
 #-----------------------------------------------------------------------------
 def item=(item)
   if @item != item
     # Change the item variable and refresh.
     @item = item
     refresh
   end
 end
 #-----------------------------------------------------------------------------
 def draw_actor_graphic(id, equipable)
   # Draws the actor graphic
   actor = $game_party.actors[id]
   @sprites[id].bitmap = RPG::Cache.character(actor.character_name,
     actor.character_hue)
   @sprites[id].src_rect.set(0, 0, @sprites[id].bitmap.width / 4,
   @sprites[id].bitmap.height / 4)
   # Set walking animation if item is equippable.
   @walk[id] = equipable
   @sprites[id].tone = Tone.new(0, 0, 0, equipable ? 0 : 255)
   @sprites[id].visible = true
 end
 #-----------------------------------------------------------------------------
 def update
   super
   # Update the walking animation.
   @count = (@count + 1) % 40
   $game_party.actors.each_index {|i|
     next unless @walk[i]
     if @sprites[i].bitmap != nil
       w = @sprites[i].bitmap.width / 4
       h = @sprites[i].bitmap.height / 4
       x = (@count / 10) * w
       @sprites[i].src_rect.set(x, 0, w, h)
     end
   }
 end
 #-----------------------------------------------------------------------------
 def visible=(bool)
   super
   # Set visible to the actor sprites as well.
   @sprites.each {|sprite| sprite.visible = bool }
 end
 #-----------------------------------------------------------------------------
 def dispose
   super
   # Dispose the actor sprites as well.
   @sprites.each {|sprite| sprite.dispose }
 end
end


#===============================================================================
# ** Window_BlacksmithExtract
#===============================================================================

class Window_BlacksmithEnchant < Window_Selectable

 def initialize
   super(0, 128, 368, 352)
   self.active = self.visible = false
   refresh
   self.index = 0
 end
 #-----------------------------------------------------------------------------
 def item
   return @data[self.index]
 end
 #-----------------------------------------------------------------------------
 def refresh
   # Dispose current bitmap if defined.
   if self.contents != nil
     self.contents = self.contents.dispose
   end
   # Create list of items in inventory
   @data = []
   ($data_items - [nil]).each {|item|
     result = false
     result = true if Blacksmith.enchant_stats(item.id) != nil
     result = true if Blacksmith.enchant_states(item.id) != nil
     result = true if Blacksmith.enchant_elements(item.id) != nil
     @data.push(item) if result
   }
   @item_max = @data.size
   # Create a new bitmap that will contain the listed items
   if @item_max > 0
     self.contents = Bitmap.new(width - 32, row_max * 32)
     (0...@item_max).each {|i| draw_item(i) }
   end
 end
 #-----------------------------------------------------------------------------
 def draw_item(index)
   item = @data[index]
   # Set a few local variables depending on the type of item.
   quantity = $game_party.item_number(item.id)
   # Draw the name, icon, and quantity of the item.
   x, y = 4, index * 32
   rect = Rect.new(x, y, self.width / @column_max - 32, 32)
   self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
   bitmap = RPG::Cache.icon(item.icon_name)
   self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24))
   self.contents.draw_text(x + 28, y, 212, 32, item.name, 0)
   self.contents.draw_text(x + 240, y, 16, 32, ':', 1)
   self.contents.draw_text(x + 256, y, 24, 32, quantity.to_s, 2)
 end
 #-----------------------------------------------------------------------------
 def update_help
   @help_window.set_text(self.item == nil ? '' : self.item.description)
 end
end

#===============================================================================
# ** Scene_Blacksmith
#===============================================================================

class Scene_Blacksmith
 
 def initialize(weapons = [], armors = [], items = [], level = nil)
   # Set available goods for this shop based off passed argument.
   @goods = []
   @goods += weapons.collect {|id| $data_weapons[id] }
   @goods += armors.collect {|id| $data_armors[id] }
   @goods += items.collect {|id| $data_items[id] }
   @goods.uniq!
   # Configure the level variable
   @level = (level == nil) ? Array.new(4, true) : (level + [true])
   @enchants = Blacksmith::USE_ENCHANTMENTS
 end
 #-----------------------------------------------------------------------------
 def main
   # Create a Proc to handle confirmation of choices
   @confirm_proc = Proc.new {
     @help_window.set_text('Are you sure?')
     window = Window_Command.new(160, ['Confirm', 'Cancel'])
     window.x, window.y, window.z = 224, 192, 9999
     loop { Graphics.update; Input.update; window.update
       if Input.trigger?(Input::C) || Input.trigger?(Input::B)
         result = (Input.trigger?(Input::C) && window.index == 0)
         $game_system.se_play($data_system.cancel_se) unless result
         window.dispose
         break(result)
       end
     }
   }
   # Initialize the needed windows.
   @command_window = Window_BlacksmithCommand.new(@level)
   @forge_window = Window_BlacksmithForge.new(@goods)
   @extract_window = Window_BlacksmithExtract.new
   @materials_window = Window_BlacksmithMaterials.new
   @enchant_window = Window_BlacksmithEnchant.new
   @status_window = Window_BlacksmithStatus.new
   @dummy_window = Window_Base.new(0, 128, 640, 352)
   @gold_window = Window_Gold.new
   @gold_window.x, @gold_window.y = 480, 64  
   @help_window = Window_Help.new
   # Bind the help window to the other windows.
   @forge_window.help_window = @extract_window.help_window = @help_window
   @enchant_window.help_window = @help_window
   # Set a windows array for easier handling of all windows.
   @windows = [@command_window, @forge_window, @extract_window, @help_window,
     @materials_window, @status_window, @dummy_window, @gold_window, @enchant_window]
   # Create map sprite if configured to do so, and set window opacity
   if Blacksmith::MAP_BACK
     @spriteset = Spriteset_Map.new
     @windows.each {|window| window.opacity = 160 }
   end
   # Execute the transition and start the main loop.
   Graphics.transition
   loop {Graphics.update; Input.update; update; break if $scene != self }
   # Freeze the Graphics and dispose the windows
   Graphics.freeze
   @windows.each {|window| window.dispose }
   if Blacksmith::MAP_BACK && @spriteset != nil
     @spriteset.dispose
   end
 end
 #-----------------------------------------------------------------------------
 def update
   # Update the windows
   @windows.each {|window| window.update }
   # Branch method depending on current action.
   if @command_window.active
     update_command
   elsif @extract_window.active
     update_extract
   elsif @forge_window.active
     update_forge
   elsif @materials_window.active
     update_materials
   elsif @enchant_window.active
     update_enchant
   end
 end
 #-----------------------------------------------------------------------------
 def back_to_map
   # Play SE and return to the map.
   $game_system.se_play($data_system.cancel_se)
   $scene = Scene_Map.new
 end
 #-----------------------------------------------------------------------------
 def update_command
   # Set help text depending on the selected index.
   help_text = case @command_window.index
   when 0 then 'Use materials to forge new weapons, armors, and items.'
   when 1 then 'Extract materials from weapons, armors, and items.'
   when 2 then !@enchants ? 'Exit the shop.' :
     'Enchant weapons, armors, and items using other items.'
   when 3 then 'Exit the shop.'
   end
   @help_window.set_text(help_text)
   # Check for Input.
   if Input.trigger?(Input::B)
     back_to_map
   elsif Input.trigger?(Input::C)
     $game_system.se_play($data_system.decision_se)
     # Branch depending on command index
     case @command_window.index
     when 0
       # Play SE and return if option is locked.
       unless @level[0]
         $game_system.se_play($data_system.buzzer_se)
         return
       end
       # Shift scene to forge phase.
       @dummy_window.visible = false
       @forge_window.refresh(false)
       @command_window.active = false
       @forge_window.active = @forge_window.visible = true
       @status_window.visible = true
     when 1
       # Play SE and return if option is locked.
       unless @level[1]
         $game_system.se_play($data_system.buzzer_se)
         return
       end
       # Shift scene to extract phase
       @extract_window.refresh
       @command_window.active = @dummy_window.visible = false
       @extract_window.active = @extract_window.visible = true
       @status_window.visible = true
     when 2
       # Play SE and return if option is locked.
       if @enchants
         unless @level[2]
           $game_system.se_play($data_system.buzzer_se)
           return
         end
         # Shift scene to enchant phase.
         @forge_window.refresh(true)
         @command_window.active = @dummy_window.visible = false
         @forge_window.active = @forge_window.visible = true
         @status_window.visible = true
       else
         back_to_map
       end
     when 3
       back_to_map
     end
   end
 end
 #-----------------------------------------------------------------------------
 def update_forge
   # Update for input when forge window is active.
   @item = @status_window.item = @forge_window.item
   if Input.trigger?(Input::B)
     $game_system.se_play($data_system.cancel_se)
     @command_window.active = @dummy_window.visible = true
     @forge_window.active = @forge_window.visible = false
     @status_window.visible = false
   elsif Input.trigger?(Input::C)
     $game_system.se_play($data_system.decision_se)
     @forge_window.active = @forge_window.visible = false
     if @command_window.index == 0
       @materials_window.refresh(@item, 0)
       @materials_window.visible = @materials_window.active = true
     else
       @enchant_window.refresh
       @enchant_window.visible = @enchant_window.active = true
     end
   end
 end
 #-----------------------------------------------------------------------------
 def update_extract
   # Update for input when extraction window is active.
   @item = @status_window.item = @extract_window.item
   if Input.trigger?(Input::B)
     $game_system.se_play($data_system.cancel_se)
     @command_window.active = @dummy_window.visible = true
     @extract_window.active = @extract_window.visible = false
     @status_window.visible = false
   elsif Input.trigger?(Input::C)
     $game_system.se_play($data_system.decision_se)
     @materials_window.refresh(@item, 1)
     @extract_window.active = @extract_window.visible = false
     @materials_window.visible = @materials_window.active = true
   end
 end
 #-----------------------------------------------------------------------------
 def update_enchant
   # Update input on the enchantment items screen.
   if Input.trigger?(Input::B)
     # Return to previous screen if cancel button is pressed.
     $game_system.se_play($data_system.cancel_se)
     @enchant_window.visible = @enchant_window.active = false
     @forge_window.active = @forge_window.visible = true
   elsif Input.trigger?(Input::C) && @confirm_proc.call
     enchant_item
   end
 end
 #-----------------------------------------------------------------------------
 def enchant_item
   # Apply enchantment to weapon/armor using item
   $game_party.lose_item(@enchant_window.item.id, 1)
   Blacksmith.create_item(@forge_window.item, @enchant_window.item)
   # Play SE
   $game_system.se_play(RPG::AudioFile.new(*Blacksmith::ENCHANT_SE))
   # Refesh windows
   [@enchant_window, @status_window].each {|window| window.refresh }
   @forge_window.refresh(true)
   # Return to previous screen
   @enchant_window.visible = @enchant_window.active = false
   @forge_window.active = @forge_window.visible = true
 end
 #-----------------------------------------------------------------------------
 def update_materials
   # Show help text.
   text = 'Press the Action Button to proceed. Press Cancel to go back'
   @help_window.set_text(text)
   if Input.trigger?(Input::B)
     # Return to previous screen if cancel button is pressed.
     $game_system.se_play($data_system.cancel_se)
     @materials_window.visible = @materials_window.active = false
     if @command_window.index == 0
       @forge_window.active = @forge_window.visible = true
     else
       @extract_window.active = @extract_window.visible = true
     end
   elsif Input.trigger?(Input::C) && @confirm_proc.call
     @command_window.index == 0 ? forge_item : extract_item
   end
 end
 #-----------------------------------------------------------------------------
 def forge_item
   # Set local variables depending on item type.
   case @item
   when RPG::Weapon
     quantity, type = $game_party.weapon_number(@item.id), 0
     materials = Blacksmith.weapon_forges(@item.id)
     price = Blacksmith.weapon_gold(@item.id)[0]
   when RPG::Armor
     quantity, type = $game_party.armor_number(@item.id), 1
     materials = Blacksmith.armor_forges(@item.id)
     price = Blacksmith.armor_gold(@item.id)[0]
   when RPG::Item
     quantity, type = $game_party.item_number(@item.id), 2
     materials = Blacksmith.item_forges(@item.id)
     price = Blacksmith.item_gold(@item.id)[0]
   end
   # If player doesn't have the materials or gold, play SE and end method.
   unless Blacksmith.materials?(type, @item.id)
     $game_system.se_play($data_system.buzzer_se)
     return
   end
   # End method and play buzzer if inventory is full.
   return $game_system.se_play($data_system.buzzer_se) if quantity == 99
   # Play the defined SE used when forging.
   $game_system.se_play(RPG::AudioFile.new(*Blacksmith::FORGE_SE))
   # Remove required materials from inventory and subtract gold cost.
   if materials != nil
     materials.each {|material|
       case material[0]
       when 0 then $game_party.lose_weapon(material[1], material[2])
       when 1 then $game_party.lose_armor(material[1], material[2])
       when 2 then $game_party.lose_item(material[1], material[2])
       end
     }
   end
   $game_party.lose_gold(price)
   # Add forged item
   case @item
   when RPG::Weapon then $game_party.gain_weapon(@item.id, 1)
   when RPG::Armor then $game_party.gain_armor(@item.id, 1)
   when RPG::Item then $game_party.gain_item(@item.id, 1)
   end
   # Reset windows.
   @materials_window.visible = @materials_window.active = false
   @forge_window.active = @forge_window.visible = true
   # Refresh any windows that may have changed
   [@status_window, @gold_window, @extract_window, @forge_window,
     @enchant_window].each {|window| window.refresh }
 end
 #-----------------------------------------------------------------------------
 def extract_item
   # Set local variables depending on item type.
   case @item
   when RPG::Weapon
     quantity = $game_party.weapon_number(@item.id)
     materials = Blacksmith.weapon_extractions(@item.id)
     price = Blacksmith.weapon_gold(@item.id)[1]
   when RPG::Armor
     quantity = $game_party.armor_number(@item.id)
     materials = Blacksmith.armor_extractions(@item.id)
     price = Blacksmith.armor_gold(@item.id)[1]
   when RPG::Item
     quantity = $game_party.item_number(@item.id)
     materials = Blacksmith.item_extractions(@item.id)
     price = Blacksmith.item_gold(@item.id)[1]
   end
   # If nothing is defined for the extraction, return.
   if materials == nil || (materials.empty? && price == 0)
     return $game_system.se_play($data_system.buzzer_se)
   end
   # Play extraction SE
   $game_system.se_play(RPG::AudioFile.new(*Blacksmith::EXTRACT_SE))
   # Perform extraction, adding materials and increasing gold.
   materials.each {|material|
     case material[0]
     when 0 then $game_party.gain_weapon(material[1], material[2])
     when 1 then $game_party.gain_armor(material[1], material[2])
     when 2 then $game_party.gain_item(material[1], material[2])
     end
   }
   $game_party.gain_gold(price)
   # Remove extracted item from inventory
   case @item
   when RPG::Weapon then $game_party.lose_weapon(@item.id, 1)
   when RPG::Armor then $game_party.lose_armor(@item.id, 1)
   when RPG::Item then $game_party.lose_item(@item.id, 1)
   end
   # Reset windows.
   @materials_window.visible = @materials_window.active = false
   @extract_window.active = @extract_window.visible = true
   # Refresh any windows that may have changed
   [@status_window, @gold_window, @extract_window].each {|window| window.refresh }
 end
end

KK20 wrote a bugfix. It mainly addresses the enchantment system and displays of the windows. Get it here: http://pastebin.com/AFrMCa2f


Instructions

Place script below Debug and above Main.
Instructions are in the script.


Compatibility

  • If you have a script that re-writes Window_Gold, it could cause graphical irregularities on the blacksmith screen.

  • Scripts that alter items in the database may cause issues, though not tested.



Credits and Thanks


  • ForeverZer0, for writing the script

  • RoseSkye, huge thanks for beta-testing and demo map




Author's Notes

Please report any bugs you may find at www.chaos-project.com.
Hope you enjoy!
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Ravenith

Very nice. The "Extract" feature explores a nice design space that few scripts had (directly) explored in the past.

Nadim13

It seems cool.
I'll try it this afternoon and I let you know. 8)

Agckuu Coceg


;) New interesting script. But maybe add a little more customization, something like for example the old Prexcraft? It would be nice.
I'm not retarded, but I'm busy. Sorry for patience.


Nadim13

Ok, that's a cool (and very simple to customize) script, good work! ;)
But I suggest you to edit the extract part: it would be better that, when you extract materials from your weapon/armor, you'll receive less quantity of them instead the same number of the creation part.

Ex.
3 Gold Ore => Gold Sword
and, during the extraction
Gold Sword => 2 Gold Ore

By the way, once again... good work! 8)

lonely_cubone

I like this script, but one thing that would be really helpful is if you could create and extract things in bulk. For example, when you select Forge Iron Sword, and you have enough materials to make 12 of them, it will let you choose how many to make. Other than that, I think this script is quite useful. :D

ForeverZer0

Thanks for the feedback everybody.
I'll see about adding the new features. I was already thinking about a few of them...
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

13579

Sorry to say, found a bug. When extracting items from a weapon, keep going until there are no more weapons left to extract items from. Keep clicking the extract button on the blank, and even though nothing is there, it will keep extracting and giving you minerals from the last weapon that was in the slot. When I exited the blacksmith system and went into the menu I had 99 gold ore. When I attempted to go back into the system to do it some more, I got this error:

 Script 'Blacksmith System' line 622: NoMethodError occurred.
undefined method 'each_index' for nil:NilClass


Sorry, I'm a noob scripter and have no idea how to fix this. Over the past 4 days I've gone over this entire forums script database for RPGXP, downloaded what interested me, and am slowly learning how to make things work by looking at others scripts. Just happened to find this when I was bored. Other than that, this is a really useful script.

ForeverZer0

@13579
Don't be sorry, I welcome people to find bugs so I can fix them. It is very difficult to completely de-bug an entire script and think of everything, so it is helpful for others to let me know what they find.

I'll check this problem and have it fixed soon. Thanks!
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

XaineC

I've got an error for you. Line 647 NoMethodError occured. undefined method `each_index' for 1:Fixnum

ForeverZer0

Quote from: XaineC on August 24, 2010, 12:30:38 pm
I've got an error for you. Line 647 NoMethodError occured. undefined method `each_index' for 1:Fixnum


When and how did it occur. That would really help narrow it down.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

XaineC

Nevermind. I screwed up the script call, that's it.

ForeverZer0

Quote from: XaineC on August 24, 2010, 07:59:49 pm
Nevermind. I screwed up the script call, that's it.


Okay.  ;) Thanks anyway.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Ninjason

December 16, 2010, 02:38:11 pm #13 Last Edit: December 16, 2010, 02:39:34 pm by Ninjason
Hey, great script, quite the thing I was looking for.

I inserted it, configured it - but upon using it, I get this error message every time I would get the item #434 among other things out of a deconstruction:



What could that be?
there's only one Ninja an these are the scripts he currently uses:
* Easy Party Switcher by Blizzard (v2.43b)
* Universal Message System (v1.8.0) by Ccoa
* Active-Time-Battle by MakirouAru
* Catergorized Items Menu (v1.3) by albertfish
* Law's Custom Equipment Screen (v2.?) by The Law G14
* Advanced Shop Status Window (v2.0) by RPG Advocate, edited by Fantasist
* Blacksmith Shop (v2.0) by ForeverZer0
* Quest Log System (v3.0) by game_guy
* Enemy HP & MP Bars by Asandril
* Map Location (v1.0) by Hunter x
* Switch Checker by Night_Runners (made for me specifically)
* Redd's TitleIcons by Redd
* Journal (v2.4) by ForeverZer0
* Drago Smooth Scroller (v2.02) by LiTTleDRAgo

Taiine

Error. It happens if you have no items that you can extract materials from but still go to the menu and try to 'extract' from the blank listing.




ForeverZer0

I will check it out. This is one of my earlier scripts, I think it is ready for a complete re-write. I learned quite a bit since writing it, so just old off a little bit and I will release a completely new and improved version of it. I'll add some new features as well, such as configurable extracted materials, etc.

Any other requests before I get started?
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Ninjason

December 20, 2010, 04:10:42 pm #16 Last Edit: December 20, 2010, 04:13:42 pm by Ninjason
Actually, yes - When you extract items from the weapon/armor on the very bottom of your list and deplete your stock, you have the possibility, to stay on that empty slot and keep extracting even though you have no more items left.

But it works nevertheless - you can get an infinite number of extracted items by that.

Here's a screenshot to help my explanation (did it with your demo):
there's only one Ninja an these are the scripts he currently uses:
* Easy Party Switcher by Blizzard (v2.43b)
* Universal Message System (v1.8.0) by Ccoa
* Active-Time-Battle by MakirouAru
* Catergorized Items Menu (v1.3) by albertfish
* Law's Custom Equipment Screen (v2.?) by The Law G14
* Advanced Shop Status Window (v2.0) by RPG Advocate, edited by Fantasist
* Blacksmith Shop (v2.0) by ForeverZer0
* Quest Log System (v3.0) by game_guy
* Enemy HP & MP Bars by Asandril
* Map Location (v1.0) by Hunter x
* Switch Checker by Night_Runners (made for me specifically)
* Redd's TitleIcons by Redd
* Journal (v2.4) by ForeverZer0
* Drago Smooth Scroller (v2.02) by LiTTleDRAgo

Ninjason

Btw i cleared my error message - I used a dot (.) instead of a comma (,) in the formulas. :ninja:
there's only one Ninja an these are the scripts he currently uses:
* Easy Party Switcher by Blizzard (v2.43b)
* Universal Message System (v1.8.0) by Ccoa
* Active-Time-Battle by MakirouAru
* Catergorized Items Menu (v1.3) by albertfish
* Law's Custom Equipment Screen (v2.?) by The Law G14
* Advanced Shop Status Window (v2.0) by RPG Advocate, edited by Fantasist
* Blacksmith Shop (v2.0) by ForeverZer0
* Quest Log System (v3.0) by game_guy
* Enemy HP & MP Bars by Asandril
* Map Location (v1.0) by Hunter x
* Switch Checker by Night_Runners (made for me specifically)
* Redd's TitleIcons by Redd
* Journal (v2.4) by ForeverZer0
* Drago Smooth Scroller (v2.02) by LiTTleDRAgo

ForeverZer0

I know already of the the extraction error, but thanks for making sure.  ;)

When I said "requests", I meant more of added features one may like in the next version. Fixing bugs will be my top priority obviously. The error you mentioned will be definitely fixed, though.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

SilverShadow737

Pretty sweet script,  maybe a feature to add would be to show how many materials the player has before forging either by pushing a button, or simply in the confirm menu.  Also you could try to space stats a little better because the + or - overlap the letters.  My final suggestion is maybe you could add item creation such as two ingredients create a potion, or iron + coal = steel?
Ginyu Force Rules