Add Herblore skill.

This commit is contained in:
Major-
2014-02-15 16:01:04 +00:00
parent d2580074ae
commit 7efa7690ab
5 changed files with 831 additions and 0 deletions
+90
View File
@@ -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)
+101
View File
@@ -0,0 +1,101 @@
# Thanks to Sillhouette <http://www.rune-server.org/members/silhouette/> 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
+258
View File
@@ -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)
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<plugin>
<id>skill-herblore</id>
<version>1</version>
<name>Herblore</name>
<description>Adds the Herblore skill.</description>
<authors>
<author>Chris Fletcher</author>
<author>Major</author>
</authors>
<scripts>
<script>herblore.rb</script>
<script>ingredient.rb</script>
<script>herb.rb</script>
<script>potion.rb</script>
</scripts>
<dependencies />
</plugin>
+364
View File
@@ -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)