Crafting/recipe System
#1
Crafting/recipe System "final" Version, mix items (and more)
By Deke
posted by Dubealex
Mar 9 2005

This is a locked, single-post thread from Creation Asylum. Archived here to prevent its loss.
No support is given. If you are the owner of the thread, please contact administration.


Final version updates:
-Item stats are now properly displayed in the result's window. (Thanks Dubealex for the help file)
-It is now possible to create the same item using different ingredients. (Previously this did not work when you used a master list).
MORE UPDATES ADDED SEE LATER POST

Here a sample picture of the interface:
[Image: index.php?act=attach&type=post&id=295]


I will try to give a little better explanation on how to use this script.

First of in order to craft an item, you need to create a recipe. A recipe has 5 things.
1. INGREDIENTS (part 1)
An array of items used to make the desired object. These arrays simply consist of the indexes of the object taken form the database. For example, in the picture below the index of a tablet is 30. The indexes of a card and fruit would be 31 and 32, respectively. If we wanted to make a recipe that used all three objects, our ingredients array would look like the following:
[30,31,32]

[Image: index.php?act=attach&type=post&id=296]


NOTE: Even if you only need 1 ingredient you should encapsulate it as an array. For example, the proper syntax would be [15], not 15.


2. INGREDIENTS (part 2)
You may not want all your recipes to be made only items. Maybe you want a recipe that uses a regular sword combined with dragon breath to make a fire sword. In order to make this possible you have to specify in your recipe what type of ingredients you are using. Ingredients can be items, armors, or weapons. I use the following convention (consistent with the default programming)
-items are type 0
-armors are type 1
-weapons are type 2

So, in my example, all the "ingredients" are items, so my type array would be [0,0,0].
NOTE: The type list should always be the same size as the ingredients list.

3. INGREDIENTS (part 3)
Well now that we know what type the ingredients are and what there index is, what else could we possibly need to know? You guessed it, we need to know how many of each ingredient the recipe requires. Suppose we just wanted 1 of each type of ingredient, our array would look like this: (This array should be the same size as the other two.)
[1,1,1]

4. THE RESULT (part 1)
Just like with the ingredients you need to tell the recipe what the index is of the object you want to create. The only difference is that now it doesn’t need to be in an array (if fact it CAN’T be an array). So if you wanted to create a mithril sword, your result would simple be the index of the sword (in mine and the default case, that’s 4).

5. THE RESULT (part 2)
Just like with the ingredients, you need to tell the recipe whether what you are making is an item (0), armor (1), or weapon (2). Once again, this is not an array.

For example, lets create a recipe for a mithril sword, requiring 1 tablet, 1 card, and 1 fruit you would use the following code:


Code:
igredients = [30,31,32]
types = [0,0,0]
quantities = [1,1,1]
sword=Game_Recipe.new(ingredients, types, quantities,4,2)


NOTE: the name "sword" doesn't matter, because in the craft screen, the name of the item being created will be displayed, not the name of the object.

Now that the recipe exist, the party needs to learn it. To do this use the following code


Code:
$game_party.learn_recipe(sword)

Finally, to enter the crafting scene you will need to use the following code:
$scene=Scene_Craft.new
NOTE: by default, exiting the crafting scene brings you to the menu.

Well, here's the code, please try it out and let me know what you think
Code:
#================================
# CRAFTING PROGRAM
#----------------------------------------------------------------
#-written by Deke
#-yes_no window code created by Phsylomortis
#----------------------------------------------------------------
#================================

#updates to Game_Party class

class Game_Party

attr_accessor       :recipes

alias crafting_party_initialize initialize

def initialize
  crafting_party_initialize
  @recipes=[]
end

#----------------------------------------------------------------------
def know?(recipe, version = 1)
  unless recipe.is_a?(Game_Recipe)
    recipe = get_recipe_from_master_list(recipe, version)
  end
  return $game_party.recipes.include?(recipe)
end

#----------------------------------------------------------------------
def learn_recipe(recipe , version = 1)
  unless recipe.is_a?(Game_Recipe)
    recipe = get_recipe_from_master_list(recipe, version)
  end
  if recipe.is_a?(Game_Recipe)
    unless know?(recipe)
      @recipes.push(recipe)
    end
  end
end

#----------------------------------------------------------------------
def forget_recipe(recipe , version = 1)
  if !recipe.is_a?(Game_Recipe)
    recipe = get_recipe_from_master_list(recipe, version)
  end
  if recipe.is_a?(Game_Recipe)
    for i in 0...@recipes.size
      if recipe == @recipes[i]
        index = i
        break
      end
    end
    if index != nil
      @recipes.delete(@recipes[index])
    end
  end
