Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Blacksmith System

Blacksmith System Version: 2.0
By: ForeverZer0

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

Blacksmith2.png
Blacksmith3.png
Blacksmith1.png

Demo

Demo Link

Script

[rgss]#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# 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 http://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 == nil
      if old.is_a?(RPG::Weapon) && $data_classes.weapon_set.include?(old.id)
        $data_classes.weapon_set.push(new.id)
      elsif old.is_a?(RPG::Armor) && $data_classes.armor_set.include?(old.id)
        $data_classes.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)  
      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)  
      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)
      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[0]
        when 0
          item = $data_weapons[@materials[1]]
          enough = $game_party.weapon_number(item.id) >= @materials[2]
        when 1
          item = $data_armors[@materials[1]]
          enough = $game_party.armor_number(item.id) >= @materials[2]
        when 2
          item = $data_items[@materials[1]]
          enough = $game_party.item_number(item.id) >= @materials[2]
        end
        next if item == nil
        # Set local variable to store required amount of this item.
        required = @materials[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.x, @sprites.y = 380, 194 + (i * 64)#(i * 34)
      @sprites.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
      # 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
      if @sprites.bitmap != nil
        w = @sprites.bitmap.width / 4
        h = @sprites.bitmap.height / 4
        x = (@count / 10) * w
        @sprites.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
[/rgss]

Instructions

Place script below Debug and above Main.
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)

Further instructions are within 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

RoseSkye, huge thanks for beta-testing and demo map

Author's Notes

Please report any bugs/issues so that they can be resolved. Enjoy!

Terms and Conditions

Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
You are free:

to Share - to copy, distribute and transmit the work
to Remix - to adapt the work

Under the following conditions:

Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).

Noncommercial. You may not use this work for commercial purposes.

Share alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.

- For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.

- Any of the above conditions can be waived if you get permission from the copyright holder.

- Nothing in this license impairs or restricts the author's moral rights.
 
Is there an easy way to remove the small window on the right (with the gold) and extend the "forge, extract, and ext" window to the length of the screen?

(Is there an easy way to remove the need for gold at all?)

I want to try and use this script for a playable character who is a blacksmith. Right now, I do all of the blacksmithing through events, but it really bad and clunky, having it done with text boxes and conditional branches.

The idea is that there are multiple Anvils & Forge found throughout the game. If you have the right materials and enough skill in Blacksmithing, she'll be able to forge something if you use her Blacksmithy skill from her skill menu.


I haven't tested the script out yet, but I'm looking through it and I'm trying to find which line describes how this works:

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

Right now, in my game, I have a variable which determines skill (0-1000). Depending on that skill, she can craft different weapons & armor. I'm trying to figure out if I can set it so 0-99 skill gives one set of items, 100-199 can add on even more items, and so on. If it can, it'll be perfect. (The variable I'm using for my game to represent Blacksmithing is 51.)

And like with the Battle Arena script, of course, credit will be given.

<3
 
Here's a quick mod that eliminates the gold window.

http://dl.dropbox.com/u/20787370/Temp/BlackSmithMod.txt

Replace Scene_Blacksmith with that, and simply do not define values for the gold configuration section, so everything will return 0 cost by default.

There isn't so much of a "skill" variable, but here's a little snippet that will enable such a feature:

[rgss]module Blacksmith
 
  LEVEL_VARIABLE = 51
  # The ID of the variable you want to use as the Blacksmith's level
 
  def self.call(*args)
    equipment = self.equipment($game_variables[LEVEL_VARIABLE])
    unless args.empty?
      equipment.push(args[0])
    end
    $scene = Scene_Blacksmith.new(*equipment)
  end
 
  def self.equipment(level)
    equipment = [[], [], []]
    case level
    when 1
      equipment[0] = [] # Insert weapon IDs here for level one
      equipment[1] = [] # Insert armor IDs here for level one
      equipment[2] = [] # Insert item IDs here for level one
    when 2
      equipment[0] = [] # Insert weapon IDs here for level two
      equipment[1] = [] # Insert armor IDs here for level two
      equipment[2] = [] # Insert item IDs here for level two
    end
   
   
    # Just follow this same pattern for every level and add them here
   
   
    return equipment
  end
end
[/rgss]

Just increment the game variable as needed throughout your game. Instead of the normal script call, us this:

Code:
Blacksmith.call

After setting up the config, this will call the blacksmith scene using the blacksmith's current level to determine the equipment. You can also use the above call and provide the "[CAN_FORGE?, CAN_EXTRACT?, CAN_ENCHANT?]" argument with it as well, like this:

Code:
Blacksmith.call([true, true, false])
 
Ok so, I replaced the Scene_blacksmith at the end and inserted the Level_variable underneath the the blacksmith module and I got this:

blacksmithyforeverzero1.png


(I didn't fill out anything else, so it should be blank.)

But I want to fill out the real estate where the gold field used to be.

Also a question about this part:

Code:
    case level

    when 1

      equipment[0] = [] # Insert weapon IDs here for level one

      equipment[1] = [] # Insert armor IDs here for level one

      equipment[2] = [] # Insert item IDs here for level one

    when 2

      equipment[0] = [] # Insert weapon IDs here for level two

      equipment[1] = [] # Insert armor IDs here for level two

      equipment[2] = [] # Insert item IDs here for level two

    end

Then "when 1" and "when 2" are referencing the variable value right? So if I want my skill to scale to 1000, I should fill out 1000 of those, yes?
 
Yes, the "level" is the variable value. If you wanted for your blacksmith to have 1000 levels, then you would need to have 1000 "when" statements. If there is no change between levels, you can use syntax like this to combine them:

[rgss]when 3, 4, 5
  # code here
when 6, 7, 8
  # etc
[/rgss]

I'm sorry, I did have it edited, but I only uploaded you the one part. You can make the change yourself by finding the "Window_BlacksmithCommand " class and changing the call to its super:

[rgss]class Window_BlacksmithCommand < Window_Selectable
 
  def initialize(level)
    super(0, 64, 640, 64)
    # ... rest of code...
[/rgss]
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top