diff --git a/data/plugins/skill-herblore/herb.rb b/data/plugins/skill-herblore/herb.rb
new file mode 100644
index 00000000..0f01fb49
--- /dev/null
+++ b/data/plugins/skill-herblore/herb.rb
@@ -0,0 +1,90 @@
+require 'java'
+
+java_import 'org.apollo.game.action.Action'
+
+# A herb is an ingredient that requires identification before being used.
+class Herb < Ingredient
+ include HerbloreMethod
+
+ attr_reader :unidentified, :level, :experience
+
+ def initialize(item_id, unidentified, level, experience)
+ super item_id
+
+ @unidentified = unidentified
+ @level = level
+ @experience = experience
+ end
+
+ def invoke(player, id, slot)
+ item = player.inventory.get(slot)
+ player.start_action(HerbIdentificationAction.new(player, self, slot, item))
+ end
+end
+
+# An action that makes a player identify a herb.
+class HerbIdentificationAction < Action
+ attr_reader :herb, :slot, :item, :pulses
+
+ def initialize(player, herb, slot, item)
+ super(0, true, player)
+
+ @herb = herb
+ @slot = slot
+ @item = item
+ @pulses = 0
+ end
+
+ def execute
+ if @pulses == 0
+ unless check_skill(mob, @herb.level, "identify this herb")
+ stop
+ return
+ end
+ end
+ execute_action
+ @pulses += 1
+ end
+
+ def execute_action
+ player = mob
+ inventory = player.inventory
+
+ if inventory.remove_slot(@slot, 1) == 1
+ identified = @herb.item
+
+ inventory.add(identified)
+ player.skill_set.add_experience(HERBLORE_ID, @herb.experience)
+ player.send_message("You identify the herb as a #{identified.definition.name}.", true)
+ end
+ stop
+ end
+
+ def equals(other)
+ return (get_class == other.get_class and slot == other.slot and herb == other.herb)
+ end
+end
+
+# Appends a herb to the InventoryItemEvent interception.
+def append_herb(item_id, unidentified, level, experience)
+ herb = Herb.new(item_id, unidentified, level, experience)
+ append_herblore_item(herb, unidentified)
+ return herb
+end
+
+# Herbs
+
+GUAM_LEAF = append_herb(249, 199, 1, 2.5) # 3, 2.5
+MARRENTILL = append_herb(251, 201, 5, 3.8)
+TARROMIN = append_herb(253, 203, 11, 5)
+HARRALANDER = append_herb(255, 205, 20, 6.3)
+RANARR = append_herb(257, 207, 25, 7.5)
+TOADFLAX = append_herb(2998, 3049, 30, 8)
+IRIT_LEAF = append_herb(259, 209, 40, 8.8)
+AVANTOE = append_herb(261, 211, 48, 10)
+KWUARM = append_herb(263, 213, 54, 11.3)
+SNAPDRAGON = append_herb(3000, 3051, 59, 11.8)
+CADANTINE = append_herb(265, 215, 65, 12.5)
+LANTADYME = append_herb(2481, 2485, 67, 13.1)
+DWARF_WEED = append_herb(267, 217, 70, 13.8)
+TORSTOL = append_herb(269, 219, 75, 15)
\ No newline at end of file
diff --git a/data/plugins/skill-herblore/herblore.rb b/data/plugins/skill-herblore/herblore.rb
new file mode 100644
index 00000000..5773c9eb
--- /dev/null
+++ b/data/plugins/skill-herblore/herblore.rb
@@ -0,0 +1,101 @@
+# Thanks to Sillhouette for posting
+# a large amount of Herblore skill data which has been thankfully used in this plugin.
+
+require 'java'
+
+java_import 'org.apollo.game.event.impl.SetWidgetItemModelEvent'
+java_import 'org.apollo.game.model.Skill'
+
+HERBLORE_ID = Skill::HERBLORE
+HERBLORE_DIALOGUE = 4429
+
+HERBLORE_ITEM = {}
+HERBLORE_ITEM_ITEM = {}
+
+DRINK_ITEM = {}
+
+# A module which describes an invocable method of the Herblore skill.
+module HerbloreMethod
+ def self.new
+ raise 'You cannot instantiate this module!'
+ end
+
+ def invoke(player, primary, secondary)
+ raise NotImplementedError.new('You must implement the invocation of HerbloreMethod!')
+ end
+end
+
+# The ItemOnItemEvent handler for all Herblore-related functions.
+on :event, :item_on_item do |ctx, player, event|
+ primary = event.id
+ secondary = event.target_id
+ hash = HERBLORE_ITEM_ITEM[primary]
+
+ if hash == nil
+ secondary = event.id
+ primary = event.target_id
+ hash = HERBLORE_ITEM_ITEM[primary]
+ end
+
+ if hash != nil
+ method = hash[secondary]
+ if method != nil
+ method.invoke(player, primary, secondary)
+ ctx.break_handler_chain
+ end
+ end
+end
+
+# The ItemOptionEvent handler for all Herblore-related functions.
+on :event, :item_option do |ctx, player, event|
+ if event.option == 1
+ id = event.id
+ method = HERBLORE_ITEM[id]
+
+ if method != nil
+ method.invoke(player, id, event.slot)
+ ctx.break_handler_chain
+ end
+ method = DRINK_ITEM[id]
+
+ if method != nil
+ method.invoke(player, id, event.slot)
+ ctx.break_handler_chain
+ end
+ end
+end
+
+# Utility for adding the various Herblore methods to the handled constant arrays.
+def append_herblore_item(method, key, secondary = -1)
+ if secondary == -1
+ HERBLORE_ITEM[key] = method
+ else
+ hash = HERBLORE_ITEM_ITEM[key]
+ hash = {} if hash == nil
+
+ hash[secondary] = method
+ HERBLORE_ITEM_ITEM[key] = hash
+ end
+end
+
+# Utility method for checking if a player's inventory has an item of the specified id, with optionally the specified amount (1 by default), at the specified slot.
+def check_slot(player, slot, id, amount = 1)
+ item = player.inventory.get(slot)
+ return (item != nil and item.id == id and item.amount >= amount)
+end
+
+# Utility method for checking if a player's Herblore (maximum) level is at a required height. Also informs the player if this is not the case with use of the action
+# variable, like so: "You need a Herblore level of at least #{required.to_s} to #{action}."
+def check_skill(player, required, action)
+ if required > player.skill_set.skill(HERBLORE_ID).current_level
+ player.send_message("You need a Herblore level of at least #{required} to #{action}.")
+ return false
+ end
+ return true
+end
+
+# Opens a 'make' dialogue for the specified player, displaying the specified item. Optionally, a listener can be used for the dialogue.
+def open_dialogue(player, item, listener = nil)
+ player.send(SetWidgetItemModelEvent.new(1746, item, 170))
+ player.interface_set.open_dialogue(listener, HERBLORE_DIALOGUE)
+end
\ No newline at end of file
diff --git a/data/plugins/skill-herblore/ingredient.rb b/data/plugins/skill-herblore/ingredient.rb
new file mode 100644
index 00000000..2f2759a1
--- /dev/null
+++ b/data/plugins/skill-herblore/ingredient.rb
@@ -0,0 +1,258 @@
+require 'java'
+
+java_import 'org.apollo.game.action.Action'
+java_import 'org.apollo.game.model.Animation'
+java_import 'org.apollo.game.model.Item'
+java_import 'org.apollo.game.model.def.ItemDefinition'
+java_import 'org.apollo.game.model.inter.EnterAmountListener'
+java_import 'org.apollo.game.model.inter.dialogue.DialogueAdapter'
+
+GRINDING_ANIM = Animation.new(364)
+PESTLE_MORTAR = 233
+
+# An ingredient which can be used for making (unfinished) potions.
+class Ingredient
+ attr_reader :item_id, :item
+
+ def initialize(item)
+ @item_id = item
+ @item = Item.new(item) # Share item instances.
+ end
+
+ # Checks if the specified player has the specified amount of this ingredient. Optionally, they can immediately be removed if that
+ # amount was indeed found.
+ def check_remove(player, amount, remove)
+ inventory = player.inventory
+ counter = 0
+
+ inventory.items.each do |inv_item|
+ break unless counter < amount
+
+ next if inv_item == nil
+
+ id = inv_item.id
+ inventory_amount = inv_item.amount
+
+ if id == @item_id
+ if inventory_amount >= amount
+ inventory.remove(@item_id, amount) if remove
+ return true
+ else
+ counter += inventory_amount
+ end
+ end
+ end
+
+ if counter >= amount
+ inventory.remove(@item_id, amount) if remove
+ return true
+ end
+
+ return false
+ end
+end
+
+# An ingredient which needs to be grinded before being usable for Herblore.
+class GrindedIngredient < Ingredient
+ include HerbloreMethod
+
+ attr_reader :raw
+
+ def initialize(item_id, raw)
+ super(item_id)
+
+ @raw = raw
+ end
+
+ def invoke(player, pestle_mortar, ingredient)
+ action = GrindingAction.new(player, self)
+ listener = GrindingDialogueListener.new(player, action)
+
+ open_dialogue(player, @item_id, listener)
+ end
+end
+
+# A DialogueAdapter used for grinding ingredients. It is also used as an EnterAmountListener for the amount of grinding actions.
+class GrindingDialogueListener < DialogueAdapter
+ include EnterAmountListener
+
+ attr_reader :player, :action
+
+ def initialize(player, action)
+ super()
+
+ @player = player
+ @action = action
+ end
+
+ # Called when a button has been clicked whilst the dialogue was opened.
+ def buttonClicked(button)
+ amount = get_amount(button)
+ if amount == 0
+ return false
+ end
+
+ interfaces = @player.interface_set
+ interfaces.close
+
+ if amount == -1
+ interfaces.open_enter_amount_dialogue(self)
+ return true
+ end
+
+ amount = player.inventory.get_amount(@action.ingredient.raw) if amount == -2
+ execute(amount)
+ end
+
+ # Called when an amount of grinding actions has been entered.
+ def amountEntered(amount)
+ if amount <= 0 then return else execute(amount) end
+ end
+
+ # Called to set the action(s) in motion.
+ def execute(amount)
+ @action.set_amount(amount)
+ @player.start_action(@action)
+ end
+
+ # Gets the amount of actions based on the specified button id.
+ def get_amount(button)
+ case button
+ when 2799 then return 1
+ when 2798 then return 5
+ when 1748 then return -1
+ when 1747 then return -2
+ else return 0
+ end
+ end
+end
+
+# An action which makes the player grind one or more GrindedIngredients from their 'raw' form.
+class GrindingAction < Action
+ attr_reader :ingredient, :amount, :pulses, :slot, :listener
+
+ def initialize(player, ingredient)
+ super 0, true, player
+
+ @ingredient = ingredient
+ @pulses = 0
+ end
+
+ def execute
+ grind
+ @pulses += 1
+ end
+
+ # Performs the grinding action once the materials have been checked.
+ def grind
+ if @pulses == 0
+ mob.play_animation GRINDING_ANIM
+ elsif @pulses == 1
+ if not gather_materials
+ stop
+ return
+ end
+
+ player = mob
+ inventory = player.inventory
+ item = inventory.get(@slot)
+
+ name = item.definition.name.downcase
+ player.send_message("You grind the #{name} to dust.", true)
+
+ inventory.reset(@slot)
+ inventory.add(@ingredient.item)
+
+ set_delay(1)
+ elsif @pulses == 2
+ mob.stop_animation
+ continue()
+ end
+ end
+
+ # Checks if the player has the required materials to perform the (next) action.
+ def gather_materials
+ items = mob.inventory.items
+
+ pst_mrt = false
+ ingr = false
+ raw = @ingredient.raw
+ (0...items.length).each do |slot|
+ item = items[slot]
+ next if item == nil
+
+ id = item.id
+ if id == PESTLE_MORTAR and !pst_mrt
+ pst_mrt = true
+ elsif id == raw and !ingr
+ ingr = true
+ @slot = slot
+ end
+
+ return true if pst_mrt and ingr
+ end
+
+ ingr = ItemDefinition.lookup(raw).name.downcase
+ mob.send_message("You do not have any more #{ingr}s.")
+ return false
+ end
+
+ # Either invokes the stop() method in Action to shut it down
+ # or continues to the next ingredient.
+ def continue
+ @amount -= 1
+
+ if @amount > 0
+ set_delay(0)
+ @pulses = -1
+ else
+ stop
+ end
+ end
+
+ # Sets the amount of actions.
+ def set_amount(amount)
+ @amount = amount
+ end
+
+ def stop
+ super
+ mob.inventory.remove_listener(@listener) unless listener == nil
+ end
+
+ def equals(other)
+ return (get_class == other.get_class and @ingredient == other.ingredient)
+ end
+end
+
+# Appends a grinded ingredient to the ItemOnItemEvent handler interception.
+def append_grinded(id, raw)
+ grinded = GrindedIngredient.new(id, raw)
+ append_herblore_item(grinded, PESTLE_MORTAR, raw)
+ return grinded
+end
+
+# Normal ingredients
+EYE_NEWT = Ingredient.new(221)
+RED_SPIDERS_EGGS = Ingredient.new(223)
+LIMPWURT_ROOT = Ingredient.new(225)
+SNAPE_GRASS = Ingredient.new(231)
+WHITE_BERRIES = Ingredient.new(239)
+WINE_ZAMORAK = Ingredient.new(245)
+JANGERBERRIES = Ingredient.new(247)
+TOADS_LEGS = Ingredient.new(2152)
+MORT_MYRE_FUNGI = Ingredient.new(2970)
+POTATO_CACTUS = Ingredient.new(3138)
+PHOENIX_FEATHER = Ingredient.new(4621)
+FROG_SPAWN = Ingredient.new(5004)
+PAPAYA_FRUIT = Ingredient.new(5972)
+POISON_IVY_BERRIES = Ingredient.new(6018)
+YEW_ROOTS = Ingredient.new(6049)
+MAGIC_ROOTS = Ingredient.new(6051)
+
+# Grinded ingredients
+UNICORN_HORN_DUST = append_grinded(235, 237)
+DRAGON_SCALE_DUST = append_grinded(241, 243)
+CHOCOLATE_DUST = append_grinded(1975, 1973)
+CRUSHED_NEST = append_grinded(6693, 5075)
+GROUND_MUD_RUNE = append_grinded(9594, 4698)
\ No newline at end of file
diff --git a/data/plugins/skill-herblore/plugin.xml b/data/plugins/skill-herblore/plugin.xml
new file mode 100644
index 00000000..a4481e6b
--- /dev/null
+++ b/data/plugins/skill-herblore/plugin.xml
@@ -0,0 +1,18 @@
+
+
+ skill-herblore
+ 1
+ Herblore
+ Adds the Herblore skill.
+
+ Chris Fletcher
+ Major
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data/plugins/skill-herblore/potion.rb b/data/plugins/skill-herblore/potion.rb
new file mode 100644
index 00000000..a8d82a75
--- /dev/null
+++ b/data/plugins/skill-herblore/potion.rb
@@ -0,0 +1,364 @@
+require 'java'
+
+java_import 'org.apollo.game.action.Action'
+java_import 'org.apollo.game.model.Animation'
+java_import 'org.apollo.game.model.Item'
+java_import 'org.apollo.game.model.def.ItemDefinition'
+java_import 'org.apollo.game.model.inter.EnterAmountListener'
+java_import 'org.apollo.game.model.inter.dialogue.DialogueAdapter'
+
+WATER_VIAL_ID = 227
+EMPTY_VIAL_ID = 229
+
+MIXING_ANIM = Animation.new(363)
+
+# Represents an unfinished potion which can be invoked as a HerbloreMethod and used as an ingredient.
+class UnfinishedPotion < Ingredient
+ include HerbloreMethod
+
+ attr_reader :herb, :level
+
+ def initialize(item_id, herb, level)
+ super item_id
+
+ @herb = herb
+ @level = level
+ end
+
+ def invoke(player, primary, secondary)
+ action = UnfinishedMixingAction.new(player, self)
+ listener = UnfinishedMixingDialogueListener.new(player, action)
+
+ open_dialogue(player, @item_id, listener)
+ end
+end
+
+# Represents a finished potion which can be invoked as a HerbloreMethod.
+class FinishedPotion
+ include HerbloreMethod
+
+ attr_reader :item, :ingredients, :level, :experience
+
+ def initialize(item, ingredients, level, experience)
+ @item = Item.new(item)
+ @ingredients = ingredients
+ @level = level
+ @experience = experience
+ end
+
+ def invoke(player, primary, secondary)
+ action = FinishedMixingAction.new(player, primary, secondary, self)
+ listener = FinishedMixingDialogueListener.new(player, action)
+
+ open_dialogue(player, @item.id, listener) end
+end
+
+# A DialogueAdapter used for mixing potions. It is also used as an EnterAmountListener for the amount of mixing actions.
+class MixingDialogueListener < DialogueAdapter
+ include EnterAmountListener
+
+ attr_reader :player, :action
+
+ def initialize(player, action)
+ super()
+
+ @player = player
+ @action = action
+ end
+
+ # Called when a button has been clicked whilst the dialogue was opened.
+ def buttonClicked(button)
+ amount = get_amount(button)
+
+ return false if amount == 0
+
+ interfaces = @player.interface_set
+ interfaces.close
+
+ if amount == -1
+ interfaces.open_enter_amount_dialogue(self)
+ return true
+ end
+
+ amount = calculate_maximum if amount == -2
+
+ execute(amount)
+ return true
+ end
+
+ # Called when an amount of mixing actions has been entered.
+ def amountEntered(amount)
+ if amount <= 0 then return else execute(amount) end
+ end
+
+ # Called to set the action(s) in motion.
+ def execute(amount)
+ @action.set_amount(amount)
+ @player.start_action(@action)
+ end
+
+ def calculate_maximum(code)
+ # Override for potion-specific amount calculation.
+ end
+
+ # Gets the amount of actions based on the specified button id.
+ def get_amount(button)
+ case button
+ when 2799 then return 1
+ when 2798 then return 5
+ when 1748 then return -1
+ when 1747 then return -2
+ else return 0
+ end
+ end
+
+end
+
+# A MixingDialogueListener used for mixing unfinished potions.
+class UnfinishedMixingDialogueListener < MixingDialogueListener
+ def calculate_maximum
+ inventory = @player.inventory
+
+ amount = inventory.get_amount(WATER_VIAL_ID)
+
+ return 0 if amount <= 0
+
+ herbs = inventory.get_amount(@action.potion.herb.item.id)
+ amount = herbs if amount > herbs
+
+ return amount
+ end
+end
+
+# A MixingDialogueListener used for mixing finished potions.
+class FinishedMixingDialogueListener < MixingDialogueListener
+
+ def calculate_maximum
+ inventory = @player.inventory
+
+ amount = inventory.capacity
+ @action.potion.ingredients.each do |ingredient|
+ item_amount = inventory.get_amount(ingredient.item.id)
+ amount = item_amount if amount > item_amount
+ end
+
+ return amount
+ end
+
+end
+
+# An Action which handles the none-finished-dependent mixing.
+class MixingAction < Action
+ attr_reader :potion, :amount, :started, :pulses, :action, :listener
+
+ def initialize(player, potion, action)
+ super(1, true, player)
+
+ @potion = potion
+ @started = false
+ @pulses = 0
+ @action = action
+ @action.freeze
+ end
+
+ def execute
+ if @pulses == 0
+ unless @started
+ unless check_skill(mob, @potion.level, @action)
+ stop
+ return
+ end
+ @started = true
+ end
+
+ unless gather_materials
+ stop
+ return
+ end
+ end
+ mob.play_animation(MIXING_ANIM)
+ execute_action
+
+ if (@amount -= 1) > 0 then @pulses = 0 else stop end
+ end
+
+ def stop
+ super()
+ mob.inventory.remove_listener(@listener) unless @listener == nil
+ end
+
+ def execute_action
+ # Override for action execution.
+ end
+
+ def gather_materials
+ # Override for ingredient checking and gathering
+ return false
+ end
+
+ # Sets the amount of actions.
+ def set_amount(amount)
+ @amount = amount
+ end
+
+ def equals(other)
+ return (get_class == other.get_class and @potion == other.potion)
+ end
+end
+
+# A MixingAction which handles the execution of making UnfinishedPotions.
+class UnfinishedMixingAction < MixingAction
+ attr_reader :slots
+
+ def initialize(player, potion)
+ super(player, potion, "use this herb.")
+ end
+
+ def execute_action
+ name = @potion.herb.item.definition.name
+ player = mob
+ inventory = player.inventory
+
+ player.send_message("You put the #{name} in the water to make an unfinished #{name.sub(/ leaf$/, "")} potion.", true)
+
+ @slots.each do |slot, amount|
+ unless inventory.remove_slot(slot, amount)
+ stop
+ return
+ end
+ end
+
+ inventory.add(@potion.item)
+ end
+
+ def gather_materials
+ @slots = {}
+ inventory = mob.inventory
+
+ vial_slot = inventory.slot_of(WATER_VIAL_ID)
+ if vial_slot == -1
+ mob.send_message('You do not have any more vials of water.')
+ return false
+ end
+
+ item = @potion.herb.item
+ herb_slot = inventory.slot_of(item.id)
+ if herb_slot == -1
+ mob.send_message("You do not have any more #{item.definition.name}.")
+ return false
+ end
+
+ @slots[vial_slot] = 1
+ @slots[herb_slot] = 1
+
+ return true
+ end
+end
+
+# A MixingAction which handles the execution of making FinishedPotions.
+class FinishedMixingAction < MixingAction
+ attr_reader :unfinished, :ingredient, :slots
+
+ def initialize(player, unfinished, ingredient, potion)
+ super(player, potion, "mix this potion")
+
+ @unfinished = unfinished
+ @ingredient = ingredient
+ end
+
+ def execute_action
+ player = mob
+ ingredient = ItemDefinition.lookup(@ingredient).name.downcase
+ name = @potion.item.definition.name.sub('(3)', '')
+
+ player.send_message("You add the #{ingredient} to the mixture to make an #{name}.", true)
+ player.skill_set.add_experience(@potion.experience)
+
+ inventory = player.inventory
+
+ @slots.each do |slot, amount|
+ if not inventory.remove_slot(slot, amount)
+ stop
+ return
+ end
+ end
+
+ inventory.add(@potion.item)
+ end
+
+ def gather_materials
+ @slots = {}
+ inventory = mob.inventory
+
+ vial_slot = inventory.slot_of(@unfinished)
+ if vial_slot == -1
+ mob.send_message('You do not have enough unfinished potions.')
+ return false
+ end
+
+ ingredient_slot = inventory.slot_of(@ingredient)
+ if ingredient_slot == -1
+ mob.send_message('You do not have enough ingredients.')
+ return false
+ end
+
+ @slots[vial_slot] = 1
+ @slots[ingredient_slot] = 1
+
+ return true
+ end
+end
+
+# Appends a finished potion to the ItemOnItemEvent handling interception.
+def append_finished_potion(item, unfinished, ingredient, level, experience)
+ potion = FinishedPotion.new(item, [ unfinished, ingredient ], level, experience)
+ append_herblore_item(potion, unfinished.item_id, ingredient.item_id)
+ return potion
+end
+
+# Appends an unfinished potion to the ItemOnItemEvent handling interception.
+def append_unfinished_potion(item, herb, level)
+ potion = UnfinishedPotion.new(item, herb, level)
+ append_herblore_item(potion, herb.item_id, WATER_VIAL_ID)
+ return potion
+end
+
+
+# Unfinished potions
+UNF_GUAM = append_unfinished_potion(91, GUAM_LEAF, 1) # 3
+UNF_MARRENTILL = append_unfinished_potion(93, MARRENTILL, 5)
+UNF_TARROMIN = append_unfinished_potion(95, TARROMIN, 12)
+UNF_HARRALANDER = append_unfinished_potion(97, HARRALANDER, 22)
+UNF_RANARR = append_unfinished_potion(99, RANARR, 30)
+UNF_TOADFLAX = append_unfinished_potion(3002, TOADFLAX, 34)
+UNF_IRIT = append_unfinished_potion(101, IRIT_LEAF, 45)
+UNF_AVANTOE = append_unfinished_potion(103, AVANTOE, 50)
+UNF_KWUARM = append_unfinished_potion(105, KWUARM, 55)
+UNF_SNAPDRAGON = append_unfinished_potion(3004, SNAPDRAGON, 63)
+UNF_CADANTINE = append_unfinished_potion(107, CADANTINE, 66)
+UNF_LANTADYME = append_unfinished_potion(2483, LANTADYME, 69)
+UNF_DWARF_WEED = append_unfinished_potion(109, DWARF_WEED, 72)
+UNF_TORSTOL = append_unfinished_potion(111, TORSTOL, 78)
+
+
+# Finished potions
+ATTACK_POT = append_finished_potion(121, UNF_GUAM, EYE_NEWT, 1, 25) # 3, 25
+ANTIPOISON_POT = append_finished_potion(175, UNF_MARRENTILL, UNICORN_HORN_DUST, 5, 37.5)
+STRENGTH_POT = append_finished_potion(115, UNF_TARROMIN, LIMPWURT_ROOT, 12, 50)
+RESTORE_POT = append_finished_potion(127, UNF_HARRALANDER, RED_SPIDERS_EGGS, 18, 62.5)
+ENERGY_POT = append_finished_potion(3010, UNF_HARRALANDER, CHOCOLATE_DUST, 26, 67.5)
+DEFENCE_POT = append_finished_potion(133, UNF_RANARR, WHITE_BERRIES, 30, 75)
+AGILITY_POT = append_finished_potion(3034, UNF_TOADFLAX, TOADS_LEGS, 34, 80)
+PRAYER_POT = append_finished_potion(139, UNF_RANARR, SNAPE_GRASS, 38, 87.5)
+SUPER_ATTACK_POT = append_finished_potion(145, UNF_IRIT, EYE_NEWT, 45, 100)
+SUPER_ANTIPOISON_POT = append_finished_potion(181, UNF_IRIT, UNICORN_HORN_DUST, 48, 106.3)
+FISHING_POT = append_finished_potion(151, UNF_AVANTOE, SNAPE_GRASS, 50, 112.5)
+SUPER_ENERGY_POT = append_finished_potion(3018, UNF_AVANTOE, MORT_MYRE_FUNGI, 52, 117.5)
+SUPER_STRENGTH_POT = append_finished_potion(157, UNF_KWUARM, LIMPWURT_ROOT, 55, 125)
+WEAPON_POISON = append_finished_potion(187, UNF_KWUARM, DRAGON_SCALE_DUST, 60, 137.5)
+SUPER_RESTORE_POT = append_finished_potion(3026, UNF_SNAPDRAGON, RED_SPIDERS_EGGS, 63, 142.5)
+SUPER_DEFENCE_POT = append_finished_potion(163, UNF_CADANTINE, WHITE_BERRIES, 66, 150)
+ANTIFIRE_POT = append_finished_potion(2428, UNF_LANTADYME, DRAGON_SCALE_DUST, 69, 157.5)
+RANGING_POT = append_finished_potion(169, UNF_DWARF_WEED, WINE_ZAMORAK, 72, 162.5)
+MAGIC_POT = append_finished_potion(3042, UNF_LANTADYME, POTATO_CACTUS, 76, 172.5)
+ZAMORAK_BREW = append_finished_potion(189, UNF_TORSTOL, JANGERBERRIES, 78, 175)
\ No newline at end of file