end

#----------------------------------------------------------------------
def get_recipe_from_master_list(item, version)
  index = nil
  for i in 0...$game_temp.recipe_list.size
    if item[0] == $game_temp.recipe_list[i].result and item[1] ==$game_temp.recipe_list[i].result_type
      version -= 1
      if version == 0
        index = i
        break
      end
    end
  end
  if index.is_a?(Integer)
    return ($game_temp.recipe_list[index])
  else
    return false
  end
end

end # of Game_Party updates

#================================
class Game_Recipe

attr_reader :ingredients
attr_reader :quantities
attr_reader :result
attr_reader :result_type
attr_reader :ingredient_types

#----------------------------------------------------------------------
def initialize( ingredients, ingredient_types, quantities, result, result_type)
  @ingredients = ingredients
  @ingredient_types = ingredient_types
  @quantities = quantities
  @result = result
  @result_type = result_type
end

#----------------------------------------------------------------------
def name
  case @result_type
    when 0
      name = $data_items[@result].name
    when 1
      name = $data_armors[@result].name
    when 2
      name = $data_weapons[@result].name
  end
  return name
end

#----------------------------------------------------------------------
def have
  have_all = true
  for i in 0...@ingredients.size
    case @ingredient_types[i]
      when 0
        if $game_party.item_number(@ingredients[i]) < @quantities[i]
          have_all=false
        end
      when 1
        if $game_party.armor_number(@ingredients[i]) < @quantities[i]
          have_all=false
        end
      when 2
        if $game_party.weapon_number(@ingredients[i]) < @quantities[i]
          have_all=false
        end
    end
  end
  return have_all
end

#----------------------------------------------------------------------
def decrement
  for i in 0...@ingredients.size
    case @ingredient_types[i]
    when 0
      $game_party.lose_item(@ingredients[i], @quantities[i])
    when 1
      $game_party.lose_armor(@ingredients[i], @quantities[i])
    when 2
      $game_party.lose_weapon(@ingredients[i], @quantities[i])
    end
  end
end

#----------------------------------------------------------------------
def make
  if have
    case @result_type
    when 0
      $game_party.gain_item(@result, 1)
    when 1
      $game_party.gain_armor(@result, 1)
    when 2
      $game_party.gain_weapon(@result, 1)
    end
    decrement
  end
end

#----------------------------------------------------------------------
def == (recipe)
  if recipe.is_a?(Game_Recipe)
    equal = true
    if recipe.ingredients != self.ingredients
      equal = false
    end
    if recipe.ingredient_types != self.ingredient_types
      equal = false
    end
    if recipe.quantities != self.quantities
      equal = false
    end
    if recipe.result != self.result
      equal=false
    end
    if recipe.result_type != self.result_type
      equal = false
    end
  else
    equal = false
  end
  return equal
end

end # of Game_Recipe class

#===================================

class Window_Craft < Window_Selectable

#--------------------------------------------------------------------------
def initialize
  super(0, 64, 240, 416)
  @column_max = 1
  refresh
  self.index = 0
end

#--------------------------------------------------------------------------
def recipe
  return @data[self.index]
end

#--------------------------------------------------------------------------
def refresh
  if self.contents != nil
    self.contents.dispose
    self.contents = nil
  end
  @data = []
  for i in 0...$game_party.recipes.size
      @data.push($game_party.recipes[i])
  end
  @item_max = @data.size
  if @item_max > 0
    self.contents = Bitmap.new(width - 32, row_max * 32)
    self.contents.font.name = $fontface.is_a?(String) ? $fontface : $defaultfonttype
    self.contents.font.size = $fontsize.is_a?(Integer) ? $fontsize : $defaultfontsize
    for i in 0...@item_max
      draw_item(i)
    end
  end
end

#--------------------------------------------------------------------------
def draw_item(index)
  recipe = @data[index]
  self.contents.font.color = recipe.have ? normal_color : disabled_color
  x = 16
  y = index * 32
  self.contents.draw_text(x , y, self.width-32, 32, recipe.name, 0)
end

#--------------------------------------------------------------------------
def update_help
  current_recipe = recipe
  if current_recipe.is_a?(Game_Recipe)
  case current_recipe.result_type
    when 0
      description = $data_items[current_recipe.result].description
    when 1
      description = $data_armors[current_recipe.result].description
    when 2
      description = $data_weapons[current_recipe.result].description
    end
  else
    description = ""
  end
  @help_window.set_text(description)
  @help_window.update
end

end # of Window_Craft

#=======================================
class Window_CraftResult < Window_Base

