ForeverZer0 44 Report post Posted May 14, 2011 (edited) Blacksmith Shop Authors: ForeverZer0 Version: 2.0 Type: Custom Shop 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 Configuration Application 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. #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=: # 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 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! Edited May 14, 2011 by ForeverZer0 1 Jon Bon reacted to this Share this post Link to post Share on other sites
FranklinX 37 Report post Posted May 14, 2011 This script sounds very usefull. Can it be used for the VX? Share this post Link to post Share on other sites
ForeverZer0 44 Report post Posted May 14, 2011 This script sounds very usefull. Can it be used for the VX? Although I have never tested it, I'm sure it cannot due to RGSS and RGSS2 being structured differently. I have never really used VX or written scripts specifically for it, so I am unsure of all the changes made. Share this post Link to post Share on other sites
frsgalaxy 0 Report post Posted May 14, 2011 Would it be possible for you to convert the code to VX? this system seems a ton more user friendly than that of KGC :) I hate typing in Arrays aswel so this would help to no end :) Share this post Link to post Share on other sites
diagostimo 11 Report post Posted May 14, 2011 hey, just wondering if there is a way that i could use this to mod items to make diamond tipped arrows and ammo etc, also i it would be compatible with my script, im using mr mo's abs, it sources weapon ids from the weapon database Share this post Link to post Share on other sites
Tenoukii 0 Report post Posted May 14, 2011 Hey... how can I use this with just the enchantments? Bit of a silly question, but still (: I just want to be able to attach pre-brought gems onto weapons/armour/accessories (and be able to take them off again) at no cost, from the menu, with the same state/element change feature. Share this post Link to post Share on other sites
imapro 1 Report post Posted July 21, 2011 This script is awesome but it isnt working for me (i think its my other scripts) but i can live without but i had to say that it is BEAST :D Share this post Link to post Share on other sites