#--------------------------------------------------------------------------
def initialize
  super(240, 64, 400, 184)
  self.contents = Bitmap.new(width - 32, height - 32)
  self.contents.font.name = $fontface.is_a?(String) ? $fontface : $defaultfonttype
  self.contents.font.size = 20
  @result = nil
  @type = nil
end

#--------------------------------------------------------------------------
def refresh
  self.contents.clear
  case @type
    when 0
      item = $data_items[@result]
      if item.recover_hp_rate > item.recover_hp
        hp_string = "HP Recovery% :"
        hp_stat = item.recover_hp_rate
      else
        hp_string = "HP Recovery Points:"
        hp_stat = item.recover_hp
      end
      if item.recover_sp_rate > item.recover_sp
        sp_string = "SP Recovery% :"
        sp_stat = item.recover_sp_rate
      else
        sp_string = "SP Recovery Points:"
        sp_stat = item.recover_sp
      end
      @strings = [hp_string, sp_string, "Phy. Def:" , "Mag Def:", "Accuracy:", "Variance:"]
      @stats = [hp_stat, sp_stat, item. pdef_f, item.mdef_f, item.hit, item.variance,
                     $game_party.item_number(@result)]
      @bitmap = RPG::Cache.icon(item.icon_name)
    when 1
      item = $data_armors[@result]
      @strings = ["Phy. Def:", "Mag. Def:", "Evasion plus:", "Strength plus:", "Dex. plus:",
                     "Agility plus:", "Int. plus:"]
      @stats = [item.pdef, item.mdef, item.eva, item.str_plus, item.dex_plus,
                  item.agi_plus, item.int_plus, $game_party.armor_number(@result) ]
      @bitmap = RPG::Cache.icon(item.icon_name)
    when 2
      item = $data_weapons[@result]
      @strings =["Attack Power:", "Phy. Def:", "Mag. Def:", "Strength plus:", "Dex. plus:",
                  "Agility plus:", "Int. plus:"]
      @stats = [item.atk, item.pdef, item.mdef, item.str_plus, item.dex_plus,
                  item.agi_plus, item.int_plus, $game_party.weapon_number(@result) ]
      @bitmap = RPG::Cache.icon(item.icon_name)
  end
  for i in 0...@strings.size
    x = i%2 * 184
    y = i /2 *28 +32
    self.contents.font.color = normal_color
    self.contents.draw_text(x,y,100, 28,@strings[i])
    self.contents.font.color = system_color
    self.contents.draw_text(x + 110, y, 45, 28, @stats[i].to_s)
  end
  self.contents.blt(0, 0, @bitmap, Rect.new(0, 0, 24, 24), 255)
  self.contents.font.color= normal_color
  self.contents.draw_text(40, 0, 300, 28, "Quantity curentley owned:")
  self.contents.font.color = system_color
  count = @stats[@stats.size - 1].to_s
  self.contents.draw_text(294, 0, 45, 28, count )
end

#----------------------------------------------------------------------
def set_result(result , type)
  @result = result
  @type = type
  refresh
end

end #of Window_CraftResult

#=======================================
class Window_CraftIngredients < Window_Base

#--------------------------------------------------------------------------
def initialize
  super(240, 248, 400, 232)
  self.contents = Bitmap.new(width - 32, height - 32)
  self.contents.font.name = $fontface.is_a?(String) ? $fontface : $defaultfonttype
  self.contents.font.size = 20
  @ingredients = []
  @types = []
  @quantities = []
  @item = nil
  @count = 0
end

#--------------------------------------------------------------------------
def refresh
  self.contents.clear
  for i in 0...@ingredients.size
    case @types[i]
    when 0
      @item = $data_items[@ingredients[i]]
      @count = $game_party.item_number(@ingredients[i])
    when 1
      @item = $data_armors[@ingredients[i]]
      @count = $game_party.armor_number(@ingredients[i])
    when 2
      @item = $data_weapons[@ingredients[i]]
      @count = $game_party.weapon_number(@ingredients[i])
    end
    y = i *26
    self.contents.blt(0, y, RPG::Cache.icon(@item.icon_name), Rect.new(0, 0, 24, 24), 255)
    self.contents.font.color = @count >= @quantities[i] ? normal_color : disabled_color
    self.contents.draw_text(30, y, 280, 28, @item.name)
    self.contents.draw_text(300, y, 45, 28, @quantities[i].to_s)
    self.contents.font.color = system_color
    self.contents.draw_text(245, y, 45, 28, @count.to_s )    
  end
end
  
#--------------------------------------------------------------------------
def set_ingredients(ingredients , types, quantities)
  @ingredients = ingredients
  @types = types
  @quantities = quantities
  refresh
end

end # of Window_CraftIngredients

#======================================
class Scene_Craft

#--------------------------------------------------------------------------
def initialize(craft_index=0, return_scene = "menu")
  @craft_index=craft_index
  @return_scene = return_scene
end

#--------------------------------------------------------------------------
def main
  @craft_window = Window_Craft.new
  @craft_window.index=@craft_index
  @confirm_window = Window_Base.new(120, 188, 400, 64)
  @confirm_window.contents = Bitmap.new(368, 32)
  @confirm_window.contents.font.name = $fontface.is_a?(String) ? $fontface : $defaultfonttype
  @confirm_window.contents.font.size = $fontsize.is_a?(Integer) ? $fontsize : $defaultfontsize
  @help_window = Window_Help.new
  @craft_window.help_window = @help_window
  @result_window=Window_CraftResult.new
  @ingredients_window=Window_CraftIngredients.new
  @yes_no_window = Window_Command.new(100, ["Yes", "No"])
  @confirm_window.visible = false
  @confirm_window.z = 1500
  @yes_no_window.visible = false
  @yes_no_window.active = false
  @yes_no_window.index = 1
  @yes_no_window.x = 270
  @yes_no_window.y = 252
  @yes_no_window.z = 1500
  @label_window = Window_Base.new(450,200,190,52)
  @label_window.contents=Bitmap.new(@label_window.width - 32,@label_window.height - 32)
  @label_window.contents.font.size=20
  @label_window.contents.font.color = @label_window.normal_color
  @label_window.contents.font.name = $fontface.is_a?(String) ? $fontface : $defaultfonttype
  @label_window.contents.draw_text(0, 0, @label_window.contents.width, 20, "   Have    Need")
  Graphics.transition
  loop do
    Graphics.update
    Input.update
    update
    if $scene != self
      break
    end
  end
  Graphics.freeze
  @help_window.dispose
  @craft_window.dispose
  @result_window.dispose
  @ingredients_window.dispose
  @confirm_window.dispose
  @yes_no_window.dispose
  @label_window.dispose
end

#--------------------------------------------------------------------------
def update
  @craft_window.update
  @ingredients_window.update
  if $game_party.recipes.size > 0
    @result_window.set_result(@craft_window.recipe.result, @craft_window.recipe.result_type)
    @ingredients_window.set_ingredients(@craft_window.recipe.ingredients,
                                                         @craft_window.recipe.ingredient_types,
                                                         @craft_window.recipe.quantities)
  end
  if @craft_window.active
    update_craft
    return
  end
  if @yes_no_window.active
    confirm_update
    return
  end
end

#--------------------------------------------------------------------------
def update_craft
  if Input.trigger?(Input::B)
    $game_system.se_play($data_system.cancel_se)
    if @return_scene == "menu"
      $scene = Scene_Menu.new(0)
    else
      $scene = Scene_Map.new
    end
    return
  end
  if Input.trigger?(Input::C) and $game_party.recipes.size != 0
    @recipe = @craft_window.recipe
    if @recipe.have
      @yes_no_window.active = true
      @craft_window.active = false
    else
      $game_system.se_play($data_system.buzzer_se)
      return
    end
  end
end

#--------------------------------------------------------------------------
def confirm_update
  @craft_index = @craft_window.index
  @confirm_window.visible = true
  @confirm_window.z = 1500
  @yes_no_window.visible = true
  @yes_no_window.active = true
  @yes_no_window.z = 1500
  @yes_no_window.update
  string = "Create " + @recipe.name + "?"
  cw = @confirm_window.contents.text_size(string).width
  center = @confirm_window.contents.width/2 - cw /2
  unless @drawn
    @confirm_window.contents.draw_text(center, 0, cw, 30, string)
    @drawn = true
  end
  if Input.trigger?(Input::C)
    if @yes_no_window.index == 0
      $game_system.se_play($data_system.decision_se)
      @recipe.make
      $game_system.se_play($data_system.save_se)
      $scene=Scene_Craft.new(@craft_index)
    else
      $game_system.se_play($data_system.cancel_se)
      $scene=Scene_Craft.new(@craft_index)
    end
  end
  if Input.trigger?(Input::B)
    $game_system.se_play($data_system.cancel_se)
    $scene=Scene_Craft.new(@craft_index)
  end
end

end # of Scene_Craft



Well, that’s all well and good you may be asking yourself, how am I going to keep track of all these recipes? No worries, I am there to help you out with that one too. I have created a way to make one big list of recipes, then when you want to teach the party a recipe, you simple have to tell it what the index and type is of the item you want to craft here’s the code to do this.
NOTE: TO USE THIS CODE YOU WILL HAVE TO DO A LITTLE BIT OF SCRIPT EDITING. (Don’t worry thought it’s not that hard.)
Code:
#================================
# Sample master list for crafting script
#----------------------------------------------------------------
#-written by Deke
#----------------------------------------------------------------
#================================

class Game_Temp
attr_reader :recipe_list

alias crafting_temp_initialize initialize

def initialize
   crafting_temp_initialize
   @recipe_list=[]
   get_recipe_list
end

def get_recipe_list
  
   ingredients = [30,31,32]
   ingredient_types = [0,0,0]
   quantities = [1,1,1]
   result = 4
   result_type = 2
   @recipe_list.push(Game_Recipe.new(ingredients,ingredient_types,quantities,result,result_type))
  
   ingredients = [29,30]
   ingredient_types = [0,0]
   quantities = [1,2]
   result = 8
   result_type = 1
   @recipe_list.push(Game_Recipe.new(ingredients,ingredient_types,quantities,result,result_type))
  
   ingredients = [30,31,1]
   ingredient_types = [0,0,1]
   quantities = [1,1,3]
   result = 4
   result_type = 0
   @recipe_list.push(Game_Recipe.new(ingredients,ingredient_types,quantities,result,result_type))
  
end # of get_recipe_list method
end # of updates to Game_Temp Class


The ONLY thing you will need to change is the numbers in red.
Just like before, the ingredients list is the number of the items from the database. The ingredients_types tell wether the the ingredients are items (0), armors (1), or weapons(2). The quantities are how many of each ingredient you need in the recipe. The result is the index of the item you are crafting, and the resuslt_type tells wether you are creating an item, armor, or weapon.

All you need to do to add more recipes is copy and past that little code snipet and put in the numbers that correspond to the ingredients and results you want.

Finally, if you want the party to learn the recipe you will use the following line of code:

Code:
$game_party.learn_recipe([4,2])
$game_party.learn_recipe([8,1])
$game_party.learn_recipe([4,0])


This fist line will teach the party how to make the fourth weapon.
The second line will teach the party to make the 8th armor.
The third line would teach you how to create the 4th item.

However, the party will only learn a recipe if you have that recipe in the master list. Otherwise, nothing will happen.

As I mentioned above (way above), I recently added the option to learn multiple recipes for the same resulting object. Suppose we added the following code snipet after the other recipes in the master list (I hope by know you know where this would go).

Code:
ingredients = [30,31]
  ingredient_types = [0,0]
  quantities = [1,1]
  result = 4
  result_type = 0
  @recipe_list.push(Game_Recipe.new(ingredients,ingredient_types,quantities,result,result_type))



You’ll notice that this is also a recipe for the fourth item (perfume in the default case). If you wanted the party to learn this recipe, you would use the following code:
$game_party.learn_recipe([4,0],2)
Just simply, add the “,2� to identify that you want to learn the second version of that recipe from the master list. Guess how it works for the third, fourth… versions. Note, that if you want to learn the first form of a recipe you can put a “1� in. However, this is not at all necessary.

Hope that helped explain some things, and I hope you enjoy!
}


Possibly Related Threads…
Thread Author Replies Views Last Post
  Looting System Thieffer 0 2,644 06-18-2009, 01:00 PM
Last Post: Thieffer
  Difficulity Level System Ekhart 0 2,641 03-14-2008, 01:00 PM
Last Post: Ekhart
  Dragon Quest VII Class Changing System Sephirothtds 0 2,763 11-15-2007, 01:00 PM
Last Post: Sephirothtds
  Map Stats and Info System Dubealex 0 2,800 10-19-2007, 01:00 PM
Last Post: Dubealex
  Spell Tablet System GubiD 0 2,895 08-25-2007, 01:00 PM
Last Post: GubiD
  Orb Based Skill System El Conductor 0 2,606 07-29-2007, 01:00 PM
Last Post: El Conductor
  Party Deleting System Ekhart 0 2,642 07-05-2007, 01:00 PM
Last Post: Ekhart
  Class Stat Bonus System Shinami 0 2,549 05-20-2007, 01:00 PM
Last Post: Shinami
  MATERIA SYSTEM with AP illustrationism 0 2,891 05-06-2007, 01:00 PM
Last Post: illustrationism
  MMORPG Leveling System Lettuce 0 2,686 12-23-2006, 01:00 PM
Last Post: Lettuce



Users browsing this thread: 2 Guest(s)