Merge pull request #1 from apollo-rsps/master

merge from apollo-rsps/apollo
This commit is contained in:
Ryley Kimmel
2015-08-27 14:44:46 -04:00
78 changed files with 1688 additions and 1575 deletions
+3
View File
@@ -1,4 +1,6 @@
!.gitignore !.gitignore
!.rubocop.yml
.* .*
*~ *~
*.class *.class
@@ -7,3 +9,4 @@
/data/fs /data/fs
/data/savedGames /data/savedGames
/lib/ /lib/
*/target/
+9
View File
@@ -0,0 +1,9 @@
Style/GlobalVars:
Enabled: false
Style/EmptyLinesAroundBlockBody:
Enabled: false
Performance/ParallelAssignment:
Enabled: false
-4
View File
@@ -3,18 +3,14 @@ require 'java'
java_import 'org.apollo.game.message.impl.DisplayCrossbonesMessage' java_import 'org.apollo.game.message.impl.DisplayCrossbonesMessage'
java_import 'org.apollo.game.model.entity.Player' java_import 'org.apollo.game.model.entity.Player'
# Registers an area action. # Registers an area action.
def area_action(name, &block) def area_action(name, &block)
AREA_ACTIONS[name] = action = AreaAction.new AREA_ACTIONS[name] = action = AreaAction.new
action.instance_eval(&block) action.instance_eval(&block)
end end
AREA_ACTIONS = {} AREA_ACTIONS = {}
private private
# An action that is called when a player enters or exits an area. # An action that is called when a player enters or exits an area.
+15 -16
View File
@@ -4,19 +4,18 @@ java_import 'org.apollo.game.model.Position'
java_import 'org.apollo.game.model.entity.EntityType' java_import 'org.apollo.game.model.entity.EntityType'
java_import 'org.apollo.game.model.entity.Player' java_import 'org.apollo.game.model.entity.Player'
# Creates a new area and registers it with the supplied coordinates. # Creates a new area and registers it with the supplied coordinates.
def area(hash) def area(hash)
raise 'Hash must contain a name, coordinates, and actions pair.' unless hash.has_keys?(:name, :coordinates, :actions) failure_message = 'Hash must contain a name, coordinates, and actions pair.'
name = hash[:name]; coordinates = hash[:coordinates]; actions = hash[:actions] fail failure_message unless hash.has_keys?(:name, :coordinates, :actions)
actions = [ actions ] if actions.is_a?(Symbol) name, coordinates, actions = hash[:name], hash[:coordinates], hash[:actions]
actions.map! { |action| AREA_ACTIONS[action]}
actions = [actions] if actions.is_a?(Symbol)
actions.map! { |action| AREA_ACTIONS[action] }
@areas << Area.new(name, coordinates, actions) @areas << Area.new(name, coordinates, actions)
end end
private private
# A map of coordinates (as an array) to areas. # A map of coordinates (as an array) to areas.
@@ -31,23 +30,23 @@ class Area
@actions = actions @actions = actions
end end
def min_x() # TODO better data structure and methods than this def min_x # TODO: better data structure and methods than this
@coordinates[0] @coordinates[0]
end end
def min_y() def min_y
@coordinates[1] @coordinates[1]
end end
def max_x() def max_x
@coordinates[2] @coordinates[2]
end end
def max_y() def max_y
@coordinates[3] @coordinates[3]
end end
def height() def height
@coordinates[4] @coordinates[4]
end end
@@ -79,7 +78,7 @@ on :mob_position_update do |event|
next_inside = event.next.inside(area) next_inside = event.next.inside(area)
if was_inside if was_inside
if next_inside then area.inside(mob) else area.exited(mob) end next_inside ? area.inside(mob) : area.exited(mob)
else else
area.entered(mob) if next_inside area.entered(mob) if next_inside
end end
@@ -91,10 +90,10 @@ class Position
# Returns whether or not this Position is inside the specified Area. # Returns whether or not this Position is inside the specified Area.
def inside(area) def inside(area)
return false if (x < area.min_x() || x > area.max_x() || y < area.min_y() || y > area.max_y()) return false if x < area.min_x || x > area.max_x || y < area.min_y || y > area.max_y
z = area.height() z = area.height
return true if (z.nil? || z == height) z.nil? || z == height
end end
end end
+3 -2
View File
@@ -7,7 +7,8 @@ BANK_BOOTH_ID = 2213
BANK_BOOTH_SIZE = 1 BANK_BOOTH_SIZE = 1
# The npcs with a 'bank' menu action. # The npcs with a 'bank' menu action.
BANKER_NPCS = [ 166, 494, 495, 496, 497, 498, 499, 1036, 1360, 1702, 2163, 2164, 2354, 2355, 2568, 2569, 2570 ] BANKER_NPCS = [166, 494, 495, 496, 497, 498, 499, 1036, 1360, 1702, 2163, 2164, 2354, 2355, 2568,
2569, 2570]
# A distanced action to open a new bank. # A distanced action to open a new bank.
class BankAction < DistancedAction class BankAction < DistancedAction
@@ -25,7 +26,7 @@ class BankAction < DistancedAction
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @position == other.position) get_class == other.get_class && @position == other.position
end end
end end
+24 -24
View File
@@ -1,7 +1,5 @@
# A script to 'bootstrap' all of the other plugins, wrapping Apollo's verbose # A script bootstrapper for the rest of the plugins, which wraps Apollo's
# Java-style API in a Ruby-style API. # verbose Java-style API in a Ruby-style API.
#
# Written by Graham.
# ********************************** WARNING ********************************** # ********************************** WARNING **********************************
# * If you do not really understand what this is for, do not edit it without * # * If you do not really understand what this is for, do not edit it without *
@@ -34,7 +32,7 @@ RIGHTS_STANDARD = PrivilegeLevel::STANDARD
class String class String
# Converts a ruby snake_case string to camel-case. # Converts a ruby snake_case string to camel-case.
def camelize() def camelize
gsub(/(?:^|_)(.)/) { $1.upcase } gsub(/(?:^|_)(.)/) { $1.upcase }
end end
@@ -68,8 +66,8 @@ class ProcEventListener
# Executes the block handling the Event. # Executes the block handling the Event.
def handle(event) def handle(event)
args = [ event ] args = [event]
args << event.player if event.kind_of?(PlayerEvent) args << event.player if event.is_a?(PlayerEvent)
@block.call(*args) @block.call(*args)
end end
@@ -87,7 +85,7 @@ class ProcMessageHandler < MessageHandler
# Handles the message. # Handles the message.
def handle(player, message) def handle(player, message)
@block.call(player, message) if (@option == 0 || @option == message.option) @block.call(player, message) if @option == 0 || @option == message.option
end end
end end
@@ -119,14 +117,15 @@ end
# behaviour is undefined (and most likely it'll be bad). # behaviour is undefined (and most likely it'll be bad).
def schedule(*args, &block) def schedule(*args, &block)
if block_given? if block_given?
raise 'Invalid combination of arguments.' unless (1..2).include?(args.length) fail 'Invalid combination of arguments.' unless (1..2).include?(args.length)
delay = args[0] delay = args[0]
immediate = args.length == 2 ? args[1] : false immediate = args.length == 2 ? args[1] : false
$world.schedule(ProcScheduledTask.new(delay, immediate, block)) $world.schedule(ProcScheduledTask.new(delay, immediate, block))
elsif args.length == 1 elsif args.length == 1
$world.schedule(args[0]) $world.schedule(args[0])
else else
raise 'Invalid combination of arguments.' fail 'Invalid combination of arguments.'
end end
end end
@@ -153,15 +152,15 @@ def on(type, *args, &block)
when :message then on_message(args, block) when :message then on_message(args, block)
when :button then on_button(args, block) when :button then on_button(args, block)
else else
class_name = type.to_s.camelize.concat('Event') class_name = type.to_s.camelize.concat('Event')
type = Java::JavaClass.for_name("org.apollo.game.model.event.impl.#{class_name}") type = Java::JavaClass.for_name("org.apollo.game.model.event.impl.#{class_name}")
$world.listen_for(type, ProcEventListener.new(block)) $world.listen_for(type, ProcEventListener.new(block))
end end
end end
# Defines an action to be taken upon a button press. # Defines an action to be taken upon a button press.
def on_button(args, proc) def on_button(args, proc)
raise 'Button must have one argument.' unless args.length == 1 fail 'Button must have one argument.' unless args.length == 1
id = args[0].to_i id = args[0].to_i
@@ -171,24 +170,25 @@ def on_button(args, proc)
end end
# Defines an action to be taken upon a message. # Defines an action to be taken upon a message.
# The message can either be a symbol with the lower-case underscored class name, or the class itself. # The message can either be a symbol with the lowercase underscored class name, or the class itself.
def on_message(args, proc) def on_message(args, proc)
raise 'Message must have one or two arguments.' unless (1..2).include?(args.length) fail 'Message must have one or two arguments.' unless (1..2).include?(args.length)
numbers = [ 'first', 'second', 'third', 'fourth', 'fifth' ]
message = args[0]; option = 0
numbers.each_index do |index| numbers = %w(first second third fourth fifth)
message = args[0].to_s
option = 0
(0..numbers.length).each do |index|
number = numbers[index] number = numbers[index]
if message.to_s.start_with?(number) if message.start_with?(number)
option = index + 1 option = index + 1
message = message[number.length + 1, message.length].to_sym message = message[number.length + 1, message.length]
break break
end end
end end
class_name = message.camelize.concat('Message')
class_name = message.to_s.camelize.concat('Message')
message = Java::JavaClass.for_name("org.apollo.game.message.impl.#{class_name}") message = Java::JavaClass.for_name("org.apollo.game.message.impl.#{class_name}")
$ctx.add_message_handler(message, ProcMessageHandler.new(proc, option)) $ctx.add_message_handler(message, ProcMessageHandler.new(proc, option))
@@ -196,7 +196,7 @@ end
# Defines an action to be taken upon a command. # Defines an action to be taken upon a command.
def on_command(args, proc) def on_command(args, proc)
raise 'Command message must have one or two arguments.' unless (1..2).include?(args.length) fail 'Command message must have one or two arguments.' unless (1..2).include?(args.length)
rights = args.length == 2 ? args[1] : RIGHTS_STANDARD rights = args.length == 2 ? args[1] : RIGHTS_STANDARD
$world.command_dispatcher.register(args[0].to_s, ProcCommandListener.new(rights, proc)) $world.command_dispatcher.register(args[0].to_s, ProcCommandListener.new(rights, proc))
+32 -21
View File
@@ -8,9 +8,8 @@ java_import 'org.apollo.game.model.entity.setting.ServerStatus'
java_import 'org.apollo.game.model.entity.setting.PrivacyState' java_import 'org.apollo.game.model.entity.setting.PrivacyState'
java_import 'org.apollo.game.model.entity.Player' java_import 'org.apollo.game.model.entity.Player'
# Processes an add friend message, updating the logged-in status of the player (and the person they
# added) if necessary.
# Processes an add friend message, updating the logged-in status of the player (and the person they added) if necessary.
on :message, :add_friend do |player, message| on :message, :add_friend do |player, message|
friend_username = message.username friend_username = message.username
player_username = player.username player_username = player.username
@@ -18,14 +17,23 @@ on :message, :add_friend do |player, message|
player.add_friend(friend_username) player.add_friend(friend_username)
friend = $world.get_player(friend_username) friend = $world.get_player(friend_username)
if friend == nil # the friend the player added is offline if friend.nil? # the friend the player added is offline
player.send(SendFriendMessage.new(friend_username, 0)) player.send(SendFriendMessage.new(friend_username, 0))
elsif friend.friends_with(player_username) # new friend already has the player added elsif friend.friends_with(player_username)
friend.send(SendFriendMessage.new(player_username, player.world_id)) unless player.friend_privacy == PrivacyState::OFF # player's private chat state is not off, so notify the friend
player.send(SendFriendMessage.new(friend_username, friend.world_id)) unless friend.friend_privacy == PrivacyState::OFF # new friend's private chat state is not off, so notify the player # player's private chat state is not off, so notify the friend
elsif friend.friend_privacy == PrivacyState::ON # new friend doesn't have the player added but their private chat state is on unless player.friend_privacy == PrivacyState::OFF
player.send(SendFriendMessage.new(friend_username, friend.world_id)) # so we can let the player know what world they're on friend.send(SendFriendMessage.new(player_username, player.world_id))
end
# new friend's private chat state is not off, so notify the player
unless friend.friend_privacy == PrivacyState::OFF
player.send(SendFriendMessage.new(friend_username, friend.world_id))
end
elsif friend.friend_privacy == PrivacyState::ON
# new friend doesn't have the player added but their private chat state is on, so inform the
# player of the world they are on.
player.send(SendFriendMessage.new(friend_username, friend.world_id))
end end
end end
@@ -35,24 +43,28 @@ on :message, :remove_friend do |player, message|
player_username = player.username player_username = player.username
player.remove_friend(friend_username) player.remove_friend(friend_username)
if ($world.is_player_online(friend_username)) if $world.is_player_online(friend_username)
friend = $world.get_player(friend_username) friend = $world.get_player(friend_username)
friend.send(SendFriendMessage.new(player_username, 0)) if (friend.friends_with(player_username) && player.friend_privacy != PrivacyState::ON)
remove = friend.friends_with(player_username) && player.friend_privacy != PrivacyState::ON
friend.send(SendFriendMessage.new(player_username, 0)) if remove
end end
end end
# Update the friend server status and send the friend/ignore lists of the player logging in. # Update the friend server status and send the friend/ignore lists of the player logging in.
on :login do |event, player| on :login do |_event, player|
player.send(FriendServerStatusMessage.new(ServerStatus::CONNECTING)) player.send(FriendServerStatusMessage.new(ServerStatus::CONNECTING))
player.send(IgnoreListMessage.new(player.ignored_usernames)) if player.ignored_usernames.size > 0 player.send(IgnoreListMessage.new(player.ignored_usernames)) if player.ignored_usernames.size > 0
username = player.username username = player.username
world = $world world = $world
iterator = player.friend_usernames.iterator # Iterate the player's friend list and notify the player that they are online if they are iterator = player.friend_usernames.iterator
# Iterate the player's friend list and notify the player that they are online if they are
while iterator.has_next while iterator.has_next
friend_username = iterator.next friend_username = iterator.next
friend = world.get_player(friend_username) friend = world.get_player(friend_username)
friend_world_id = (friend == nil || !viewable?(friend, username)) ? 0 : friend.world_id friend_world_id = (friend.nil? || !viewable?(friend, username)) ? 0 : friend.world_id
player.send(SendFriendMessage.new(friend_username, friend_world_id)) player.send(SendFriendMessage.new(friend_username, friend_world_id))
end end
@@ -62,14 +74,13 @@ on :login do |event, player|
end end
# Notifies the player's friends that the player has logged out. # Notifies the player's friends that the player has logged out.
on :logout do |event, player| on :logout do |_event, player|
update_friends(player, 0) update_friends(player, 0)
end end
# Notifies the currently logged in players that the specified player has logged into the specified
# Notifies the currently logged in players that the specified player has logged into the specified world, unless the # world, unless the newly logged-in player has their friend privacy state set to 'off'.
# newly logged-in player has their friend privacy state set to 'off'. def update_friends(player, world = 0)
def update_friends(player, world=0)
privacy = player.friend_privacy privacy = player.friend_privacy
iterator = $world.player_repository.iterator iterator = $world.player_repository.iterator
@@ -77,7 +88,7 @@ def update_friends(player, world=0)
while iterator.has_next while iterator.has_next
other = iterator.next other = iterator.next
next if (!other.friends_with(username) || other == player) next if !other.friends_with(username) || other == player
world = viewable?(player, other.username) ? world : 0 world = viewable?(player, other.username) ? world : 0
other.send(SendFriendMessage.new(username, world)) other.send(SendFriendMessage.new(username, world))
@@ -87,5 +98,5 @@ end
# Checks if the specified player can be viewed by the player with the specified other username # Checks if the specified player can be viewed by the player with the specified other username
def viewable?(player, other_username) def viewable?(player, other_username)
privacy = player.friend_privacy privacy = player.friend_privacy
return privacy != PrivacyState::OFF && player.friends_with(other_username) || privacy == PrivacyState::ON privacy != PrivacyState::OFF && player.friends_with(other_username) || privacy == PrivacyState::ON
end end
@@ -6,14 +6,18 @@ java_import 'org.apollo.game.model.entity.setting.PrivacyState'
on :message, :private_chat do |player, message| on :message, :private_chat do |player, message|
friend = $world.get_player(message.username) friend = $world.get_player(message.username)
friend.send(ForwardPrivateChatMessage.new(player.username, player.privilege_level, message.compressed_chat)) if interaction_permitted(player, friend)
if interaction_permitted(player, friend)
chat = message.compressed_chat
friend.send(ForwardPrivateChatMessage.new(player.username, player.privilege_level, chat))
end
end end
# Checks if the sender is permitted to interact with the friend they have added: # Checks if the sender is permitted to interact with the friend they have added:
def interaction_permitted(sender, friend) def interaction_permitted(sender, friend)
if friend.nil? || friend.has_ignored(sender.username) username = sender.username
return false return false if friend.nil? || friend.has_ignored(username)
end
return friend.friends_with(sender.username) ? (friend.friend_privacy != PrivacyState::OFF) : (friend.friend_privacy == PrivacyState::ON) privacy = friend.friend_privacy
friend.friends_with(username) ? (privacy != PrivacyState::OFF) : (privacy == PrivacyState::ON)
end end
+1 -1
View File
@@ -1,6 +1,6 @@
require 'java' require 'java'
# Opens the player's bank. # Opens the player's bank.
on :command, :bank, RIGHTS_ADMIN do |player, command| on :command, :bank, RIGHTS_ADMIN do |player, _command|
player.open_bank player.open_bank
end end
+6 -4
View File
@@ -9,7 +9,8 @@ on :command, :item, RIGHTS_ADMIN do |player, command|
id = args[0].to_i id = args[0].to_i
amount = args.length == 2 ? args[1].to_i : 1 amount = args.length == 2 ? args[1].to_i : 1
if (id < 0 || id >= ItemDefinition.count)
if id < 0 || id >= ItemDefinition.count
player.send_message('The item id you specified is out of bounds!') player.send_message('The item id you specified is out of bounds!')
next next
end end
@@ -24,7 +25,8 @@ on :command, :remove, RIGHTS_MOD do |player, command|
id = args[0].to_i id = args[0].to_i
amount = args.length == 2 ? args[1].to_i : 1 amount = args.length == 2 ? args[1].to_i : 1
if (id < 0 || id >= ItemDefinition.count)
if id < 0 || id >= ItemDefinition.count
player.send_message('The item id you specified is out of bounds!') player.send_message('The item id you specified is out of bounds!')
next next
end end
@@ -33,11 +35,11 @@ on :command, :remove, RIGHTS_MOD do |player, command|
end end
# Clears the player's inventory. # Clears the player's inventory.
on :command, :empty, RIGHTS_MOD do |player, command| on :command, :empty, RIGHTS_MOD do |player, _command|
player.inventory.clear player.inventory.clear
end end
# Gives the player 1,000 of each rune. # Gives the player 1,000 of each rune.
on :command, :runes, RIGHTS_ADMIN do |player, command| on :command, :runes, RIGHTS_ADMIN do |player, _command|
(554..566).each { |item| player.inventory.add(item, 1000) } (554..566).each { |item| player.inventory.add(item, 1000) }
end end
+12 -7
View File
@@ -9,20 +9,22 @@ java_import 'org.apollo.game.model.entity.Player'
on :command, :lookup, RIGHTS_ADMIN do |player, command| on :command, :lookup, RIGHTS_ADMIN do |player, command|
args = command.arguments.to_a args = command.arguments.to_a
next unless valid_arg_length(args, (1..10), player, 'Invalid syntax - ::lookup [npc/object/item] [name]') message = 'Invalid syntax - ::lookup [npc/object/item] [name]'
next unless valid_arg_length(args, (1..10), player, message)
type = args.shift.downcase type = args.shift.downcase
limit = args.first.to_i == 0 ? 5 : args.shift.to_i; limit = args.first.to_i == 0 ? 5 : args.shift.to_i
name = args.join(' ').downcase name = args.join(' ').downcase
if ['npc', 'object', 'item'].index(type) == nil if %w(npc object item).index(type).nil?
player.send_message('Invalid syntax - ::lookup [npc/object/item] [name]') player.send_message('Invalid syntax - ::lookup [npc/object/item] [name]')
next next
end end
ids = find_entities(type, name, limit).join(', ') ids = find_entities(type, name, limit).join(', ')
message = ids.empty? ? "Could not find an #{type} called #{name}." : "Possible ids for \"#{name}\" are: #{ids}." message = ids.empty? ? "Could not find an #{type} called #{name}." :
"Possible ids for \"#{name}\" are: #{ids}."
player.send_message(message) player.send_message(message)
end end
@@ -35,7 +37,8 @@ on :command, :iteminfo, RIGHTS_ADMIN do |player, command|
definition = ItemDefinition.lookup(id) definition = ItemDefinition.lookup(id)
members = definition.is_members_only ? 'members' : 'not members' members = definition.is_members_only ? 'members' : 'not members'
player.send_message("Item #{id} is called #{definition.name}, is #{members} only, and has a team of #{definition.team}.") player.send_message("Item #{id} is called #{definition.name}, is #{members} only, and has a "\
"team of #{definition.team}.")
player.send_message("Its description is \"#{definition.description}\".") player.send_message("Its description is \"#{definition.description}\".")
end end
@@ -46,7 +49,8 @@ on :command, :npcinfo, RIGHTS_ADMIN do |player, command|
id = args[0].to_i id = args[0].to_i
definition = NpcDefinition.lookup(id) definition = NpcDefinition.lookup(id)
is_combative = definition.has_combat_level ? "has a combat level of #{definition.combat_level}" : "does not have a combat level" is_combative = definition.has_combat_level ? "has a combat level of #{definition.combat_level}" :
'does not have a combat level'
player.send_message("Npc #{id} is called #{definition.name} and #{is_combative}.") player.send_message("Npc #{id} is called #{definition.name} and #{is_combative}.")
player.send_message("Its description is \"#{definition.description}\".") player.send_message("Its description is \"#{definition.description}\".")
@@ -59,6 +63,7 @@ on :command, :objectinfo, RIGHTS_ADMIN do |player, command|
id = args[0].to_i id = args[0].to_i
definition = ObjectDefinition.lookup(id) definition = ObjectDefinition.lookup(id)
player.send_message("Object #{id} is called #{definition.name} and its description is \"#{definition.description}\".") player.send_message("Object #{id} is called #{definition.name} and its description is "\
"\"#{definition.description}\".")
player.send_message("Its width is #{definition.width} and its length is #{definition.length}.") player.send_message("Its width is #{definition.width} and its length is #{definition.length}.")
end end
+3 -2
View File
@@ -5,7 +5,8 @@ java_import 'org.apollo.game.model.entity.Player'
# Adds a command to broadcast a message to every player on the server. # Adds a command to broadcast a message to every player on the server.
on :command, :broadcast, RIGHTS_ADMIN do |player, command| on :command, :broadcast, RIGHTS_ADMIN do |player, command|
message = command.arguments.to_a.join(" ") message = command.arguments.to_a.join(' ')
broadcast = "[Broadcast] #{player.get_username.capitalize}: #{message}" broadcast = "[Broadcast] #{player.get_username.capitalize}: #{message}"
$world.player_repository.each { |player| player.send_message(broadcast) }
$world.player_repository.each { |other| other.send_message(broadcast) }
end end
+2 -1
View File
@@ -1,5 +1,6 @@
require 'java' require 'java'
on :command, :filter do |player, command| on :command, :filter do |player, command|
player.send_message('Your message filter is now ' + (player.toggle_message_filter ? 'enabled.' : 'disabled.')) status = player.toggle_message_filter ? 'enabled' : 'disabled'
player.send_message('Your message filter is now ' + status + '.')
end end
+19 -12
View File
@@ -7,11 +7,12 @@ java_import 'org.apollo.game.model.entity.Npc'
# An array of npcs that cannot be spawned. # An array of npcs that cannot be spawned.
blacklist = [] blacklist = []
# Spawns a non-blacklisted npc in the specified position, or the player's position if both 'x' and 'y' are not supplied. # Spawns a non-blacklisted npc in the specified position, or the player's position if both 'x' and
# 'y' are not supplied.
on :command, :spawn, RIGHTS_ADMIN do |player, command| on :command, :spawn, RIGHTS_ADMIN do |player, command|
args = command.arguments args = command.arguments
unless [1, 3].include?(args.length) and (id = args[0].to_i) > -1 unless [1, 3, 4].include?(args.length) && (id = args[0].to_i) > -1
player.send_message('Invalid syntax - ::spawn [npc id] [optional-x] [optional-y]') player.send_message('Invalid syntax - ::spawn [npc id] [optional-x] [optional-y] [optional-z]')
return return
end end
@@ -20,7 +21,12 @@ on :command, :spawn, RIGHTS_ADMIN do |player, command|
return return
end end
position = args.length == 1 ? player.position : Position.new(args[1].to_i, args[2].to_i, player.position.height) if args.length == 1
position = player.position
else
height = args.length == 4 ? args[3].to_i : player.position.height
position = Position.new(args[1].to_i, args[2].to_i, height)
end
$world.register(Npc.new(id, position)) $world.register(Npc.new(id, position))
end end
@@ -28,7 +34,7 @@ end
# Mass spawns npcs around the player. # Mass spawns npcs around the player.
on :command, :mass, RIGHTS_ADMIN do |player, command| on :command, :mass, RIGHTS_ADMIN do |player, command|
args = command.arguments args = command.arguments
unless args.length == 2 and (id = args[0].to_i) > -1 and (1..5).include?(range = args[1].to_i) unless args.length == 2 && (id = args[0].to_i) > -1 && (1..5).include?(range = args[1].to_i)
player.send_message('Invalid syntax - ::spawn [npc id] [range (1-5)]') player.send_message('Invalid syntax - ::spawn [npc id] [range (1-5)]')
return return
end end
@@ -40,22 +46,23 @@ on :command, :mass, RIGHTS_ADMIN do |player, command|
center_position = player.position center_position = player.position
minX = center_position.x - range min_x = center_position.x - range
minY = center_position.y - range min_y = center_position.y - range
maxX = center_position.x + range max_x = center_position.x + range
maxY = center_position.y + range max_y = center_position.y + range
z = center_position.height z = center_position.height
for x in minX..maxX do (min_x..max_x).each do |x|
for y in minY..maxY do (min_y..max_y).each do |y|
$world.register(Npc.new(id, Position.new(x, y, z))) $world.register(Npc.new(id, Position.new(x, y, z)))
end end
end end
player.send_message("Mass spawning npcs with id #{id}.") player.send_message("Mass spawning npcs with id #{id}.")
end end
# Unregisters all npcs from the world npc repository. # Unregisters all npcs from the world npc repository.
on :command, :clearnpcs, RIGHTS_ADMIN do |player, command| on :command, :clearnpcs, RIGHTS_ADMIN do |player, _command|
$world.npc_repository.each { |npc| $world.unregister(npc) } $world.npc_repository.each { |npc| $world.unregister(npc) }
player.send_message('Unregistered all npcs from the world.') player.send_message('Unregistered all npcs from the world.')
end end
+9 -6
View File
@@ -3,8 +3,9 @@ java_import 'org.apollo.game.model.entity.SkillSet'
java_import 'org.apollo.game.model.entity.Skill' java_import 'org.apollo.game.model.entity.Skill'
# Maximises the player's skill set. # Maximises the player's skill set.
on :command, :max, RIGHTS_ADMIN do |player, command| on :command, :max, RIGHTS_ADMIN do |player, _command|
skills = player.skill_set skills = player.skill_set
(0...skills.size).each do |skill| (0...skills.size).each do |skill|
skills.add_experience(skill, SkillSet::MAXIMUM_EXP) skills.add_experience(skill, SkillSet::MAXIMUM_EXP)
end end
@@ -13,15 +14,16 @@ end
# Levels the specified skill to the specified level, optionally updating the current level as well. # Levels the specified skill to the specified level, optionally updating the current level as well.
on :command, :level, RIGHTS_ADMIN do |player, command| on :command, :level, RIGHTS_ADMIN do |player, command|
args = command.arguments args = command.arguments
unless (2..3).include?(args.length) && (0..20).include?(skill_id = args[0].to_i) && (1..99).include?(level = args[1].to_i) unless (2..3).include?(args.length) && (0..20).include?(skill_id = args[0].to_i) &&
player.send_message("Invalid syntax - ::level [skill-id] [level]") (1..99).include?(level = args[1].to_i)
player.send_message('Invalid syntax - ::level [skill-id] [level]')
return return
end end
experience = SkillSet.experience_for_level(level) experience = SkillSet.experience_for_level(level)
current = level current = level
if args.length == 3 && args[2].to_s == "old" if args.length == 3 && args[2].to_s == 'old'
skill = player.skill_set.skill(skill_id) skill = player.skill_set.skill(skill_id)
current = skill.current_level current = skill.current_level
end end
@@ -32,8 +34,9 @@ end
# Adds the specified amount of experience to the specified skill. # Adds the specified amount of experience to the specified skill.
on :command, :xp, RIGHTS_ADMIN do |player, command| on :command, :xp, RIGHTS_ADMIN do |player, command|
args = command.arguments args = command.arguments
unless args.length == 2 && (0..20).include?(skill_id = args[0].to_i) && (experience = args[1].to_i) >= 0 unless args.length == 2 && (0..20).include?(skill_id = args[0].to_i) &&
player.send_message("Invalid syntax - ::xp [skill-id] [experience]") (experience = args[1].to_i) >= 0
player.send_message('Invalid syntax - ::xp [skill-id] [experience]')
return return
end end
+2 -4
View File
@@ -3,10 +3,8 @@ require 'java'
java_import 'org.apollo.game.model.Position' java_import 'org.apollo.game.model.Position'
# Sends the player's position. # Sends the player's position.
on :command, :pos, RIGHTS_MOD do |player, command| on :command, :pos, RIGHTS_MOD do |player, _command|
position = player.position player.send_message("You are at: #{player.position}.")
player.send_message("You are at: #{position}.")
player.send_message("Local coordinates: (#{position.get_local_x}, #{position.get_local_y}).")
end end
# Teleports the player to the specified position. # Teleports the player to the specified position.
+17 -13
View File
@@ -4,6 +4,7 @@ java_import 'org.apollo.game.model.entity.Player'
java_import 'org.apollo.game.message.impl.SetWidgetTextMessage' java_import 'org.apollo.game.message.impl.SetWidgetTextMessage'
java_import 'org.apollo.game.message.impl.OpenOverlayMessage' java_import 'org.apollo.game.message.impl.OpenOverlayMessage'
declare_attribute(:wilderness_level, 0, :transient)
# Constants constants related to the wilderness # Constants constants related to the wilderness
module WildernessConstants module WildernessConstants
@@ -16,47 +17,50 @@ module WildernessConstants
end end
declare_attribute(:wilderness_level, 0, :transient)
# Determines the wilderness level for the specified player's position # Determines the wilderness level for the specified player's position
def wilderness_level(player) def wilderness_level(player)
return ((player.position.y - 3520) / 8).ceil ((player.position.y - 3520) / 8).ceil
end end
area_action :wilderness_level do area_action :wilderness_level do
on_entry do |player| on_entry do |player|
player.wilderness_level = wilderness_level(player) player.wilderness_level = wilderness_level(player)
player.interface_set.open_overlay(WildernessConstants::OVERLAY_INTERFACE_ID) player.interface_set.open_overlay(WildernessConstants::OVERLAY_INTERFACE_ID)
player.send(SetWidgetTextMessage.new(WildernessConstants::LEVEL_STRING_ID, "Level: #{player.wilderness_level}"))
id = WildernessConstants::LEVEL_STRING_ID
player.send(SetWidgetTextMessage.new(id, "Level: #{player.wilderness_level}"))
show_action(player, ATTACK_ACTION) show_action(player, ATTACK_ACTION)
end end
while_in do |player| while_in do |player|
current = player.wilderness_level current = player.wilderness_level
updated = wilderness_level(player) updated = wilderness_level(player)
if (current != updated)
player.wilderness_level = updated if current != updated
player.send(SetWidgetTextMessage.new(WildernessConstants::LEVEL_STRING_ID, "Level: #{player.wilderness_level}")) player.wilderness_level = updated
id = WildernessConstants::LEVEL_STRING_ID
player.send(SetWidgetTextMessage.new(id, "Level: #{player.wilderness_level}"))
end end
end end
on_exit do |player| on_exit do |player|
player.wilderness_level = 0 player.wilderness_level = 0
player.interface_set.close() player.interface_set.close
player.send(OpenOverlayMessage.new(-1)) player.send(OpenOverlayMessage.new(-1))
hide_action(player, ATTACK_ACTION) hide_action(player, ATTACK_ACTION)
end end
end end
# Monkey patch the existing player class to add method of checking whether or not a player is within the wilderness # Monkey patch the existing player class to add method of checking whether or not a player is
# within the wilderness
class Player class Player
def in_wilderness def in_wilderness
self.wilderness_level > 0 wilderness_level > 0
end end
end end
area :name => :wilderness, :coordinates => [ 2945, 3522, 3390, 3972, 0 ], :actions => :wilderness_level area name: :wilderness, coordinates: [2945, 3522, 3390, 3972, 0], actions: :wilderness_level
+7 -4
View File
@@ -3,6 +3,7 @@ require 'java'
# A map of item ids to consumables. # A map of item ids to consumables.
CONSUMABLES = {} CONSUMABLES = {}
# The id of the food consumption animation.
CONSUME_ANIMATION_ID = 829 CONSUME_ANIMATION_ID = 829
# An item that can be consumed to produce a skill effect. # An item that can be consumed to produce a skill effect.
@@ -15,8 +16,8 @@ class Consumable
@sound = sound @sound = sound
end end
def consume(player) def consume(_player)
# Override to provide specific functionality. # Override to provide specific functionality.
end end
end end
@@ -26,6 +27,7 @@ def append_consumable(consumable)
CONSUMABLES[consumable.id] = consumable CONSUMABLES[consumable.id] = consumable
end end
# An Action used for food consumption.
class ConsumeAction < Action class ConsumeAction < Action
attr_reader :consumable attr_reader :consumable
@@ -36,10 +38,11 @@ class ConsumeAction < Action
@executions = 0 @executions = 0
end end
def execute() def execute
if @executions == 0 if @executions == 0
mob.inventory.reset(@slot) mob.inventory.reset(@slot)
@consumable.consume(mob) @consumable.consume(mob)
mob.play_animation(Animation.new(CONSUME_ANIMATION_ID)) mob.play_animation(Animation.new(CONSUME_ANIMATION_ID))
@executions += 1 @executions += 1
else else
@@ -48,7 +51,7 @@ class ConsumeAction < Action
end end
def equals(other) def equals(other)
return (mob == other.mob && @consumable.id == other.consumable.id) mob == other.mob && @consumable.id == other.consumable.id
end end
end end
+183 -178
View File
@@ -6,10 +6,11 @@ java_import 'org.apollo.game.model.entity.Player'
private private
# The id the of the sound made when eating food.
EAT_FOOD_SOUND = 317 EAT_FOOD_SOUND = 317
# Represents an edible piece of food, such as bread or fish. # Represents an edible piece of food, such as bread or fish.
# TODO delay eating times # TODO: delay eating times
class Food < Consumable class Food < Consumable
def initialize(name, id, restoration, replace) def initialize(name, id, restoration, replace)
@@ -21,221 +22,225 @@ class Food < Consumable
# Restore the appropriate amount of hitpoints when consumed. # Restore the appropriate amount of hitpoints when consumed.
def consume(player) def consume(player)
hitpoints = player.skill_set.skill(Skill::HITPOINTS) hitpoints = player.skill_set.skill(Skill::HITPOINTS)
new_curr = [ hitpoints.current_level + @restoration, hitpoints.maximum_level ].min new_curr = [hitpoints.current_level + @restoration, hitpoints.maximum_level].min
player.inventory.add(@replace) unless (@replace == -1) player.inventory.add(@replace) unless @replace == -1
player.send_message("You eat the #{name}.", true) player.send_message("You eat the #{name}.", true)
player.send_message("It heals some health.", true) if new_curr == hitpoints player.send_message('It heals some health.', true) if new_curr == hitpoints
player.skill_set.set_skill(Skill::HITPOINTS, Skill.new(hitpoints.experience, new_curr, hitpoints.maximum_level)) skill = Skill.new(hitpoints.experience, new_curr, hitpoints.maximum_level)
player.skill_set.set_skill(Skill::HITPOINTS, skill)
end end
end end
# The default delay before a piece of food is eaten
DEFAULT_DELAY = 3
# Appends a food item to the list of consumables. # Appends a food item to the list of consumables.
def food(hash) def food(hash)
raise 'Hash must contain a name, id, and a restoration value.' unless (hash.has_keys?(:name, :id, :restoration)) unless hash.has_keys?(:name, :id, :restoration)
name = hash[:name]; id = hash[:id]; restoration = hash[:restoration]; replace = hash[:replace] || -1; @delay = hash[:delay] || 3 fail 'Hash must contain a name, id, and a restoration value.'
end
name, id, restoration = hash[:name], hash[:id], hash[:restoration];
replace = hash[:replace] || -1
delay = hash[:delay] || DEFAULT_DELAY # TODO: ??
append_consumable(Food.new(name, id, restoration, replace)) append_consumable(Food.new(name, id, restoration, replace))
end end
# TODO special effects # TODO: special effects
food :name => :cooked_slimy_eel, :id => 3381, :restoration => 6 # this has a chance to heal 6 to 10 hp food name: :cooked_slimy_eel, id: 3381, restoration: 6 # this has a chance to heal 6 to 10 hp
food :name => :thin_snail_meat, :id => 3369, :restoration => 5 # this has a chance to heal 5 to 7 hp food name: :thin_snail_meat, id: 3369, restoration: 5 # this has a chance to heal 5 to 7 hp
food :name => :fat_snail_meat, :id => 3373, :restoration => 2 # this has a chance to heal 7 to 9 hp food name: :fat_snail_meat, id: 3373, restoration: 2 # this has a chance to heal 7 to 9 hp
food :name => :watermelon_slice, :id => 5984, :restoration => 0 # this heals 5% of player's life food name: :watermelon_slice, id: 5984, restoration: 0 # this heals 5% of player's life
food :name => :cooked_karambwan, :id => 3146, :restoration => 0 # poisons player(50) food name: :cooked_karambwan, id: 3146, restoration: 0 # poisons player(50)
food :name => :spider_on_stick, :id => 6297, :restoration => 7 # heals between 7 and 10 food name: :spider_on_stick, id: 6297, restoration: 7 # heals between 7 and 10
food :name => :spider_on_shaft, :id => 6299, :restoration => 7 # heals between 7 and 10 food name: :spider_on_shaft, id: 6299, restoration: 7 # heals between 7 and 10
# Meats/Fish # Meats/Fish
food :name => :anchovies, :id => 319, :restoration => 1 food name: :anchovies, id: 319, restoration: 1
food :name => :crab_meat, :id => 7521, :restoration => 2, :replace => 7523 food name: :crab_meat, id: 7521, restoration: 2, replace: 7523
food :name => :crab_meat, :id => 7523, :restoration => 2, :replace => 7524 food name: :crab_meat, id: 7523, restoration: 2, replace: 7524
food :name => :crab_meat, :id => 7524, :restoration => 2, :replace => 7525 food name: :crab_meat, id: 7524, restoration: 2, replace: 7525
food :name => :crab_meat, :id => 7525, :restoration => 2, :replace => 7526 food name: :crab_meat, id: 7525, restoration: 2, replace: 7526
food :name => :crab_meat, :id => 7526, :restoration => 2 food name: :crab_meat, id: 7526, restoration: 2
food :name => :shrimp, :id => 315, :restoration => 3 food name: :shrimp, id: 315, restoration: 3
food :name => :sardine, :id => 325, :restoration => 3 food name: :sardine, id: 325, restoration: 3
food :name => :cooked_meat, :id => 2142, :restoration => 3 food name: :cooked_meat, id: 2142, restoration: 3
food :name => :cooked_chicken, :id => 2140, :restoration => 3 food name: :cooked_chicken, id: 2140, restoration: 3
food :name => :ugthanki_meat, :id => 1861, :restoration => 3 food name: :ugthanki_meat, id: 1861, restoration: 3
food :name => :karambwanji, :id => 3151, :restoration => 3 food name: :karambwanji, id: 3151, restoration: 3
food :name => :cooked_rabbit, :id => 3228, :restoration => 5 food name: :cooked_rabbit, id: 3228, restoration: 5
food :name => :herring, :id => 347, :restoration => 6 food name: :herring, id: 347, restoration: 6
food :name => :trout, :id => 333, :restoration => 7 food name: :trout, id: 333, restoration: 7
food :name => :cod, :id => 339, :restoration => 7 food name: :cod, id: 339, restoration: 7
food :name => :mackeral, :id => 355, :restoration => 7 food name: :mackeral, id: 355, restoration: 7
food :name => :roast_rabbit, :id => 7223, :restoration => 7 food name: :roast_rabbit, id: 7223, restoration: 7
food :name => :pike, :id => 351, :restoration => 8 food name: :pike, id: 351, restoration: 8
food :name => :lean_snail_meat, :id => 3371, :restoration => 8 food name: :lean_snail_meat, id: 3371, restoration: 8
food :name => :salmon, :id => 329, :restoration => 9 food name: :salmon, id: 329, restoration: 9
food :name => :tuna, :id => 361, :restoration => 10 food name: :tuna, id: 361, restoration: 10
food :name => :lobster, :id => 379, :restoration => 12 food name: :lobster, id: 379, restoration: 12
food :name => :bass, :id => 365, :restoration => 13 food name: :bass, id: 365, restoration: 13
food :name => :swordfish, :id => 373, :restoration => 14 food name: :swordfish, id: 373, restoration: 14
food :name => :cooked_jubbly, :id => 7568, :restoration => 15 food name: :cooked_jubbly, id: 7568, restoration: 15
food :name => :monkfish, :id => 7946, :restoration => 16 food name: :monkfish, id: 7946, restoration: 16
food :name => :cooked_karambwan, :id => 3144, :restoration => 18 food name: :cooked_karambwan, id: 3144, restoration: 18
food :name => :shark, :id => 385, :restoration => 20 food name: :shark, id: 385, restoration: 20
food :name => :sea_turtle, :id => 397, :restoration => 21 food name: :sea_turtle, id: 397, restoration: 21
food :name => :manta_ray, :id => 391, :restoration => 22 food name: :manta_ray, id: 391, restoration: 22
# Breads/Wraps # Breads/Wraps
food :name => :bread, :id => 2309, :restoration => 5 food name: :bread, id: 2309, restoration: 5
food :name => :oomlie_wrap, :id => 2343, :restoration => 14 food name: :oomlie_wrap, id: 2343, restoration: 14
food :name => :ugthanki_kebab, :id => 1883, :restoration => 19 food name: :ugthanki_kebab, id: 1883, restoration: 19
# Fruits # Fruits
food :name => :banana, :id => 1963, :restoration => 2 food name: :banana, id: 1963, restoration: 2
food :name => :sliced_banana, :id => 3162, :restoration => 2 food name: :sliced_banana, id: 3162, restoration: 2
food :name => :lemon, :id => 2102, :restoration => 2 food name: :lemon, id: 2102, restoration: 2
food :name => :lemon_chunks, :id => 2104, :restoration => 2 food name: :lemon_chunks, id: 2104, restoration: 2
food :name => :lemon_slices, :id => 2106, :restoration => 2 food name: :lemon_slices, id: 2106, restoration: 2
food :name => :lime, :id => 2120, :restoration => 2 food name: :lime, id: 2120, restoration: 2
food :name => :lime_chunks, :id => 2122, :restoration => 2 food name: :lime_chunks, id: 2122, restoration: 2
food :name => :lime_slices, :id => 2124, :restoration => 2 food name: :lime_slices, id: 2124, restoration: 2
food :name => :strawberry, :id => 5504, :restoration => 5 food name: :strawberry, id: 5504, restoration: 5
food :name => :papaya_fruit, :id => 5972, :restoration => 8 food name: :papaya_fruit, id: 5972, restoration: 8
food :name => :pineapple_chunks, :id => 2116, :restoration => 2 food name: :pineapple_chunks, id: 2116, restoration: 2
food :name => :pineapple_ring, :id => 2118, :restoration => 2 food name: :pineapple_ring, id: 2118, restoration: 2
food :name => :orange, :id => 2108, :restoration => 2 food name: :orange, id: 2108, restoration: 2
food :name => :orange_rings, :id => 2110, :restoration => 2 food name: :orange_rings, id: 2110, restoration: 2
food :name => :orange_slices, :id => 2112, :restoration => 2 food name: :orange_slices, id: 2112, restoration: 2
# Pies
# TODO: pie special effects (e.g. fish pie raises fishing level)
food name: :redberry_pie, id: 2325, restoration: 5, replace: 2333, delay: 1
food name: :redberry_pie, id: 2333, restoration: 5, delay: 1
# Pies food name: :meat_pie, id: 2327, restoration: 6, replace: 2331, delay: 1
#TODO Special Effects on pies (i.e.fish pie raises fishing level) food name: :meat_pie, id: 2331, restoration: 6, delay: 1
food :name => :redberry_pie, :id => 2325, :restoration => 5, :replace => 2333, :delay => 1
food :name => :redberry_pie, :id => 2333, :restoration => 5, :delay => 1
food :name => :meat_pie, :id => 2327, :restoration => 6, :replace => 2331, :delay => 1 food name: :apple_pie, id: 2323, restoration: 7, replace: 2335, delay: 1
food :name => :meat_pie, :id => 2331, :restoration => 6, :delay => 1 food name: :apple_pie, id: 2335, restoration: 7, delay: 1
food :name => :apple_pie, :id => 2323, :restoration => 7, :replace => 2335, :delay => 1 food name: :fish_pie, id: 7188, restoration: 6, replace: 7190, delay: 1
food :name => :apple_pie, :id => 2335, :restoration => 7, :delay => 1 food name: :fish_pie, id: 7190, restoration: 6, delay: 1
food :name => :fish_pie, :id => 7188, :restoration => 6, :replace => 7190, :delay => 1 food name: :admiral_pie, id: 7198, restoration: 8, replace: 7200, delay: 1
food :name => :fish_pie, :id => 7190, :restoration => 6, :delay => 1 food name: :admiral_pie, id: 7200, restoration: 8, delay: 1
food :name => :admiral_pie, :id => 7198, :restoration => 8, :replace => 7200, :delay => 1 food name: :wild_pie, id: 7208, restoration: 11, replace: 7210, delay: 1
food :name => :admiral_pie, :id => 7200, :restoration => 8, :delay => 1 food name: :wild_pie, id: 7210, restoration: 11, delay: 1
food :name => :wild_pie, :id => 7208, :restoration => 11, :replace => 7210, :delay => 1 food name: :summer_pie, id: 7218, restoration: 11, replace: 7220, delay: 1
food :name => :wild_pie, :id => 7210, :restoration => 11, :delay => 1 food name: :summer_pie, id: 7220, restoration: 11, delay: 1
food :name => :summer_pie, :id => 7218, :restoration => 11, :replace => 7220, :delay => 1 # Stews
food :name => :summer_pie, :id => 7220, :restoration => 11, :delay => 1 food name: :stew, id: 2003, restoration: 11
food name: :banana_stew, id: 4016, restoration: 11
food name: :curry, id: 2011, restoration: 19
# Stews # Pizzas
food :name => :stew, :id => 2003, :restoration => 11 food name: :plain_pizza, id: 2289, restoration: 7, replace: 2291
food :name => :banana_stew, :id => 4016, :restoration => 11 food name: :plain_pizza, id: 2291, restoration: 7
food :name => :curry, :id => 2011, :restoration => 19
# Pizzas food name: :meat_pizza, id: 2293, restoration: 8, replace: 2295
food :name => :plain_pizza, :id => 2289, :restoration => 7, :replace => 2291 food name: :meat_pizza, id: 2295, restoration: 8
food :name => :plain_pizza, :id => 2291, :restoration => 7
food :name => :meat_pizza, :id => 2293, :restoration => 8, :replace => 2295 food name: :anchovy_pizza, id: 2297, restoration: 9, replace: 2299
food :name => :meat_pizza, :id => 2295, :restoration => 8 food name: :anchovy_pizza, id: 2299, restoration: 9
food :name => :anchovy_pizza, :id => 2297, :restoration => 9, :replace => 2299 food name: :pineapple_pizza, id: 2301, restoration: 11, replace: 2303
food :name => :anchovy_pizza, :id => 2299, :restoration => 9 food name: :pineapple_pizza, id: 2303, restoration: 11
food :name => :pineapple_pizza, :id => 2301, :restoration => 11, :replace => 2303 # Cakes
food :name => :pineapple_pizza, :id => 2303, :restoration => 11 food name: :fishcake, id: 7530, restoration: 11
# Cakes food name: :cake, id: 1891, restoration: 4, replace: 1893
food :name => :fishcake, :id => 7530, :restoration => 11 food name: :cake, id: 1893, restoration: 4, replace: 1895
food name: :cake, id: 1895, restoration: 4
food :name => :cake, :id => 1891, :restoration => 4, :replace => 1893 food name: :chocolate_cake, id: 1897, restoration: 5, replace: 1899
food :name => :cake, :id => 1893, :restoration => 4, :replace => 1895 food name: :chocolate_cake, id: 1899, restoration: 5, replace: 1901
food :name => :cake, :id => 1895, :restoration => 4 food name: :chocolate_cake, id: 1901, restoration: 5
food :name => :chocolate_cake, :id => 1897, :restoration => 5, :replace => 1899 # Wine
food :name => :chocolate_cake, :id => 1899, :restoration => 5, :replace => 1901 # TODO: Add to drinks.rb?
food :name => :chocolate_cake, :id => 1901, :restoration => 5 food name: :jug_of_wine, id: 1993, restoration: 11
# Wine # Hot Drinks
# Add to drinks.rb? # TODO: Add to drinks.rb?
food :name => :jug_of_wine, :id => 1993, :restoration => 11 food name: :nettle_tea, id: 4239, restoration: 3
food name: :nettle_tea, id: 4240, restoration: 3
# Hot Drinks # Vegetables
# Add to drinks.rb? food name: :potato, id: 1942, restoration: 1
food :name => :nettle_tea, :id => 4239, :restoration => 3 food name: :spinach_roll, id: 1969, restoration: 2
food :name => :nettle_tea, :id => 4240, :restoration => 3 food name: :baked_potato, id: 6701, restoration: 4
food name: :sweetcorn, id: 5988, restoration: 10
food name: :sweetcorn_bowl, id: 7088, restoration: 13
food name: :potato_with_butter, id: 6703, restoration: 14
food name: :chili_potato, id: 7054, restoration: 14
food name: :potato_with_cheese, id: 6705, restoration: 16
food name: :egg_potato, id: 7056, restoration: 16
food name: :mushroom_potato, id: 7058, restoration: 20
food name: :tuna_potato, id: 7060, restoration: 22
# Vegetables # Dairy
food :name => :potato, :id => 1942, :restoration => 1 food name: :cheese, id: 1985, restoration: 2
food :name => :spinach_roll, :id => 1969, :restoration => 2 food name: :pot_of_cream, id: 2130, restoration: 1
food :name => :baked_potato, :id => 6701, :restoration => 4
food :name => :sweetcorn, :id => 5988, :restoration => 10
food :name => :sweetcorn_bowl, :id => 7088, :restoration => 13
food :name => :potato_with_butter, :id => 6703, :restoration => 14
food :name => :chili_potato, :id => 7054, :restoration => 14
food :name => :potato_with_cheese, :id => 6705, :restoration => 16
food :name => :egg_potato, :id => 7056, :restoration => 16
food :name => :mushroom_potato, :id => 7058, :restoration => 20
food :name => :tuna_potato, :id => 7060, :restoration => 22
# Dairy # Gnome Food
food :name => :cheese, :id => 1985, :restoration => 2 food name: :toads_legs, id: 2152, restoration: 3
food :name => :pot_of_cream, :id => 2130, :restoration => 1
# Gnome Food # Gnome Bowls
food :name => :toads_legs, :id => 2152, :restoration => 3 food name: :worm_hole, id: 2191, restoration: 12
food name: :worm_hole, id: 2233, restoration: 12
food name: :vegetable_ball, id: 2195, restoration: 12
food name: :vegetable_ball, id: 2235, restoration: 12
food name: :tangled_toads_legs, id: 2187, restoration: 15
food name: :tangled_toads_legs, id: 2231, restoration: 15
food name: :chocolate_bomb, id: 2185, restoration: 15
food name: :chocolate_bomb, id: 2229, restoration: 15
# Gnome Bowls # Gnome Crunchies
food :name => :worm_hole, :id => 2191, :restoration => 12 food name: :toad_crunchies, id: 2217, restoration: 7
food :name => :worm_hole, :id => 2233, :restoration => 12 food name: :toad_crunchies, id: 2243, restoration: 7
food :name => :vegetable_ball, :id => 2195, :restoration => 12 food name: :spicy_crunchies, id: 2213, restoration: 7
food :name => :vegetable_ball, :id => 2235, :restoration => 12 food name: :spicy_crunchies, id: 2241, restoration: 7
food :name => :tangled_toads_legs, :id => 2187, :restoration => 15 food name: :worm_crunchies, id: 2205, restoration: 8
food :name => :tangled_toads_legs, :id => 2231, :restoration => 15 food name: :worm_crunchies, id: 2237, restoration: 8
food :name => :chocolate_bomb, :id => 2185, :restoration => 15 food name: :chocchip_crunchies, id: 2209, restoration: 7
food :name => :chocolate_bomb, :id => 2229, :restoration => 15 food name: :chocchip_crunchies, id: 2239, restoration: 7
# Gnome Crunchies
food :name => :toad_crunchies, :id => 2217, :restoration => 7
food :name => :toad_crunchies, :id => 2243, :restoration => 7
food :name => :spicy_crunchies, :id => 2213, :restoration => 7
food :name => :spicy_crunchies, :id => 2241, :restoration => 7
food :name => :worm_crunchies, :id => 2205, :restoration => 8
food :name => :worm_crunchies, :id => 2237, :restoration => 8
food :name => :chocchip_crunchies, :id => 2209, :restoration => 7
food :name => :chocchip_crunchies, :id => 2239, :restoration => 7
# Gnome Battas
food :name => :fruit_batta, :id => 2225, :restoration => 11
food :name => :fruit_batta, :id => 2277, :restoration => 11
food :name => :toad_batta, :id => 2221, :restoration => 11
food :name => :toad_batta, :id => 2255, :restoration => 11
food :name => :worm_batta, :id => 2219, :restoration => 11
food :name => :worm_batta, :id => 2253, :restoration => 11
food :name => :vegetable_batta, :id => 2227, :restoration => 11
food :name => :vegetable_batta, :id => 2281, :restoration => 11
food :name => :cheese_tom_batta, :id => 2223, :restoration => 11
food :name => :cheese_tom_batta, :id => 2259, :restoration => 11
# Gnome Cocktails
# Make new drink.rb file for drinks? That way it's seperated from food and says You drink, instead of you eat :{name}.
food :name => :fruit_blast, :id => 2034, :restoration => 9
food :name => :fruit_blast, :id => 2084, :restoration => 9
food :name => :pineapple_punch, :id => 2036, :restoration => 9
food :name => :pineapple_punch, :id => 2048, :restoration => 9
food :name => :wizard_blizzard, :id => 2040, :restoration => 5 # -4attack,+5strength also
food :name => :wizard_blizzard, :id => 2054, :restoration => 5 # -4attack,+5strength also
food :name => :short_green_guy, :id => 2038, :restoration => 5 # -4attack,+5strength also
food :name => :short_green_guy, :id => 2080, :restoration => 5 # -4attack,+5strength also
food :name => :drunk_dragon, :id => 2032, :restoration => 5 # -4attack,+6strength also
food :name => :drunk_dragon, :id => 2092, :restoration => 5 # -4attack,+6strength also
food :name => :chocolate_saturday, :id => 2030, :restoration => 7 # -4attack,+6strength also
food :name => :chocolate_saturday, :id => 2074, :restoration => 7 # -4attack,+6strength also
food :name => :blurberry_special, :id => 2028, :restoration => 7 # -4attack,+6strength also
food :name => :blurberry_special, :id => 2064, :restoration => 7 # -4attack,+6strength also
# Misc
# Gnome Battas
food name: :fruit_batta, id: 2225, restoration: 11
food name: :fruit_batta, id: 2277, restoration: 11
food name: :toad_batta, id: 2221, restoration: 11
food name: :toad_batta, id: 2255, restoration: 11
food name: :worm_batta, id: 2219, restoration: 11
food name: :worm_batta, id: 2253, restoration: 11
food name: :vegetable_batta, id: 2227, restoration: 11
food name: :vegetable_batta, id: 2281, restoration: 11
food name: :cheese_tom_batta, id: 2223, restoration: 11
food name: :cheese_tom_batta, id: 2259, restoration: 11
# Gnome Cocktails
# TODO: seperate from food, should say 'You drink' instead of 'You eat'.
food name: :fruit_blast, id: 2034, restoration: 9
food name: :fruit_blast, id: 2084, restoration: 9
food name: :pineapple_punch, id: 2036, restoration: 9
food name: :pineapple_punch, id: 2048, restoration: 9
food name: :wizard_blizzard, id: 2040, restoration: 5 # -4 attack, +5 strength also
food name: :wizard_blizzard, id: 2054, restoration: 5 # -4 attack, +5 strength also
food name: :short_green_guy, id: 2038, restoration: 5 # -4 attack, +5 strength also
food name: :short_green_guy, id: 2080, restoration: 5 # -4 attack, +5 strength also
food name: :drunk_dragon, id: 2032, restoration: 5 # -4 attack, +6 strength also
food name: :drunk_dragon, id: 2092, restoration: 5 # -4 attack, +6 strength also
food name: :chocolate_saturday, id: 2030, restoration: 7 # -4 attack, +6 strength also
food name: :chocolate_saturday, id: 2074, restoration: 7 # -4 attack, +6 strength also
food name: :blurberry_special, id: 2028, restoration: 7 # -4 attack, +6 strength also
food name: :blurberry_special, id: 2064, restoration: 7 # -4 attack, +6 strength also
+48 -32
View File
@@ -4,9 +4,10 @@ java_import 'org.apollo.game.model.entity.Skill'
private private
# Contains potion-related constants.
module Constants module Constants
# The sound made when drinking a potion. # The id of the sound made when drinking a potion.
DRINK_POTION_SOUND = 334 DRINK_POTION_SOUND = 334
# The id of an empty vial. # The id of an empty vial.
@@ -25,10 +26,12 @@ class Potion < Consumable
def consume(player) def consume(player)
index = @doses.find_index(id) + 1 index = @doses.find_index(id) + 1
unless index == @doses.length # Consumable removes the previous potion for us, so we don't do it here. if index != @doses.length # Consumable removes the old potion for us, so don't do it here.
player.inventory.add(@doses[index]) player.inventory.add(@doses[index])
player.send_message("You drink some of your #{name} potion.", true) player.send_message("You drink some of your #{name} potion.", true)
player.send_message("You have #{ @doses.length - index } dose#{ "s" unless index == 3 } of potion left.", true)
remaining = "You have #{@doses.length - index} dose#{'s' unless index == 3} of potion left."
player.send_message(remaining, true)
else else
player.send_message('You drink the last of your potion.', true) player.send_message('You drink the last of your potion.', true)
player.inventory.add(Constants::EMPTY_VIAL_ID) player.inventory.add(Constants::EMPTY_VIAL_ID)
@@ -37,7 +40,7 @@ class Potion < Consumable
drink(player) drink(player)
end end
def drink(player) def drink(_player)
# Override to provide functionality # Override to provide functionality
end end
@@ -48,7 +51,7 @@ class BoostingPotion < Potion
def initialize(id, name, doses, skills, boost) def initialize(id, name, doses, skills, boost)
super(id, name, doses) super(id, name, doses)
@skill_ids = skills.kind_of?(Array) ? skills : [ skills ] @skill_ids = skills.is_a?(Array) ? skills : [skills]
@boost = boost @boost = boost
end end
@@ -56,7 +59,7 @@ class BoostingPotion < Potion
@skill_ids.each do |id| @skill_ids.each do |id|
skill = player.skill_set.skill(id) skill = player.skill_set.skill(id)
max = skill.maximum_level max = skill.maximum_level
level = [ skill.current_level, max ].min level = [skill.current_level, max].min
new_current = @boost.call(max, level).floor new_current = @boost.call(max, level).floor
player.skill_set.set_skill(id, Skill.new(skill.experience, new_current, max)) player.skill_set.set_skill(id, Skill.new(skill.experience, new_current, max))
@@ -65,17 +68,18 @@ class BoostingPotion < Potion
end end
# Returns the parameters for the potion, as an array. Raises if any of the specified keys do not exist # Returns the parameters for the potion, as an array. Fails if any of the specified keys do not
# exist.
def get_parameters(hash, keys) def get_parameters(hash, keys)
raise "Hash must contain the following keys: #{ keys.join(", ") }." unless hash.has_keys?(*keys) fail "Hash must contain the following keys: #{keys.join(', ')}." unless hash.has_keys?(*keys)
return keys.map {|key| hash[key] } keys.map { |key| hash[key] }
end end
# Appends a potion to the list of consumables. # Appends a potion to the list of consumables.
def append_potion(hash) def potion(hash)
class_name = 'Potion' class_name = 'Potion'
keys = [ :name, :doses ] keys = [:name, :doses]
unless (hash.size == 2) unless (hash.size == 2)
keys << :skills << :boost keys << :skills << :boost
@@ -83,36 +87,48 @@ def append_potion(hash)
end end
parameters = get_parameters(hash, keys) parameters = get_parameters(hash, keys)
doses = hash[:doses]
hash[:doses].each { |dose| append_consumable(Object.const_get(class_name).new(dose, *parameters)) } doses.each { |dose| append_consumable(Object.const_get(class_name).new(dose, *parameters)) }
end end
# Some frequently-used boosts and skills # Some frequently-used boosts and skills
# Lambda parameters are | maximum_skill_level, current_skill_level | # Lambda parameters are | maximum_skill_level, current_skill_level |
basic_combat_boost = lambda { |max, level| level * 1.10 + 3 } basic_combat_boost = ->(_, level) { level * 1.10 + 3 }
super_combat_boost = lambda { |max, level| level * 1.15 + 5 } super_combat_boost = ->(_, level) { level * 1.15 + 5 }
non_combat_boost = lambda { |max, level| level + 3 } non_combat_boost = ->(_, level) { level + 3 }
ATTACK, STRENGTH, DEFENCE = Skill::ATTACK, Skill::STRENGTH, Skill::DEFENCE
MAGIC, RANGED, PRAYER = Skill::MAGIC, Skill::RANGED, Skill::PRAYER
all_skills = (Skill::ATTACK..Skill::RUNECRAFT).to_a all_skills = (Skill::ATTACK..Skill::RUNECRAFT).to_a
combat_skills = [ Skill::ATTACK, Skill::STRENGTH, Skill::DEFENCE, Skill::MAGIC, Skill::RANGED ] combat_skills = [ATTACK, STRENGTH, DEFENCE, MAGIC, RANGED]
# Boosting potions: # Boosting potions:
# Note that the order of the elements must be: :name, :doses, :skills, :boost. # Note that the order of the elements must be: :name, :doses, :skills, :boost.
append_potion :name => :attack, :doses => [ 2428, 121, 123, 125 ], :skills => Skill::ATTACK, :boost => basic_combat_boost potion name: :attack, doses: [2428, 121, 123, 125], skills: ATTACK, boost: basic_combat_boost
append_potion :name => :strength, :doses => [ 113, 115, 117, 119 ], :skills => Skill::STRENGTH, :boost => basic_combat_boost potion name: :strength, doses: [113, 115, 117, 119], skills: STRENGTH, boost: basic_combat_boost
append_potion :name => :defence, :doses => [ 2432, 133, 135, 137 ], :skills => Skill::DEFENCE, :boost => basic_combat_boost potion name: :defence, doses: [2432, 133, 135, 137], skills: DEFENCE, boost: basic_combat_boost
append_potion :name => :agility, :doses => [ 3032, 3034, 3036, 3038 ], :skills => Skill::AGILITY, :boost => non_combat_boost potion name: :agility, doses: [3032, 3034, 3036, 3038], skills: Skill::AGILITY,
append_potion :name => :fishing, :doses => [ 2438, 151, 153, 155 ], :skills => Skill::FISHING, :boost => non_combat_boost boost: non_combat_boost
append_potion :name => :prayer, :doses => [ 2434, 139, 141, 143 ], :skills => Skill::PRAYER, :boost => lambda { |max, level| level / 4 + 7 } potion name: :fishing, doses: [2438, 151, 153, 155], skills: Skill::FISHING,
boost: non_combat_boost
potion name: :prayer, doses: [2434, 139, 141, 143], skills: Skill::PRAYER,
boost: ->(_, level) { level / 4 + 7 }
append_potion :name => :restore, :doses => [ 2430, 127, 129, 131 ], :skills => combat_skills, :boost => lambda { |max, level| [ level * 1.3 + 10, max ].min } potion name: :restore, doses: [2430, 127, 129, 131], skills: combat_skills,
append_potion :name => :super_restore, :doses => [ 3024, 3026, 3028, 3030 ], :skills => all_skills, :boost => lambda { |max, level| [ level * 1.25 + 8, max ].min } boost: ->(_, level) { [level * 1.3 + 10, max].min }
potion name: :super_restore, doses: [3024, 3026, 3028, 3030], skills: all_skills,
boost: ->(_, level) { [level * 1.25 + 8, max].min }
append_potion :name => :super_attack, :doses => [ 2436, 145, 147, 149 ], :skills => Skill::ATTACK, :boost => super_combat_boost potion name: :super_attack, doses: [2436, 145, 147, 149], skills: ATTACK, boost: super_combat_boost
append_potion :name => :super_strength, :doses => [ 2440, 157, 159, 161 ], :skills => Skill::STRENGTH, :boost => super_combat_boost potion name: :super_strength, doses: [2440, 157, 159, 161], skills: STRENGTH,
append_potion :name => :super_defence, :doses => [ 2442, 163, 165, 167 ], :skills => Skill::DEFENCE, :boost => super_combat_boost boost: super_combat_boost
append_potion :name => :ranging, :doses => [ 2444, 169, 171, 173 ], :skills => Skill::RANGED, :boost => lambda { |max, level| level * 1.10 + 4 } potion name: :super_defence, doses: [2442, 163, 165, 167], skills: DEFENCE,
append_potion :name => :magic, :doses => [ 3040, 3042, 3044, 3046 ], :skills => Skill::MAGIC, :boost => lambda { |max, level| level + 4 } boost: super_combat_boost
potion name: :ranging, doses: [2444, 169, 171, 173], skills: RANGED,
boost: ->(_, level) { level * 1.10 + 4 }
potion name: :magic, doses: [3040, 3042, 3044, 3046], skills: MAGIC,
boost: ->(_, level) { level + 4 }
+9 -8
View File
@@ -10,6 +10,7 @@ ANIMATION_PULSES = 0
LEVEL_THRESHOLD = 8 LEVEL_THRESHOLD = 8
EXP_PER_HIT = 5 EXP_PER_HIT = 5
# A DistancedAction for attacking a training dummy.
class DummyAction < DistancedAction class DummyAction < DistancedAction
attr_reader :position attr_reader :position
@@ -21,13 +22,7 @@ class DummyAction < DistancedAction
end end
def executeAction def executeAction
unless @started if @started
@started = true
mob.send_message('You hit the dummy.', true)
mob.turn_to(position)
mob.play_animation(PUNCH_ANIMATION)
else
skills = mob.skill_set skills = mob.skill_set
if (skills.skill(ATTACK_SKILL_ID).maximum_level >= LEVEL_THRESHOLD) if (skills.skill(ATTACK_SKILL_ID).maximum_level >= LEVEL_THRESHOLD)
@@ -37,11 +32,17 @@ class DummyAction < DistancedAction
end end
stop stop
else
@started = true
mob.send_message('You hit the dummy.', true)
mob.turn_to(position)
mob.play_animation(PUNCH_ANIMATION)
end end
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @position == other.position) get_class == other.get_class && @position == other.position
end end
end end
-21
View File
@@ -1,21 +0,0 @@
require 'java'
java_import 'org.apollo.game.model.Animation'
ANIMATIONS = {
162 => Animation::THINKING, 6503 => Animation::CLIMB_ROPE, 169 => Animation::NO, 164 => Animation::BOW, 13384 => Animation::GOBLIN_DANCE,
161 => Animation::CRY, 170 => Animation::LAUGH, 171 => Animation::CHEER, 163 => Animation::WAVE, 167 => Animation::BECKON,
3362 => Animation::PANIC, 172 => Animation::CLAP, 166 => Animation::DANCE, 13363 => Animation::JIG, 13364 => Animation::SPIN,
13365 => Animation::HEAD_BANG, 6506 => Animation::LEAN, 165 => Animation::ANGRY, 13368 => Animation::YAWN, 13366 => Animation::JOY_JUMP,
667 => Animation::GLASS_BOX, 13367 => Animation::RASPBERRY, 13369 => Animation::SALUTE, 13370 => Animation::SHRUG, 11100 => Animation::BLOW_KISS,
666 => Animation::GLASS_WALL, 168 => Animation::YES, 13383 => Animation::GOBLIN_BOW
}
# Intercept the button message.
on :message, :button do |player, message|
anim = ANIMATIONS[message.widget_id]
unless anim == nil
player.play_animation(anim)
message.terminate
end
end
+26
View File
@@ -0,0 +1,26 @@
require 'java'
java_import 'org.apollo.game.model.Animation'
ANIMATIONS = {
162 => Animation::THINKING, 6_503 => Animation::CLIMB_ROPE, 169 => Animation::NO,
164 => Animation::BOW, 13_384 => Animation::GOBLIN_DANCE, 161 => Animation::CRY,
170 => Animation::LAUGH, 171 => Animation::CHEER, 163 => Animation::WAVE,
167 => Animation::BECKON, 3_362 => Animation::PANIC, 172 => Animation::CLAP,
166 => Animation::DANCE, 13_363 => Animation::JIG, 13_364 => Animation::SPIN,
13_365 => Animation::HEAD_BANG, 6_506 => Animation::LEAN, 165 => Animation::ANGRY,
13_368 => Animation::YAWN, 13_366 => Animation::JOY_JUMP, 667 => Animation::GLASS_BOX,
13_367 => Animation::RASPBERRY, 13_369 => Animation::SALUTE, 13_370 => Animation::SHRUG,
11_100 => Animation::BLOW_KISS, 666 => Animation::GLASS_WALL, 168 => Animation::YES,
13_383 => Animation::GOBLIN_BOW
}
# Intercept the button message.
on :message, :button do |player, message|
anim = ANIMATIONS[message.widget_id]
unless anim.nil?
player.play_animation(anim)
message.terminate
end
end
+1 -1
View File
@@ -8,7 +8,7 @@
<author>Major</author> <author>Major</author>
</authors> </authors>
<scripts> <scripts>
<script>emote-tab.rb</script> <script>emote_tab.rb</script>
</scripts> </scripts>
<dependencies /> <dependencies />
</plugin> </plugin>
+17 -14
View File
@@ -12,13 +12,15 @@ java_import 'org.apollo.game.model.entity.attr.BooleanAttribute'
java_import 'org.apollo.game.model.entity.attr.NumericalAttribute' java_import 'org.apollo.game.model.entity.attr.NumericalAttribute'
java_import 'org.apollo.game.model.entity.attr.StringAttribute' java_import 'org.apollo.game.model.entity.attr.StringAttribute'
# Declares an attribute and adds its definition. # Declares an attribute and adds its definition.
def declare_attribute(name, default, persistence=:transient) def declare_attribute(name, default, persistence = :transient)
raise "Attribute #{name} clashes with an existing variable." if (Player.method_defined?(name) || Mob.method_defined?(name) || Npc.method_defined?(name)) if Player.method_defined?(name) || Mob.method_defined?(name) || Npc.method_defined?(name)
AttributeMap::define(name.to_s, AttributeDefinition.new(default, get_persistence(persistence), get_type(default))) fail "Attribute #{name} clashes with an existing variable."
end end
definition = AttributeDefinition.new(default, get_persistence(persistence), get_type(default))
AttributeMap::define(name.to_s, definition)
end
private private
@@ -29,8 +31,8 @@ class Mob
def method_missing(symbol, *args) def method_missing(symbol, *args)
name = symbol.to_s.strip name = symbol.to_s.strip
if name[-1] == "=" if name[-1] == '='
raise "Expected argument count of 1, received #{args.length}" unless args.length == 1 fail "Expected argument count of 1, received #{args.length}" unless args.length == 1
name = name[0...-1].strip # Drop the equals and trim whitespace. name = name[0...-1].strip # Drop the equals and trim whitespace.
set_attribute(name, to_attribute(args[0])) set_attribute(name, to_attribute(args[0]))
@@ -39,20 +41,19 @@ class Mob
else else
attribute = get_attribute(name) attribute = get_attribute(name)
value = attribute.value value = attribute.value
return (attribute.type == AttributeType::SYMBOL) ? value.to_sym : value (attribute.type == AttributeType::SYMBOL) ? value.to_sym : value
end end
end end
end end
# Gets the appropriate attribute for the specified value.
# Gets the appropriate attribute for the specified value.
def to_attribute(value) def to_attribute(value)
case value case value
when String, Symbol then return StringAttribute.new(value.to_s, value.is_a?(Symbol)) when String, Symbol then return StringAttribute.new(value.to_s, value.is_a?(Symbol))
when Integer, Float then return NumericalAttribute.new(value) when Integer, Float then return NumericalAttribute.new(value)
when TrueClass, FalseClass then return BooleanAttribute.new(value) when TrueClass, FalseClass then return BooleanAttribute.new(value)
else raise "Undefined attribute type #{value.class}." else fail "Undefined attribute type #{value.class}."
end end
end end
@@ -64,13 +65,15 @@ def get_type(value)
when Integer then return AttributeType::LONG when Integer then return AttributeType::LONG
when Float then return AttributeType::DOUBLE when Float then return AttributeType::DOUBLE
when TrueClass, FalseClass then return AttributeType::BOOLEAN when TrueClass, FalseClass then return AttributeType::BOOLEAN
else raise "Undefined attribute type #{value.class}." else fail "Undefined attribute type #{value.class}."
end end
end end
# Gets the Persistence type of the specified value. # Gets the Persistence type of the specified value.
def get_persistence(persistence) def get_persistence(persistence)
raise "Undefined persistence type #{persistence}." unless [ :persistent, :transient ].include?(persistence) unless [:persistent, :transient].include?(persistence)
fail "Undefined persistence type #{persistence}."
end
return (persistence == :persistent) ? AttributePersistence::PERSISTENT : AttributePersistence::TRANSIENT (persistence == :persistent) ? AttributePersistence::PERSISTENT : AttributePersistence::TRANSIENT
end end
+36 -26
View File
@@ -10,22 +10,29 @@ java_import 'org.apollo.game.model.entity.Npc'
# Information about npc spawning # Information about npc spawning
# #
# Npcs are passed to spawn npc as a hash. Every key and every non-integer value must be a Symbol. Every hash must implement the following: # Npcs are passed to spawn npc as a hash. Every key and every non-integer value must be a Symbol.
# :name - the name of the npc. If this npc shares its name with another, append the specific id after the name (e.g. :woman_4) # Every hash must implement the following:
# :name - the name of the npc. If this npc shares its name with another, append the specific id
# after the name (e.g. :woman_4)
# :x - the x coordinate where the npc will spawn. # :x - the x coordinate where the npc will spawn.
# :y - the y coordinate where the npc will spawn. # :y - the y coordinate where the npc will spawn.
# Optional arguments are as follows: # Optional arguments are as follows:
# :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west # :face - the direction the npc should face when it spawns. Supported options are :north,
# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate] # :north_east, :east, :south_east, :south, :south_west, :west, and :north_west
# :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds. # :bounds - the rectangular bound that the npc can wander about in. Order is
# [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate,
# top-right y-coordinate]
# :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from
# the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds.
# :spawn_animation - the animation that will be played when the npc spawns. # :spawn_animation - the animation that will be played when the npc spawns.
# :spawn_graphic - the graphic that will be played when the npc spawns. # :spawn_graphic - the graphic that will be played when the npc spawns.
# Spawns an npc with the properties specified in the hash. # Spawns an npc with the properties specified in the hash.
def spawn_npc(hash) def spawn_npc(hash)
raise 'A name (or id), x coordinate, and y coordinate must be specified to spawn an npc.' unless (hash.has_key?(:name) || hash.has_key?(:id)) && hash.has_keys?(:x, :y) unless (hash.key?(:name) || hash.key?(:id)) && hash.has_keys?(:x, :y)
fail 'A name (or id), x coordinate, and y coordinate must be specified to spawn an npc.'
end
npc = get_npc(hash) npc = get_npc(hash)
spawn(npc, hash) spawn(npc, hash)
npc npc
@@ -46,8 +53,8 @@ def get_npc(hash)
id = lookup_npc(hash.delete(:name)) id = lookup_npc(hash.delete(:name))
z = hash.delete(:z) z = hash.delete(:z)
position = Position.new(hash.delete(:x), hash.delete(:y), z == nil ? 0 : z) position = Position.new(hash.delete(:x), hash.delete(:y), z.nil? ? 0 : z)
return Npc.new($world, id, position) Npc.new($world, id, position)
end end
# Applies a decoded hash (one aquired using parse_hash) to the specified npc. # Applies a decoded hash (one aquired using parse_hash) to the specified npc.
@@ -58,7 +65,7 @@ def apply_decoded_hash(npc, hash)
when :boundary then npc.boundaries = value when :boundary then npc.boundaries = value
when :spawn_animation then npc.play_animation(Animation.new(value)) when :spawn_animation then npc.play_animation(Animation.new(value))
when :spawn_graphic then npc.play_graphic(Graphic.new(value)) when :spawn_graphic then npc.play_graphic(Graphic.new(value))
else raise "Unrecognised key #{key} - value #{value}." else fail "Unrecognised key #{key} - value #{value}."
end end
end end
end end
@@ -72,27 +79,27 @@ def decode_hash(position, hash)
when :face when :face
decoded[:face] = direction_to_position(value, position) decoded[:face] = direction_to_position(value, position)
when :delta_bounds when :delta_bounds
raise ':delta_bounds must have two values.' unless value.length == 2 fail ':delta_bounds must have two values.' unless value.length == 2
dx, dy, x, y, z = value[0], value[1], position.x, position.y, position.height dx, dy, x, y, z = value[0], value[1], position.x, position.y, position.height
raise 'Delta values cannot be less than 0.' if (dx < 0 || dy < 0) fail 'Delta values cannot be less than 0.' if dx < 0 || dy < 0
decoded[:boundary] = [ Position.new(x - dx, y - dy, z), Position.new(x + dx, y + dy, z) ] decoded[:boundary] = [Position.new(x - dx, y - dy, z), Position.new(x + dx, y + dy, z)]
when :bounds when :bounds
raise ':bounds must have four values.' unless value.length == 4 fail ':bounds must have four values.' unless value.length == 4
min_x, min_y, max_x, max_y = value[0], value[1], value[2], value[3] min_x, min_y, max_x, max_y = value[0], value[1], value[2], value[3]
decoded[:boundary] = [ Position.new(min_x, min_y), Position.new(max_x, max_y) ] decoded[:boundary] = [Position.new(min_x, min_y), Position.new(max_x, max_y)]
when :spawn_animation then decoded[:spawn_animation] = Animation.new(value) when :spawn_animation then decoded[:spawn_animation] = Animation.new(value)
when :spawn_graphic then decoded[:spawn_graphic ] = Graphic.new(value) when :spawn_graphic then decoded[:spawn_graphic] = Graphic.new(value)
else raise "Unrecognised key #{key} - value #{value}." else fail "Unrecognised key #{key} - value #{value}."
end end
end end
return decoded decoded
end end
# Returns a position that an entity at the specified position should be facing towards if they are
# Returns a position that an entity at the specified position should be facing towards if they are looking in the specified direction. # looking in the specified direction.
def direction_to_position(direction, position) def direction_to_position(direction, position)
x, y, z = position.x, position.y, position.height x, y, z = position.x, position.y, position.height
@@ -121,13 +128,14 @@ class TemporaryNpcAction < Action
end end
def execute def execute
if executions == 0 if @executions == 0
spawn(mob, @hash) spawn(mob, @hash)
execute_spawn_action execute_spawn_action
else else
execute_action execute_action
end end
executions += 1
@executions += 1
end end
def execute_action def execute_action
@@ -168,17 +176,19 @@ RANDOM_EVENTS = []
# Spawns a random event for the specified player. # Spawns a random event for the specified player.
def send_random_event(player) def send_random_event(player)
position = player.position position = player.position
npc_position = Position.new(position.x + 1, position.y, position.height) # TODO Find an unoccupied tile instead of the assumption that (x + 1) is traversable!! npc_position = Position.new(position.x + 1, position.y, position.height)
# TODO: Find an unoccupied tile instead of the assumption that (x + 1) is traversable!!
spawn_random_event(npc_position, false) spawn_random_event(npc_position, false)
end end
# Spawns a random event in the specified position. # Spawns a random event in the specified position.
# If 'combat' is false, only non-combat events will be spawned. # If 'combat' is false, only non-combat events will be spawned.
def spawn_random_event(position, combat) def spawn_random_event(_position, _combat)
event = RANDOM_EVENTS[rand(RANDOM_EVENTS.size)] event = RANDOM_EVENTS[rand(RANDOM_EVENTS.size)]
attempts = 0 attempts = 0
while (event.combative && attempts < 5)
while event.combative && attempts < 5
event = RANDOM_EVENTS[rand(RANDOM_EVENTS.size)] event = RANDOM_EVENTS[rand(RANDOM_EVENTS.size)]
attempts += 1 attempts += 1
end end
+39 -50
View File
@@ -1,66 +1,55 @@
# Information about npc spawning
#
# Npcs are passed to spawn npc as a hash. Every key and every non-integer value must be a Symbol. Every hash must implement the following:
# :name - the name of the npc. If this npc shares its name with another, append the specific id after the name (e.g. :woman_4)
# :x - the x coordinate where the npc will spawn.
# :y - the y coordinate where the npc will spawn.
# Optional arguments are as follows:
# :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west
# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate]
# :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds.
# :spawn_animation - the animation that will be played when the npc spawns.
# :spawn_graphic - the graphic that will be played when the npc spawns.
# Generic npcs # Generic npcs
spawn_npc :name => :man, :x => 3276, :y => 3186 spawn_npc name: :man, x: 3276, y: 3186
# Palace guards # Palace guards
spawn_npc :name => "Al-Kharid warrior", :x => 3283, :y => 3161 # String must be used here because the actual npc name is 'Al-Kharid warrior', and symbols don't support hyphens. spawn_npc name: 'Al-Kharid warrior', x: 3283, y: 3161
spawn_npc :name => "Al-Kharid warrior", :x => 3285, :y => 3174 spawn_npc name: 'Al-Kharid warrior', x: 3285, y: 3174
spawn_npc :name => "Al-Kharid warrior", :x => 3286, :y => 3164 spawn_npc name: 'Al-Kharid warrior', x: 3286, y: 3164
spawn_npc :name => "Al-Kharid warrior", :x => 3287, :y => 3168 spawn_npc name: 'Al-Kharid warrior', x: 3287, y: 3168
spawn_npc :name => "Al-Kharid warrior", :x => 3288, :y => 3169 spawn_npc name: 'Al-Kharid warrior', x: 3288, y: 3169
spawn_npc :name => "Al-Kharid warrior", :x => 3290, :y => 3162 spawn_npc name: 'Al-Kharid warrior', x: 3290, y: 3162
spawn_npc :name => "Al-Kharid warrior", :x => 3295, :y => 3162 spawn_npc name: 'Al-Kharid warrior', x: 3295, y: 3162
spawn_npc :name => "Al-Kharid warrior", :x => 3295, :y => 3170 spawn_npc name: 'Al-Kharid warrior', x: 3295, y: 3170
spawn_npc :name => "Al-Kharid warrior", :x => 3297, :y => 3175 spawn_npc name: 'Al-Kharid warrior', x: 3297, y: 3175
spawn_npc :name => "Al-Kharid warrior", :x => 3300, :y => 3171 spawn_npc name: 'Al-Kharid warrior', x: 3300, y: 3171
spawn_npc :name => "Al-Kharid warrior", :x => 3301, :y => 3164 spawn_npc name: 'Al-Kharid warrior', x: 3301, y: 3164
spawn_npc :name => "Al-Kharid warrior", :x => 3301, :y => 3168 spawn_npc name: 'Al-Kharid warrior', x: 3301, y: 3168
spawn_npc :name => :shantay_guard_838, :x => 3301, :y => 3120 spawn_npc name: :shantay_guard_838, x: 3301, y: 3120
spawn_npc :name => :shantay_guard, :x => 3304, :y => 3119 spawn_npc name: :shantay_guard, x: 3304, y: 3119
spawn_npc :name => :shantay_guard_838, :x => 3307, :y => 3122 spawn_npc name: :shantay_guard_838, x: 3307, y: 3122
# Mine # Mine
spawn_npc :name => :scorpion, :x => 3296, :y => 3294 spawn_npc name: :scorpion, x: 3296, y: 3294
spawn_npc :name => :scorpion, :x => 3298, :y => 3280 spawn_npc name: :scorpion, x: 3298, y: 3280
spawn_npc :name => :scorpion, :x => 3299, :y => 3299 spawn_npc name: :scorpion, x: 3299, y: 3299
spawn_npc :name => :scorpion, :x => 3299, :y => 3309 spawn_npc name: :scorpion, x: 3299, y: 3309
spawn_npc :name => :scorpion, :x => 3300, :y => 3287 spawn_npc name: :scorpion, x: 3300, y: 3287
spawn_npc :name => :scorpion, :x => 3301, :y => 3305 spawn_npc name: :scorpion, x: 3301, y: 3305
# Functional npcs # Functional npcs
spawn_npc :name => :gnome_pilot, :x => 3279, :y => 3213 spawn_npc name: :gnome_pilot, x: 3279, y: 3213
spawn_npc :name => :banker_496, :x => 3267, :y => 3164, :face => :east # TODO are these the correct banker ids? # TODO: are these the correct banker ids?
spawn_npc :name => :banker_497, :x => 3267, :y => 3166, :face => :east spawn_npc name: :banker_496, x: 3267, y: 3164, face: :east
spawn_npc :name => :banker_496, :x => 3267, :y => 3167, :face => :east spawn_npc name: :banker_497, x: 3267, y: 3166, face: :east
spawn_npc :name => :banker_497, :x => 3267, :y => 3168, :face => :east spawn_npc name: :banker_496, x: 3267, y: 3167, face: :east
spawn_npc :name => :banker_496, :x => 3267, :y => 3169, :face => :east spawn_npc name: :banker_497, x: 3267, y: 3168, face: :east
spawn_npc name: :banker_496, x: 3267, y: 3169, face: :east
spawn_npc :name => :gem_trader, :x => 3287, :y => 3210 spawn_npc name: :gem_trader, x: 3287, y: 3210
spawn_npc :name => :zeke, :x => 3289, :y => 3189 spawn_npc name: :zeke, x: 3289, y: 3189
spawn_npc :name => :shantay, :x => 3304, :y => 3124 spawn_npc name: :shantay, x: 3304, y: 3124
spawn_npc :name => :rug_merchant_2296, :x => 3311, :y => 3109, :face => :west spawn_npc name: :rug_merchant_2296, x: 3311, y: 3109, face: :west
spawn_npc :name => :ranael, :x => 3315, :y => 3163, :face => :north spawn_npc name: :ranael, x: 3315, y: 3163, face: :north
spawn_npc :name => :shop_assistant_525, :x => 3315, :y => 3178, :face => :north # TODO are these the correct shop staff ids?
spawn_npc :name => :shop_keeper_524, :x => 3315, :y => 3180, :face => :west # TODO: are these the correct shop staff ids?
spawn_npc :name => :louie_legs, :x => 3316, :y => 3175, :face => :west spawn_npc name: :shop_assistant_525, x: 3315, y: 3178, face: :north
spawn_npc name: :shop_keeper_524, x: 3315, y: 3180, face: :west
spawn_npc name: :louie_legs, x: 3316, y: 3175, face: :west
+30 -44
View File
@@ -1,53 +1,39 @@
# Information about npc spawning
#
# Npcs are passed to spawn npc as a hash. Every key and every non-integer value must be a Symbol. Every hash must implement the following:
# :name - the name of the npc. If this npc shares its name with another, append the specific id after the name (e.g. :woman_4)
# :x - the x coordinate where the npc will spawn.
# :y - the y coordinate where the npc will spawn.
# Optional arguments are as follows:
# :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west
# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate]
# :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds.
# :spawn_animation - the animation that will be played when the npc spawns.
# :spawn_graphic - the graphic that will be played when the npc spawns.
# Generic npcs # Generic npcs
spawn_npc :name => :man, :x => 3095, :y => 3508 spawn_npc name: :man, x: 3095, y: 3508
spawn_npc :name => :man, :x => 3095, :y => 3511 spawn_npc name: :man, x: 3095, y: 3511
spawn_npc :name => :man, :x => 3098, :y => 3509 spawn_npc name: :man, x: 3098, y: 3509
spawn_npc :name => :guard, :x => 3108, :y => 3514 spawn_npc name: :guard, x: 3108, y: 3514
spawn_npc :name => :guard, :x => 3110, :y => 3514 spawn_npc name: :guard, x: 3110, y: 3514
spawn_npc :name => :guard, :x => 3113, :y => 3514 spawn_npc name: :guard, x: 3113, y: 3514
spawn_npc :name => :guard, :x => 3113, :y => 3516 spawn_npc name: :guard, x: 3113, y: 3516
spawn_npc :name => :sheep_43, :x => 3053, :y => 3514 spawn_npc name: :sheep_43, x: 3053, y: 3514
spawn_npc :name => :sheep_43, :x => 3053, :y => 3517 spawn_npc name: :sheep_43, x: 3053, y: 3517
spawn_npc :name => :sheep_43, :x => 3053, :y => 3518 spawn_npc name: :sheep_43, x: 3053, y: 3518
spawn_npc :name => :sheep_43, :x => 3056, :y => 3517 spawn_npc name: :sheep_43, x: 3056, y: 3517
spawn_npc :name => :mugger, :x => 3076, :y => 3504 spawn_npc name: :mugger, x: 3076, y: 3504
spawn_npc :name => :monk, :x => 3044, :y => 3491
spawn_npc :name => :monk, :x => 3045, :y => 3483
spawn_npc :name => :monk, :x => 3045, :y => 3497
spawn_npc :name => :monk, :x => 3050, :y => 3490
spawn_npc :name => :monk, :x => 3054, :y => 3490
spawn_npc :name => :monk, :x => 3058, :y => 3497
spawn_npc name: :monk, x: 3044, y: 3491
spawn_npc name: :monk, x: 3045, y: 3483
spawn_npc name: :monk, x: 3045, y: 3497
spawn_npc name: :monk, x: 3050, y: 3490
spawn_npc name: :monk, x: 3054, y: 3490
spawn_npc name: :monk, x: 3058, y: 3497
# Functional npcs # Functional npcs
spawn_npc :name => :brother_jered, :x => 3045, :y => 3488 spawn_npc name: :brother_jered, x: 3045, y: 3488
spawn_npc :name => :brother_althric, :x => 3054, :y => 3504 spawn_npc name: :brother_althric, x: 3054, y: 3504
spawn_npc :name => :abbot_langley, :x => 3059, :y => 3484 spawn_npc name: :abbot_langley, x: 3059, y: 3484
spawn_npc :name => :oziach, :x => 3067, :y => 3518, :face => :east spawn_npc name: :oziach, x: 3067, y: 3518, face: :east
spawn_npc :name => :shop_assistant, :x => 3079, :y => 3509 spawn_npc name: :shop_assistant, x: 3079, y: 3509
spawn_npc :name => :shop_keeper, :x => 3082, :y => 3513 spawn_npc name: :shop_keeper, x: 3082, y: 3513
spawn_npc :name => :banker, :x => 3096, :y => 3489, :face => :west # TODO probably not all the same bankers. # TODO: probably not all the same bankers.
spawn_npc :name => :banker, :x => 3096, :y => 3491, :face => :west spawn_npc name: :banker, x: 3096, y: 3489, face: :west
spawn_npc :name => :banker, :x => 3096, :y => 3492, :face => :north spawn_npc name: :banker, x: 3096, y: 3491, face: :west
spawn_npc :name => :banker, :x => 3098, :y => 3492, :face => :north spawn_npc name: :banker, x: 3096, y: 3492, face: :north
spawn_npc :name => :mage_of_zamorak, :x => 3106, :y => 3560 spawn_npc name: :banker, x: 3098, y: 3492, face: :north
spawn_npc name: :mage_of_zamorak, x: 3106, y: 3560
+10 -23
View File
@@ -1,29 +1,16 @@
# Information about npc spawning
#
# Npcs are passed to spawn npc as a hash. Every key and every non-integer value must be a Symbol. Every hash must implement the following:
# :name - the name of the npc. If this npc shares its name with another, append the specific id after the name (e.g. :woman_4)
# :x - the x coordinate where the npc will spawn.
# :y - the y coordinate where the npc will spawn.
# Optional arguments are as follows:
# :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west
# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate]
# :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds.
# :spawn_animation - the animation that will be played when the npc spawns.
# :spawn_graphic - the graphic that will be played when the npc spawns.
# Generic npcs # Generic npcs
spawn_npc :name => :woman_4, :x => 3232, :y => 3207 # southernmost house spawn_npc name: :woman_4, x: 3232, y: 3207 # southernmost house
spawn_npc :name => :man_1, :x => 3231, :y => 3237 # house by willow tree spawn_npc name: :man_1, x: 3231, y: 3237 # house by willow tree
spawn_npc :name => :man_2, :x => 3224, :y => 3240 # house by willow tree spawn_npc name: :man_2, x: 3224, y: 3240 # house by willow tree
spawn_npc :name => :woman_5, :x => 3229, :y => 2329 # house by willow tree spawn_npc name: :woman_5, x: 3229, y: 2329 # house by willow tree
# Functional npcs # Functional npcs
spawn_npc :name => :hans, :x => 3221, :y => 3221 spawn_npc name: :hans, x: 3221, y: 3221
spawn_npc :name => :father_aereck, :x => 3243, :y => 3210 spawn_npc name: :father_aereck, x: 3243, y: 3210
spawn_npc :name => :bob, :x => 3231, :y => 3203 spawn_npc name: :bob, x: 3231, y: 3203
spawn_npc :name => :shop_keeper, :x => 3212, :y => 3247 spawn_npc name: :shop_keeper, x: 3212, y: 3247
spawn_npc :name => :shop_assistant, :x => 3211, :y => 3245 spawn_npc name: :shop_assistant, x: 3211, y: 3245
spawn_npc :name => :lumbridge_guide, :x => 3232, :y => 3229 spawn_npc name: :lumbridge_guide, x: 3232, y: 3229
+32 -28
View File
@@ -3,32 +3,33 @@ require 'java'
java_import 'org.apollo.game.message.impl.HintIconMessage' java_import 'org.apollo.game.message.impl.HintIconMessage'
java_import 'org.apollo.game.message.impl.SwitchTabInterfaceMessage' java_import 'org.apollo.game.message.impl.SwitchTabInterfaceMessage'
private private
# The ids of tabs that are displayed when the player has yet to start the tutorial. # The ids of tabs that are displayed when the player has yet to start the tutorial.
INITIAL_TABS = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2449, 904, -1, -1 ] INITIAL_TABS = [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2449, 904, -1, -1]
# The character design interface id. # The character design interface id.
CHARACTER_DESIGN = 3559 CHARACTER_DESIGN = 3559
# The Runescape guide Npc # The Runescape guide Npc
@runescape_guide = spawn_npc :name => :runescape_guide, :x => 3093, :y => 3107 @runescape_guide = spawn_npc name: :runescape_guide, x: 3093, y: 3107
# Sends the appropriate data to the client when the player logs in to the game. # Sends the appropriate data to the client when the player logs in to the game.
on :login do |event, player| on :login do |_event, player|
if player.in_tutorial_island if player.in_tutorial_island && player.privilege_level != RIGHTS_ADMIN
# TutorialInstructions::show_instruction(player) TutorialInstructions.show_instruction(player)
# INITIAL_TABS.each_with_index { |tab, index| player.send(SwitchTabInterfaceMessage.new(index, tab)) }
if (player.tutorial_island_progress == :not_started) INITIAL_TABS.each_with_index do |tab, index|
player.send(SwitchTabInterfaceMessage.new(index, tab))
end
if player.tutorial_island_progress == :not_started
show_hint_icon(player) show_hint_icon(player)
player.interface_set.open_window(CHARACTER_DESIGN) player.interface_set.open_window(CHARACTER_DESIGN)
end end
end end
end end
# The conversation with the Runescape Guide, when on tutorial island. # The conversation with the Runescape Guide, when on tutorial island.
conversation :tutorial_runescape_guide do conversation :tutorial_runescape_guide do
@@ -39,60 +40,63 @@ conversation :tutorial_runescape_guide do
precondition { |player| player.tutorial_island_progress == :not_started } precondition { |player| player.tutorial_island_progress == :not_started }
text "Greetings! I see you are a new arrival to this land. My job is to welcome all new visitors. So welcome!" text 'Greetings! I see you are a new arrival to this land. My job is to welcome all new '\
'visitors. So welcome!'
continue :dialogue => :talk_to_people do |player| continue dialogue: :talk_to_people do |player|
player.tutorial_island_progress = :talk_to_people player.tutorial_island_progress = :talk_to_people
end end
end end
# The Guide welcomes back the Player if they speak to him after they have already gone through
# The Guide welcomes back the Player if they speak to him after they have already gone through the conversation once. # the conversation once.
dialogue :welcome_back do dialogue :welcome_back do
type :npc_speech type :npc_speech
npc :runescape_guide npc :runescape_guide
precondition { |player| player.tutorial_island_progress != :not_started } precondition { |player| player.tutorial_island_progress != :not_started }
text "Welcome back." text 'Welcome back.'
continue :dialogue => :talk_to_people continue dialogue: :talk_to_people
end end
# The Guide tells Players to speak to people in order to succeed. # The Guide tells Players to speak to people in order to succeed.
dialogue :talk_to_people do dialogue :talk_to_people do
type :npc_speech type :npc_speech
npc :runescape_guide npc :runescape_guide
text "You have already learned the first thing you need to succeed in this world: talking to people!", text 'You have already learned the first thing you need to succeed in this world: talking to '\
"You will find many inhabitants of this world have useful things to say to you. By clicking on them with your mouse you can talk to them.", 'people!',
"I would also suggest reading through some of the supporting information on the website. There you can find maps, a bestiary, and much more." 'You will find many inhabitants of this world have useful things to say to you. By '\
'clicking on them with your mouse you can talk to them.',
'I would also suggest reading through some of the supporting information on the website.'\
' There you can find maps, a bestiary, and much more.'
continue :dialogue => :go_through_door continue dialogue: :go_through_door
end end
# The Guide tells Players to go through the door, advancing the tutorial progress if this is the first time the Player has heard this. # The Guide tells Players to go through the door, advancing the tutorial progress if this is the
# first time the Player has heard this.
dialogue :go_through_door do dialogue :go_through_door do
type :npc_speech type :npc_speech
npc :runescape_guide npc :runescape_guide
text "To continue the tutorial go through that door over there, and speak to your first instructor." text 'To continue the tutorial go through that door over there, and speak to your first '\
'instructor.'
close do |player| close do |player|
if (player.tutorial_island_progress < :runescape_guide_finished) if player.tutorial_island_progress < :runescape_guide_finished
reset_hint_icon(player) reset_hint_icon(player)
# TODO door hint icon # TODO: door hint icon
player.tutorial_island_progress = :runescape_guide_finished player.tutorial_island_progress = :runescape_guide_finished
end end
TutorialInstructions.show_instruction(player) TutorialInstructions.show_instruction(player)
end end
end end
end end
# Enables the hint icon above the Runescape guide. # Enables the hint icon above the Runescape guide.
def show_hint_icon(player) def show_hint_icon(player)
player.send(HintIconMessage.for_npc(@runescape_guide.index)) player.send(HintIconMessage.for_npc(@runescape_guide.index))
@@ -100,5 +104,5 @@ end
# Resets the hint icon. # Resets the hint icon.
def reset_hint_icon(player) def reset_hint_icon(player)
player.send(HintIconMessage.reset_npc()) player.send(HintIconMessage.reset_npc)
end end
@@ -1,5 +1,5 @@
# TODO update the status to :moving_around when the door is opened # TODO: update the status to :moving_around when the door is opened
# Contains members related to the instructions issues during tutorial island. # Contains members related to the instructions issues during tutorial island.
module TutorialInstructions module TutorialInstructions
@@ -18,104 +18,115 @@ module TutorialInstructions
when :given_axe then :viewing_items when :given_axe then :viewing_items
when :cut_tree then :cut_tree when :cut_tree then :cut_tree
when :cutting_tree then :please_wait when :cutting_tree then :please_wait
else raise "No dialogue for current stage #{progress} exists." else fail 'No dialogue for current stage #{progress} exists.'
end end
dialogue = instructions.part(name) dialogue = instructions.part(name)
send_dialogue(player, dialogue) send_dialogue(player, dialogue)
end end
# The one-sided 'conversation' of instruction instructions. # The one-sided 'conversation' of instruction instructions.
conversation :tutorial_island_instructions do conversation :tutorial_island_instructions do
# The initial instruction displayed when the player logs in, before they have spoken to the guide. # The initial instruction displayed when the player logs in, before they have spoken to the
# guide.
dialogue :getting_started do dialogue :getting_started do
type :text type :text
title "Getting started" title 'Getting started'
text "To start the tutorial, use your left mouse button to click on the Runescape Guide in this room. He is indicated by "\ text 'To start the tutorial, use your left mouse button to click on the Runescape Guide in '\
"a flashing yellow arrow above his head. If you can't see him, use your keyboard's arrow keys to rotate the view." 'this room. He is indicated by a flashing yellow arrow above his head. If you can\'t '\
'see him, use your keyboard\'s arrow keys to rotate the view.'
end end
# The instruction displayed after the player has spoken to the Runescape Guide. # The instruction displayed after the player has spoken to the Runescape Guide.
dialogue :scenery do dialogue :scenery do
type :text type :text
title "Interacting with scenery" title 'Interacting with scenery'
text "You can interact with many items of the scenery by simply clicking on them. Right clicking will also give more options. "\ text 'You can interact with many items of the scenery by simply clicking on them. Right '\
"Click on the door indicated with the yellow arrow to go through to the next area and speak with your next instructor." 'clicking will also give more options. Click on the door indicated with the yellow '\
'arrow to go through to the next area and speak with your next instructor.'
end end
## TODO !! When we have door support, the player's tutorial island progress needs to be set to :moving_around when they walk through the door !! # TODO: The player's tutorial island progress needs to be set to :moving_around when they walk
# through the door !!
# The instruction displayed after the player has left the initial building. # The instruction displayed after the player has left the initial building.
dialogue :moving_around do dialogue :moving_around do
type :text type :text
title "Moving around" title 'Moving around'
text "Follow the path to find the next instructor. Clicking on the ground will walk you to that point. Talk to the survival expert "\ text 'Follow the path to find the next instructor. Clicking on the ground will walk you to '\
"by the pond to continue the tutorial. Remember you can rotate the view by pressing the arrow keys." 'that point. Talk to the survival expert by the pond to continue the tutorial. '\
'Remember you can rotate the view by pressing the arrow keys.'
end end
# The instruction displayed after the player has been given the tinderbox and bronze axe by the Survival Guide. # The instruction displayed after the player has been given the tinderbox and bronze axe by the
# Survival Guide.
dialogue :viewing_items do dialogue :viewing_items do
type :text type :text
title "Viewing the items you were given" title 'Viewing the items you were given'
text "Click on the flashing backpack icon to the right side of the main window to view your inventory. Your inventory is a list of "\ text 'Click on the flashing backpack icon to the right side of the main window to view your '\
"everything you have in your backpack." 'inventory. Your inventory is a list of everything you have in your backpack.'
end end
# The instruction displayed before the player has begun to cut the tree. # The instruction displayed before the player has begun to cut the tree.
dialogue :cut_tree do dialogue :cut_tree do
type :text type :text
title "Cut down a tree" title 'Cut down a tree'
text "You can click on the backpack icon at any time to view the items that you currently have in your inventory. You will see that you "\ text 'You can click on the backpack icon at any time to view the items that you currently '\
"now have an axe in your inventory. Use this to get some logs by clicking on the indicated tree." 'have in your inventory. You will see that you now have an axe in your inventory. '\
end 'Use this to get some logs by clicking on the indicated tree.'
end
# The instruction displayed when the player begins to cut the tree. # The instruction displayed when the player begins to cut the tree.
dialogue :please_wait do dialogue :please_wait do
type :text type :text
title "Please wait..." title 'Please wait...'
text "Your character is now attempting to cut down the tree. Sit back for a moment whilst he does all the hard work." # TODO she instead of he if applicable text 'Your character is now attempting to cut down the tree. Sit back for a moment whilst '\
end 'he does all the hard work.' # TODO: she instead of he if applicable
end
# The instruction displayed after the player has successfully cut logs from the tree. # The instruction displayed after the player has successfully cut logs from the tree.
dialogue :make_a_fire do dialogue :make_a_fire do
type :text type :text
title "Making a fire" title 'Making a fire'
text "Well done! You managed to cut some logs from the tree! Next, use the tinderbox in your inventory to light the logs. First click on the "\ text 'Well done! You managed to cut some logs from the tree! Next, use the tinderbox in '\
"tinderbox to 'use' it. Then click on the logs in your inventory to light them." 'your inventory to light the logs. First click on the tinderbox to \'use\' it.'\
end 'Then click on the logs in your inventory to light them.'
end
# The instruction displayed when the player begins to light the fire. # The instruction displayed when the player begins to light the fire.
dialogue :lighting_fire do dialogue :lighting_fire do
type :text type :text
title "Please wait..." title 'Please wait...'
text "Your character is now attempting to light the logs. Sit back for a moment whilst he does all the hard work." # TODO she instead of he if applicable # TODO: she instead of he if applicable
end text 'Your character is now attempting to light the logs. Sit back for a moment whilst he '\
'does all the hard work.'
end
# The instruction displayed when the has lit the logs. # The instruction displayed when the has lit the logs.
dialogue :gained_experience do dialogue :gained_experience do
type :text type :text
text "You gained some experience."\ text 'You gained some experience.'\
"Click on the flashing bar graph icon near the inventory button to see your skill stats." 'Click on the flashing bar graph icon near the inventory button to see your skill '\
end 'stats.'
end
# The dialogue displayed when the Player has clicked the flashing skill tab icon. # The dialogue displayed when the Player has clicked the flashing skill tab icon.
dialogue :skill_stats do dialogue :skill_stats do
type :text type :text
title "Your skill stats." title 'Your skill stats.'
text "" # TODO !! text '' # TODO: this !!
end end
end end
end end
+25 -37
View File
@@ -1,52 +1,40 @@
# Information about npc spawning
#
# Npcs are passed to spawn npc as a hash. Every key and every non-integer value must be a Symbol. Every hash must implement the following:
# :name - the name of the npc. If this npc shares its name with another, append the specific id after the name (e.g. :woman_4)
# :x - the x coordinate where the npc will spawn.
# :y - the y coordinate where the npc will spawn.
# Optional arguments are as follows:
# :face - the direction the npc should face when it spawns. Supported options are :north, :north_east, :east, :south_east, :south, :south_west, :west, and :north_west
# :bounds - the rectangular bound that the npc can wander about in. Order is [bottom-left x-coordinate, bottom-left y-coordinate, top-right x-coordinate, top-right y-coordinate]
# :delta_bounds - the rectangular bound that the npc can wander about in, as a difference from the spawn point. Order is [x-delta, y-delta]. Should not be used with :bounds.
# :spawn_animation - the animation that will be played when the npc spawns.
# :spawn_graphic - the graphic that will be played when the npc spawns.
# Functional npcs # Functional npcs
# 'Above-ground' npcs # 'Above-ground' npcs
spawn_npc :name => :master_chef, :x => 3076, :y => 3085 spawn_npc name: :master_chef, x: 3076, y: 3085
spawn_npc :name => :quest_guide, :x => 3086, :y => 3122, :face => :north spawn_npc name: :quest_guide, x: 3086, y: 3122, face: :north
spawn_npc :name => :financial_advisor, :x => 3127, :y => 3124, :face => :west spawn_npc name: :financial_advisor, x: 3127, y: 3124, face: :west
spawn_npc :name => :brother_brace, :x => 3124, :y => 3107, :face => :east spawn_npc name: :brother_brace, x: 3124, y: 3107, face: :east
spawn_npc :name => :magic_instructor, :x => 3140, :y => 3085 spawn_npc name: :magic_instructor, x: 3140, y: 3085
# 'Below-ground' npcs # 'Below-ground' npcs
# Note: They aren't actually on a different plane, they're just in a different location that pretends to be underground. # Note: They aren't actually on a different plane, they're just in a different location that
# pretends to be underground.
spawn_npc :name => :mining_instructor, :x => 3081, :y => 9504 spawn_npc name: :mining_instructor, x: 3081, y: 9504
spawn_npc :name => :combat_instructor, :x => 3104, :y => 9506 spawn_npc name: :combat_instructor, x: 3104, y: 9506
# Non-humanoid npcs # Non-humanoid npcs
spawn_npc :name => :fishing_spot_316, :x => 3102, :y => 3093 spawn_npc name: :fishing_spot_316, x: 3102, y: 3093
spawn_npc :name => :chicken, :x => 3140, :y => 3095
spawn_npc :name => :chicken, :x => 3140, :y => 3093
spawn_npc :name => :chicken, :x => 3138, :y => 3092
spawn_npc :name => :chicken, :x => 3137, :y => 3094
spawn_npc :name => :chicken, :x => 3138, :y => 3095
spawn_npc name: :chicken, x: 3140, y: 3095
spawn_npc name: :chicken, x: 3140, y: 3093
spawn_npc name: :chicken, x: 3138, y: 3092
spawn_npc name: :chicken, x: 3137, y: 3094
spawn_npc name: :chicken, x: 3138, y: 3095
# 'Below-ground' npcs # 'Below-ground' npcs
# Note: They aren't actually on a different plane, they're just in a different location that pretends to be underground. # Note: They aren't actually on a different plane, they're just in a different location that
# pretends to be underground.
spawn_npc :name => :giant_rat_87, :x => 3105, :y => 9514 spawn_npc name: :giant_rat_87, x: 3105, y: 9514
spawn_npc :name => :giant_rat_87, :x => 3105, :y => 9517 spawn_npc name: :giant_rat_87, x: 3105, y: 9517
spawn_npc :name => :giant_rat_87, :x => 3106, :y => 9514 spawn_npc name: :giant_rat_87, x: 3106, y: 9514
spawn_npc :name => :giant_rat_87, :x => 3104, :y => 9514 spawn_npc name: :giant_rat_87, x: 3104, y: 9514
spawn_npc :name => :giant_rat_87, :x => 3105, :y => 9519 spawn_npc name: :giant_rat_87, x: 3105, y: 9519
spawn_npc :name => :giant_rat_87, :x => 3109, :y => 9516 spawn_npc name: :giant_rat_87, x: 3109, y: 9516
spawn_npc :name => :giant_rat_87, :x => 3108, :y => 9520 spawn_npc name: :giant_rat_87, x: 3108, y: 9520
spawn_npc :name => :giant_rat_87, :x => 3102, :y => 9517 spawn_npc name: :giant_rat_87, x: 3102, y: 9517
@@ -5,11 +5,12 @@ private
STAGES = [] STAGES = []
# The stages that are used when interacting with the Runescape Guide. # The stages that are used when interacting with the Runescape Guide.
RUNESCAPE_GUIDE = [ :not_started, :talk_to_people, :go_through_door, :runescape_guide_finished, :moving_around ] RUNESCAPE_GUIDE = [:not_started, :talk_to_people, :go_through_door, :runescape_guide_finished,
:moving_around]
STAGES.concat(RUNESCAPE_GUIDE) STAGES.concat(RUNESCAPE_GUIDE)
# The stages that are used when interacting with the Survival Expert. # The stages that are used when interacting with the Survival Expert.
SURVIVAL_EXPERT = [ :given_axe, :cut_tree, :cutting_tree, ] SURVIVAL_EXPERT = [:given_axe, :cut_tree, :cutting_tree]
STAGES.concat(SURVIVAL_EXPERT) STAGES.concat(SURVIVAL_EXPERT)
quest :tutorial_island, STAGES quest :tutorial_island, STAGES
@@ -10,7 +10,7 @@ private
module SurvivalConstants module SurvivalConstants
# The Survival Expert Npc. # The Survival Expert Npc.
@survival_expert = spawn_npc :name => :survival_expert, :x => 3104, :y => 3095, :face => :north @survival_expert = spawn_npc name: :survival_expert, x: 3104, y: 3095, face: :north
# The inventory tab index. # The inventory tab index.
INVENTORY_TAB_INDEX = 3 INVENTORY_TAB_INDEX = 3
@@ -29,7 +29,6 @@ module SurvivalConstants
end end
# The conversation with the Survival Expert, when on tutorial island. # The conversation with the Survival Expert, when on tutorial island.
conversation :tutorial_surivival_expert do conversation :tutorial_surivival_expert do
@@ -39,23 +38,23 @@ conversation :tutorial_surivival_expert do
precondition { |player| player.tutorial_island_progress == :moving_around } precondition { |player| player.tutorial_island_progress == :moving_around }
text "Hello there, newcomer. My name is Brynna. My job is to teach you a few survival tips and tricks. First off we're "\ text 'Hello there, newcomer. My name is Brynna. My job is to teach you a few survival tips and'\
"going to start with the most basic survival skill of all: making a fire." ' tricks. First off we\'re going to start with the most basic survival skill of all: '\
'making a fire.'
close &:add_survival_items close(&:add_survival_items)
end end
dialogue :hello_again do dialogue :hello_again do
type :npc_speech type :npc_speech
npc :survival_expert npc :survival_expert
precondition { |player| player.tutorial_island_progress == :moving_around } precondition { |player| player.tutorial_island_progress == :moving_around }
text "Hello again. I'm here to teach you a few survival tips and tricks. First off we're going to start with the most "\ text 'Hello again. I\'m here to teach you a few survival tips and tricks. First off we\'re '\
"basic survival skill of all: making a fire." 'going to start with the most basic survival skill of all: making a fire.'
close &:add_survival_items close(&:add_survival_items)
end end
# The dialogue displayed when the Survival Expert gives the player a bronze axe. # The dialogue displayed when the Survival Expert gives the player a bronze axe.
@@ -63,7 +62,7 @@ conversation :tutorial_surivival_expert do
type :message_with_item type :message_with_item
item :bronze_axe item :bronze_axe
text "The Survival Expert gives you a bronze axe!" text 'The Survival Expert gives you a bronze axe!'
close { |player| TutorialInstructions.show_instruction(player) } close { |player| TutorialInstructions.show_instruction(player) }
end end
@@ -73,23 +72,28 @@ conversation :tutorial_surivival_expert do
type :message_with_item type :message_with_item
item :tinderbox item :tinderbox
text "The Survival Expert gives you a tinderbox!" text 'The Survival Expert gives you a tinderbox!'
close { |player| TutorialInstructions.show_instruction(player) } close { |player| TutorialInstructions.show_instruction(player) }
end end
# The dialogue displayed when the Survival Expert gives the player both a bronze axe and a tinderbox. # The dialogue displayed when the Survival Expert gives the player both a bronze axe and a
# tinderbox.
dialogue :give_axe_and_tinderbox do dialogue :give_axe_and_tinderbox do
type :message_with_item type :message_with_item
item :bronze_axe # TODO the tinderbox is also displayed - find this dialogue id. Scale looks like the default http://i.imgur.com/i1abN5X.png item :bronze_axe
# TODO: the tinderbox is also displayed - find this dialogue id. Scale looks like the default
# http://i.imgur.com/i1abN5X.png
text "The Survival Expert gives you a tinderbox and a bronze axe!" text 'The Survival Expert gives you a tinderbox and a bronze axe!'
close do |player| close do |player|
if (player.tutorial_island_progress < :given_axe) if player.tutorial_island_progress < :given_axe
player.tutorial_island_progress = :given_axe player.tutorial_island_progress = :given_axe
player.send(SwitchTabInterfaceMessage.new(SurvivalConstants::INVENTORY_TAB_INDEX, SurvivalConstants::INVENTORY_TAB_ID))
player.send(FlashTabInterfaceMessage.new(SurvivalConstants::INVENTORY_TAB_INDEX)) index = SurvivalConstants::INVENTORY_TAB_INDEX
player.send(SwitchTabInterfaceMessage.new(index, SurvivalConstants::INVENTORY_TAB_ID))
player.send(FlashTabInterfaceMessage.new(index))
end end
TutorialInstructions.show_instruction(player) TutorialInstructions.show_instruction(player)
@@ -101,14 +105,14 @@ conversation :tutorial_surivival_expert do
type :message_with_item type :message_with_item
item :logs item :logs
text "You get some logs." text 'You get some logs.'
close { |player| TutorialInstructions.show_instruction(player) } close { |player| TutorialInstructions.show_instruction(player) }
end end
end end
# Add the survival items (bronze axe and tinderbox) to the inventory of the player, if they do not
# Add the survival items (bronze axe and tinderbox) to the inventory of the player, if they do not already have them. # already have them.
def add_survival_items(player) def add_survival_items(player)
inventory = player.inventory inventory = player.inventory
@@ -125,21 +129,25 @@ def add_survival_items(player)
send_dialogue(player, get_dialogue(:tutorial_surivival_expert, dialogue)) send_dialogue(player, get_dialogue(:tutorial_surivival_expert, dialogue))
end end
# Intercept the FirstObjectActionMessage to send tutorial-only events if the player is chopping down a tree. # Intercept the FirstObjectActionMessage to send tutorial-only events if the player is chopping
# down a tree.
on :message, :first_object_action do |player, message| on :message, :first_object_action do |player, message|
if (player.in_tutorial_island && message.id == SurvivalConstants::TREE_ID) if player.in_tutorial_island && message.id == SurvivalConstants::TREE_ID
progress = player.tutorial_island_progress progress = player.tutorial_island_progress
if (progress < :cut_tree)
# TODO display "You cannot cut down this tree; you must first follow the guide's instructions." if progress < :cut_tree
elsif (player.tutorial_island_progress == :cut_tree) # TODO: 'You cannot cut down this tree; you must first follow the guide's instructions.'
player.tutorial_island_progress = :cutting_tree # Don't break the chain, so that the Woodcutting event actually happens. elsif player.tutorial_island_progress == :cut_tree
# Don't break the chain, so that the Woodcutting event actually happens.
player.tutorial_island_progress = :cutting_tree
end end
end end
end end
# Intercept the FlashingTabClickedMessage to update the player's progress, if applicable. # Intercept the FlashingTabClickedMessage to update the player's progress, if applicable.
on :message, :flashing_tab_clicked do |player, message| on :message, :flashing_tab_clicked do |player, message|
if (player.in_tutorial_island && message.tab == SurvivalConstants::INVENTORY_TAB_INDEX && player.tutorial_island_progress == :given_axe) if player.in_tutorial_island && message.tab == SurvivalConstants::INVENTORY_TAB_INDEX &&
player.tutorial_island_progress == :given_axe
player.tutorial_island_progress = :cut_tree player.tutorial_island_progress = :cut_tree
message.terminate message.terminate
end end
@@ -5,30 +5,26 @@ java_import 'org.apollo.game.model.entity.Player'
# Declare the tutorial island progress attribute. # Declare the tutorial island progress attribute.
declare_attribute(:tutorial_island_progress, :not_started, :persistent) declare_attribute(:tutorial_island_progress, :not_started, :persistent)
# The existing player class. # The existing player class.
class Player class Player
# Returns whether or not this Player is currently on tutorial island. # Returns whether or not this Player is currently on tutorial island.
def in_tutorial_island def in_tutorial_island
x, y = self.position.x, self.position.y x = position.x
y = position.y
return above_ground(x, y) || below_ground(x, y) above_ground(x, y) || below_ground(x, y)
end end
end end
private private
# Returns whether or not the specified coordinate pair is above ground on tutorial island. # Returns whether or not the specified coordinate pair is above ground on tutorial island.
def above_ground(x, y) def above_ground(x, y)
return (x >= 3053 && x <= 3156 && y >= 3056 && y <= 3136) x >= 3053 && x <= 3156 && y >= 3056 && y <= 3136
end end
# Returns whether or not the specified coordinate pair is 'below' ground on tutorial island. # Returns whether or not the specified coordinate pair is 'below' ground on tutorial island.
def below_ground(x, y) def below_ground(x, y)
return (x >= 3072 && x <= 3118 && y >= 9492 && y <= 9535) x >= 3072 && x <= 3118 && y >= 9492 && y <= 9535
end end
+17 -16
View File
@@ -4,6 +4,7 @@ require 'set'
module DoorConstants module DoorConstants
# TODO: GameObjectOrientation enumeration in Apollo's core? # TODO: GameObjectOrientation enumeration in Apollo's core?
# The orientation of a door.
module Orientation module Orientation
WEST = 0 WEST = 0
NORTH = 1 NORTH = 1
@@ -15,29 +16,29 @@ module DoorConstants
DOOR_SIZE = 1 DOOR_SIZE = 1
# Door object ids that have a hinge on the left side. # Door object ids that have a hinge on the left side.
LEFT_HINGE_DOORS = Set.new [ 1516, 1536, 1533 ] LEFT_HINGE_DOORS = Set.new [1516, 1536, 1533]
# Door object ids that have a hinge on the right side. # Door object ids that have a hinge on the right side.
RIGHT_HINGE_DOORS = Set.new [ 1519, 1530, 4465, 4467, 3014, 3017, 3018, 3019 ] RIGHT_HINGE_DOORS = Set.new [1519, 1530, 4465, 4467, 3014, 3017, 3018, 3019]
# The hash of orientations that a door will translate to when opened. # The hash of orientations that a door will translate to when opened.
ORIENTATIONS = { ORIENTATIONS = {
# Orientations for doors that have a hinge on the left side. # Orientations for doors that have a hinge on the left side.
:left_side_hinge => { left_side_hinge: {
Orientation::NORTH => Orientation::WEST, Orientation::NORTH => Orientation::WEST,
Orientation::SOUTH => Orientation::EAST, Orientation::SOUTH => Orientation::EAST,
Orientation::WEST => Orientation::SOUTH, Orientation::WEST => Orientation::SOUTH,
Orientation::EAST => Orientation::NORTH Orientation::EAST => Orientation::NORTH
}, },
# Orientations for doors that have a hinge on the right side. # Orientations for doors that have a hinge on the right side.
:right_side_hinge => { right_side_hinge: {
Orientation::NORTH => Orientation::EAST, Orientation::NORTH => Orientation::EAST,
Orientation::SOUTH => Orientation::WEST, Orientation::SOUTH => Orientation::WEST,
Orientation::WEST => Orientation::NORTH, Orientation::WEST => Orientation::NORTH,
Orientation::EAST => Orientation::SOUTH Orientation::EAST => Orientation::SOUTH
} }
} }
end end
+5 -4
View File
@@ -1,3 +1,4 @@
java_import 'org.apollo.game.action.DistancedAction' java_import 'org.apollo.game.action.DistancedAction'
# A distanced action which opens a door. # A distanced action which opens a door.
@@ -13,20 +14,20 @@ class OpenDoorAction < DistancedAction
def executeAction def executeAction
mob.turn_to(@door.position) mob.turn_to(@door.position)
DoorUtil::toggle(@door) DoorUtil.toggle(@door)
stop stop
end end
def equals(other) def equals(other)
return (get_class == other.get_class && @door == other.door) get_class == other.get_class && @door == other.door
end end
end end
# MessageListener for opening and closing doors. # MessageListener for opening and closing doors.
on :message, :first_object_action do |player, message| on :message, :first_object_action do |player, message|
if DoorUtil::is_door?(message.id) if DoorUtil.door?(message.id)
door = DoorUtil::get_door_object(message.position, message.id) door = DoorUtil.get_door_object(message.position, message.id)
player.start_action(OpenDoorAction.new(player, door)) unless door.nil? player.start_action(OpenDoorAction.new(player, door)) unless door.nil?
end end
end end
+19 -19
View File
@@ -15,20 +15,18 @@ module DoorUtil
# Translates a door's position in the direction of its orientation. # Translates a door's position in the direction of its orientation.
def self.translate_door_position(door) def self.translate_door_position(door)
position = door.position position = door.position
orientation = door.orientation
case orientation case door.orientation
when Orientation::WEST when Orientation::WEST
return Position.new(position.x - 1, position.y, position.height) Position.new(position.x - 1, position.y, position.height)
when Orientation::EAST when Orientation::EAST
return Position.new(position.x + 1, position.y, position.height) Position.new(position.x + 1, position.y, position.height)
when Orientation::NORTH when Orientation::NORTH
return Position.new(position.x, position.y + 1, position.height) Position.new(position.x, position.y + 1, position.height)
when Orientation::SOUTH when Orientation::SOUTH
return Position.new(position.x, position.y - 1, position.height) Position.new(position.x, position.y - 1, position.height)
else fail "Unsupported orientation #{door.orientation}."
end end
raise 'Invalid orientation for door!'
end end
# Translates the orientation of a door to a toggled position. # Translates the orientation of a door to a toggled position.
@@ -42,13 +40,12 @@ module DoorUtil
return ORIENTATIONS[:left_side_hinge][orientation] return ORIENTATIONS[:left_side_hinge][orientation]
end end
raise 'Given object was not registered as a door.' fail 'Given object was not registered as a door.'
end end
# Toggles the given door. # Toggles the given door.
def self.toggle(door) def self.toggle(door)
position = door.position region = $world.region_repository.from_position(door.position)
region = $world.region_repository.from_position(position)
region.remove_entity(door) region.remove_entity(door)
if TOGGLED_DOORS.include?(door) if TOGGLED_DOORS.include?(door)
@@ -57,11 +54,13 @@ module DoorUtil
original_region = $world.region_repository.from_position(original_door.position) original_region = $world.region_repository.from_position(original_door.position)
original_region.add_entity(original_door) original_region.add_entity(original_door)
else else
toggled_position = translate_door_position(door) position = translate_door_position(door)
toggled_orientation = translate_door_orientation(door) orientation = translate_door_orientation(door)
toggled_door = DynamicGameObject.create_public($world, door.id, toggled_position, door.type, toggled_orientation) type = door.type
toggled_region = $world.region_repository.from_position(toggled_position) toggled_door = DynamicGameObject.create_public($world, door.id, position, type, orientation)
toggled_region = $world.region_repository.from_position(position)
toggled_region.add_entity(toggled_door) toggled_region.add_entity(toggled_door)
TOGGLED_DOORS[toggled_door] = door TOGGLED_DOORS[toggled_door] = door
@@ -70,13 +69,14 @@ module DoorUtil
# Gets the door object at the given position, if it exists. # Gets the door object at the given position, if it exists.
def self.get_door_object(position, object_id) def self.get_door_object(position, object_id)
game_objects = $world.region_repository.from_position(position).get_entities(position, EntityType::DYNAMIC_OBJECT, EntityType::STATIC_OBJECT) region = $world.region_repository.from_position(position)
game_objects.each { |game_object| return game_object if game_object.id == object_id } objects = region.get_entities(position, EntityType::DYNAMIC_OBJECT, EntityType::STATIC_OBJECT)
return nil objects.each { |game_object| return game_object if game_object.id == object_id }
nil
end end
# Checks if the given game object id is a door. # Checks if the given game object id is a door.
def self.is_door?(object_id) def self.door?(object_id)
RIGHT_HINGE_DOORS.include?(object_id) || LEFT_HINGE_DOORS.include?(object_id) RIGHT_HINGE_DOORS.include?(object_id) || LEFT_HINGE_DOORS.include?(object_id)
end end
@@ -3,14 +3,13 @@ require 'java'
java_import 'org.apollo.game.message.impl.SetPlayerActionMessage' java_import 'org.apollo.game.message.impl.SetPlayerActionMessage'
java_import 'org.apollo.game.model.entity.Player' java_import 'org.apollo.game.model.entity.Player'
# A right-click action for a Player.
class PlayerAction class PlayerAction
attr_reader :slot, :primary, :name attr_reader :slot, :primary, :name
def initialize(slot, primary, name) def initialize(slot, primary, name)
index = [ :first, :second, :third, :fourth, :fifth ].find_index(slot) index = [:first, :second, :third, :fourth, :fifth].find_index(slot)
raise "Unsupported action slot #{slot}." if index.nil? fail "Unsupported action slot #{slot}." if index.nil?
@slot = index @slot = index
@primary = primary @primary = primary
@@ -26,7 +25,7 @@ FOLLOW_ACTION = PlayerAction.new(:fifth, true, 'Follow')
# Shows multiple context menu action for the specified player # Shows multiple context menu action for the specified player
def show_actions(player, *actions) def show_actions(player, *actions)
raise 'Must specify at least one action' if actions.nil? fail 'Must specify at least one action.' if actions.nil?
actions.each do |action| actions.each do |action|
player.add_action(action) player.add_action(action)
@@ -44,6 +43,7 @@ def hide_action(player, action)
show_action(player, PlayerAction.new(action.slot, action.primary, 'null')) show_action(player, PlayerAction.new(action.slot, action.primary, 'null'))
end end
# Monkey-patch Player to provide action utility methods.
class Player class Player
def actions def actions
@@ -54,7 +54,7 @@ class Player
actions[action.slot] = action.name actions[action.slot] = action.name
end end
def has_action(action) def action?(action)
actions[action.slot] == action.name actions[action.slot] == action.name
end end
+1 -1
View File
@@ -1,6 +1,6 @@
java_import 'org.apollo.game.model.entity.Player' java_import 'org.apollo.game.model.entity.Player'
on :login do |event, player| on :login do |_event, player|
show_action(player, TRADE_ACTION) show_action(player, TRADE_ACTION)
show_action(player, FOLLOW_ACTION) show_action(player, FOLLOW_ACTION)
end end
+1 -1
View File
@@ -8,7 +8,7 @@
<author>Ryley</author> <author>Ryley</author>
</authors> </authors>
<scripts> <scripts>
<script>player-action.rb</script> <script>action.rb</script>
<script>login.rb</script> <script>login.rb</script>
</scripts> </scripts>
<dependencies /> <dependencies />
+24 -25
View File
@@ -1,7 +1,7 @@
# Defines a quest with the specified name. # Defines a quest with the specified name.
def quest(name, stage_names) def quest(name, stage_names)
stages = { } stages = {}
stage_names.each_with_index { |stage, index| stages[stage] = QuestStage.new(stage, index, name) } stage_names.each_with_index { |stage, index| stages[stage] = QuestStage.new(stage, index, name) }
QUESTS[name] = Quest.new(name, stages) QUESTS[name] = Quest.new(name, stages)
@@ -18,25 +18,26 @@ class Quest
# Creates the Quest. # Creates the Quest.
def initialize(name, stages) def initialize(name, stages)
raise "Quest name must be a symbol, received '#{name}'." unless name.kind_of?(Symbol) fail "Quest name must be a symbol, received '#{name}'." unless name.is_a?(Symbol)
@name = name @name = name
@stages = stages @stages = stages
end end
# Gets the finishing quest stage (i.e. the stage that indicates the Player has completed the quest). # Gets the finishing quest stage (i.e. the stage that indicates the Player has completed the
def final_stage() # quest).
def final_stage
@stages.last @stages.last
end end
# Gets the starting quest stage. # Gets the starting quest stage.
def initial_stage() def initial_stage
@stages.first @stages.first
end end
# Gets the QuestStage with the specified name. # Gets the QuestStage with the specified name.
def stage(name) def stage(name)
stage = @stages[name] stage = @stages[name]
raise "No stage named #{name} exists in #{@name}." if stage.nil? fail "No stage named #{name} exists in #{@name}." if stage.nil?
stage stage
end end
@@ -47,7 +48,7 @@ class QuestStage
attr_reader :name, :index attr_reader :name, :index
# Creates the QuestProgress. # Creates the QuestProgress.
def initialize(name, index, quest, log_text=nil) def initialize(name, index, quest, log_text = nil)
@name = name @name = name
@index = index @index = index
@quest = quest @quest = quest
@@ -61,41 +62,40 @@ class QuestStage
# Gets the log text for this stage. # Gets the log text for this stage.
def log_text def log_text
raise "Cannot get the log text from an unlogged quest stage." unless logged fail 'Cannot get the log text from an unlogged quest stage.' unless logged
@log_text @log_text
end end
# Defines the equality operator. # Defines the equality operator.
def ==(name) def ==(other)
@index == index_of(name) @index == index_of(other)
end end
# Defines the not equal operator. # Defines the not equal operator.
def !=(name) def !=(other)
@index != index_of(name) @index != index_of(other)
end end
# Defines the greater than or equal to operator. # Defines the greater than or equal to operator.
def >=(name) def >=(other)
@index >= index_of(name) @index >= index_of(other)
end end
# Defines the greater than operator. # Defines the greater than operator.
def >(name) def >(other)
@index > index_of(name) @index > index_of(other)
end end
# Defines the less than operator. # Defines the less than operator.
def <(name) def <(other)
@index < index_of(name) @index < index_of(other)
end end
# Defines the less than or equal to operator. # Defines the less than or equal to operator.
def <=(name) def <=(other)
@index <= index_of(name) @index <= index_of(other)
end end
private private
# Gets the index of the QuestStage with the specified name. # Gets the index of the QuestStage with the specified name.
@@ -105,7 +105,6 @@ class QuestStage
end end
# Define method_missing for player # Define method_missing for player
class Player class Player
@@ -113,16 +112,16 @@ class Player
def method_missing(symbol, *args) def method_missing(symbol, *args)
unless args.nil? unless args.nil?
arg = args[0] arg = args[0]
args[0] = arg.name if arg.kind_of?(QuestStage) args[0] = arg.name if arg.is_a?(QuestStage)
end end
result = super(symbol, *args) result = super(symbol, *args)
string = symbol.to_s string = symbol.to_s
if (string.end_with?('_progress')) if string.end_with?('_progress')
name = string[0..-10] # Cut the '_progress' from the end name = string[0..-10] # Cut the '_progress' from the end
quest = QUESTS[name.to_sym] quest = QUESTS[name.to_sym]
raise "No Quest with the name '#{name}' exists." if quest.nil? fail "No Quest with the name '#{name}' exists." if quest.nil?
result = quest.stage(result) result = quest.stage(result)
end end
+20 -17
View File
@@ -11,28 +11,31 @@ class Fish
@id = id @id = id
@level = level @level = level
@experience = experience @experience = experience
@name = name_of(:item, id) @name = name_of(:item, id)
end end
end end
# Appends a Fish to the hash. # Appends a Fish to the hash.
def append_fish(name, fish) def append_fish(name, hash)
CATCHABLE_FISH[name] = fish unless hash.has_keys?(:id, :level, :experience)
fail 'Hash must contain an id, level, and experience.'
end
CATCHABLE_FISH[name] = Fish.new(hash[:id], hash[:level], hash[:experience])
end end
append_fish(:shrimp, Fish.new(317, 1, 10)) append_fish :shrimp, id: 317, level: 1, experience: 10
append_fish(:sardine, Fish.new(327, 5, 20)) append_fish :sardine, id: 327, level: 5, experience: 20
append_fish(:herring, Fish.new(345, 10, 30)) append_fish :herring, id: 345, level: 10, experience: 30
append_fish(:anchovy, Fish.new(321, 15, 40)) append_fish :anchovy, id: 321, level: 15, experience: 40
append_fish(:mackerel, Fish.new(353, 16, 20)) append_fish :mackerel, id: 353, level: 16, experience: 20
append_fish(:trout, Fish.new(335, 20, 50)) append_fish :trout, id: 335, level: 20, experience: 50
append_fish(:cod, Fish.new(341, 23, 45)) append_fish :cod, id: 341, level: 23, experience: 45
append_fish(:pike, Fish.new(349, 25, 60)) append_fish :pike, id: 349, level: 25, experience: 60
append_fish(:salmon, Fish.new(331, 30, 70)) append_fish :salmon, id: 331, level: 30, experience: 70
append_fish(:tuna, Fish.new(359, 35, 80)) append_fish :tuna, id: 359, level: 35, experience: 80
append_fish(:lobster, Fish.new(377, 40, 90)) append_fish :lobster, id: 377, level: 40, experience: 90
append_fish(:bass, Fish.new(363, 46, 100)) append_fish :bass, id: 363, level: 46, experience: 100
append_fish(:swordfish, Fish.new(371, 50, 100)) append_fish :swordfish, id: 371, level: 50, experience: 100
append_fish(:shark, Fish.new(383, 76, 110)) append_fish :shark, id: 383, level: 76, experience: 110
+44 -35
View File
@@ -6,7 +6,7 @@ java_import 'org.apollo.game.model.entity.Skill'
# An action that causes a mob to fish at a spot. # An action that causes a mob to fish at a spot.
class FishingAction < DistancedAction class FishingAction < DistancedAction
attr_reader :spot, :tool, :position, :started attr_reader :position, :options, :spot, :started, :tool
# Creates the FishingAction. # Creates the FishingAction.
def initialize(mob, position, spot, option) def initialize(mob, position, spot, option)
@@ -15,28 +15,28 @@ class FishingAction < DistancedAction
@spot = spot @spot = spot
@tool = spot.tools[option - 1] @tool = spot.tools[option - 1]
@options = (option == 1) ? spot.first_option : spot.second_option @options = (option == 1) ? spot.first_fish : spot.second_fish
@minimum_level = options.map { |fish| fish.level }.min @minimum_level = @options.map(&:level).min
end end
# Returns whether or not a catch is successful. # Returns whether or not a catch is successful.
def successful_catch(level, requirement) def successful_catch(level, requirement)
return [level - requirement, 30].min > rand(40) [level - requirement + 5, 30].min > rand(40)
end end
# Starts the fishing process. # Starts the fishing process.
def start_fishing() def start_fishing
@started = true @started = true
mob.send_message(tool.message, true) mob.send_message(tool.message, true)
end end
# Executes the action. # Executes the action.
def executeAction() def executeAction
skills = mob.skill_set skills = mob.skill_set
fishing_level = skills.get_skill(Skill::FISHING).current_level fishing_level = skills.get_skill(Skill::FISHING).current_level
mob.turn_to(position) mob.turn_to(position)
if (@minimum_level > fishing_level) if @minimum_level > fishing_level
mob.send_message("You need a fishing level of #{@minimum_level} to fish at this spot.") mob.send_message("You need a fishing level of #{@minimum_level} to fish at this spot.")
stop stop
return return
@@ -49,52 +49,61 @@ class FishingAction < DistancedAction
return return
end end
unless inventory.contains(@tool.id) unless inventory.contains(@tool.id)
mob.send_message("You need a #{@tool.name} to fish at this spot.") mob.send_message("You need a #{@tool.name.downcase} to fish at this spot.")
stop stop
return return
end end
bait = @tool.bait bait = find_bait
if (bait.empty? && !mob.inventory.contains(bait)) if bait == -1
mob.send_message("You need #{name_of(:item, bait)}s to fish at this spot.") mob.send_message("You need #{name_of(:item, bait).downcase}s to fish at this spot.")
stop stop
return return
end end
unless @started if @started
start_fishing options = @options.reject { |fish| fish.level > fishing_level }
else # Player may level up mid-action so reject here, not at initialisation.
options = @options.reject { |fish| fish.level > fishing_level } # Player may level up mid-action so reject here, not at initialisation. fish = options.sample # TODO: it's a ~70/30 chance, not 50/50
fish = options.sample # TODO it's a ~70/30 chance, not 50/50
if successful_catch(fishing_level, fish.level) if successful_catch(fishing_level, fish.level)
inventory.remove(bait) unless bait.empty? inventory.remove(bait) unless bait.nil?
inventory.add(type.id) inventory.add(fish.id)
name = fish.name name = fish.name
mob.send_message("You catch #{name.end_with?('s') ? 'some' : 'a'} #{name}.", true) mob.send_message("You catch #{name.end_with?('s') ? 'some' : 'a'} #{name.downcase}.", true)
skills.add_experience(Skill::FISHING, fish.experience) skills.add_experience(Skill::FISHING, fish.experience)
unless (bait != -1 && !mob.inventory.contains(bait)) if find_bait == -1
mob.send_message("You need more #{name_of(:item, bait)}s to fish at this spot.") mob.send_message("You need more #{name_of(:item, bait).downcase}s to fish at this spot.")
stop stop
return return
end end
end end
else
start_fishing
end end
mob.play_animation(@tool.animation) mob.play_animation(@tool.animation)
end end
# Finds the id of the first piece of bait in the player's inventory, or nil if no bait is
# required, or -1 if the player's inventory does not contain any valid bait.
def find_bait
baits = @tool.bait
baits.empty? ? nil : baits.find(-1) { |bait| mob.inventory.contains(bait) }
end
# Stops this action. # Stops this action.
def stop() def stop
super super
mob.stop_animation mob.stop_animation
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @spot == other.spot and @position == other.position && @options == @other.options) get_class == other.get_class && @spot == other.spot && @position == other.position &&
@options == @other.options
end end
end end
@@ -104,8 +113,8 @@ on :message, :npc_action do |player, message|
npc = $world.npc_repository.get(message.index) npc = $world.npc_repository.get(message.index)
spot = FISHING_SPOTS[npc.id] spot = FISHING_SPOTS[npc.id]
unless spot.nil? unless spot.nil?
player.start_action(FishingAction.new(player, npc.position, spot, message.option)) player.start_action(FishingAction.new(player, npc.position, spot, message.option))
message.terminate message.terminate
end end
end end
+31 -18
View File
@@ -7,10 +7,10 @@ FISHING_TOOLS = {}
# A fishing tool. # A fishing tool.
class Tool class Tool
attr_reader :id, :bait, :animation, :message, :name attr_reader :animation, :bait, :id, :message, :name
# Creates the tool. # Creates the tool.
def initialize(id, bait=[], animation, message) def initialize(id, animation, message, bait)
@id = id @id = id
@bait = bait @bait = bait
@animation = Animation.new(animation) @animation = Animation.new(animation)
@@ -21,27 +21,40 @@ class Tool
end end
private private
# Appends a tool with the specified name to the hash. # Appends a tool with the specified name to the hash.
def append_tool(name, tool) def tool(name, hash)
FISHING_TOOLS[name] = tool unless hash.has_keys?(:id, :animation, :message)
fail 'Hash must contain an id, animation, and message.'
end
bait = hash[:bait] || []
FISHING_TOOLS[name] = Tool.new(hash[:id], hash[:animation], hash[:message], bait)
end end
HARPOON_ANIMATION_ID = 618 # The harpoon fishing animation id.
CAGE_ANIMATION_ID = 619 HARPOON_ANIMATION = 618
NET_ANIMATION_ID = 620
ROD_ANIMATION_ID = 622
# TODO The other feathers that can be used # The cage fishing animation id.
FISHING_ROD_BAIT = [ 313 ] CAGE_ANIMATION = 619
FLY_FISHING_ROD_BAIT = [ 314 ]
append_tool(:lobster_cage, Tool.new(301, CAGE_ANIMATION_ID, 'You attempt to catch a lobster...')) # The net fishing animation id.
append_tool(:small_net, Tool.new(303, NET_ANIMATION_ID, 'You cast out your net...')) NET_ANIMATION = 620
append_tool(:big_net, Tool.new(305, NET_ANIMATION_ID, 'You cast out your net...'))
append_tool(:harpoon, Tool.new(311, HARPOON_ANIMATION_ID, 'You start harpooning fish...'))
append_tool(:fishing_rod, Tool.new(307, FISHING_ROD_BAIT, ROD_ANIMATION_ID, 'You attempt to catch a fish...')) # The rod fishing animation id.
append_tool(:fly_fishing_rod, Tool.new(309, FLY_FISHING_ROD_BAIT, ROD_ANIMATION_ID, 'You attempt to catch a fish...')) ROD_ANIMATION = 622
# TODO: The other feathers that can be used
FISHING_ROD_BAIT = [313]
FLY_FISHING_ROD_BAIT = [314]
tool :lobster_cage, id: 301, animation: CAGE_ANIMATION, message: 'You attempt to catch a lobster...'
tool :small_net, id: 303, animation: NET_ANIMATION, message: 'You cast out your net...'
tool :big_net, id: 305, animation: NET_ANIMATION, message: 'You cast out your net...'
tool :harpoon, id: 311, animation: HARPOON_ANIMATION, message: 'You start harpooning fish...'
tool :fishing_rod, id: 307, animation: ROD_ANIMATION, message: 'You attempt to catch a fish...',
bait: FISHING_ROD_BAIT
tool :fly_fishing_rod, id: 309, animation: ROD_ANIMATION, message: 'You attempt to catch a fish...',
bait: FLY_FISHING_ROD_BAIT
+7 -4
View File
@@ -16,7 +16,7 @@ class Herb < Ingredient
@experience = experience @experience = experience
end end
def invoke(player, id, slot) def invoke(player, _id, slot)
item = player.inventory.get(slot) item = player.inventory.get(slot)
player.start_action(HerbIdentificationAction.new(player, self, slot, item)) player.start_action(HerbIdentificationAction.new(player, self, slot, item))
end end
@@ -37,11 +37,12 @@ class HerbIdentificationAction < Action
def execute def execute
if @pulses == 0 if @pulses == 0
unless check_skill(mob, @herb.level, "identify this herb") unless check_skill(mob, @herb.level, 'identify this herb')
stop stop
return return
end end
end end
execute_action execute_action
@pulses += 1 @pulses += 1
end end
@@ -56,12 +57,14 @@ class HerbIdentificationAction < Action
inventory.add(identified) inventory.add(identified)
player.skill_set.add_experience(HERBLORE_ID, @herb.experience) player.skill_set.add_experience(HERBLORE_ID, @herb.experience)
player.send_message("You identify the herb as a #{identified.definition.name}.", true) player.send_message("You identify the herb as a #{identified.definition.name}.", true)
# TODO: 'as an' in some cases
end end
stop stop
end end
def equals(other) def equals(other)
return (get_class == other.get_class and slot == other.slot and herb == other.herb) get_class == other.get_class && slot == other.slot && herb == other.herb
end end
end end
@@ -69,7 +72,7 @@ end
def append_herb(item_id, unidentified, level, experience) def append_herb(item_id, unidentified, level, experience)
herb = Herb.new(item_id, unidentified, level, experience) herb = Herb.new(item_id, unidentified, level, experience)
append_herblore_item(herb, unidentified) append_herblore_item(herb, unidentified)
return herb herb
end end
# Herbs # Herbs
+14 -12
View File
@@ -1,4 +1,4 @@
# Thanks to Sillhouette <http://www.rune-server.org/members/silhouette/> for posting # 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. # a large amount of Herblore skill data which has been thankfully used in this plugin.
require 'java' require 'java'
@@ -13,15 +13,14 @@ HERBLORE_ITEM_ON_ITEM = {}
DRINK_ITEM = {} DRINK_ITEM = {}
# A module which describes an invocable method of the Herblore skill. # A module which describes an invocable method of the Herblore skill.
module HerbloreMethod module HerbloreMethod
def self.new def self.new
raise 'You cannot instantiate this module!' fail 'You cannot instantiate this module!'
end end
def invoke(player, primary, secondary) def invoke(_player, _primary, _secondary)
raise NotImplementedError.new('You must implement the invocation of HerbloreMethod!') fail 'You must implement the invocation of HerbloreMethod!'
end end
end end
@@ -76,24 +75,27 @@ def append_herblore_item(method, key, secondary = -1)
end end
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. # Utility method for checking if a player's inventory has a of the specified id, with optionally
# the specified amount (1 by default), at the specified slot.
def check_slot(player, slot, id, amount = 1) def check_slot(player, slot, id, amount = 1)
item = player.inventory.get(slot) item = player.inventory.get(slot)
return (!item.nil? and item.id == id and item.amount >= amount) !item.nil? && item.id == id && item.amount >= amount
end 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 # Utility method for checking if a player's Herblore (maximum) level is at the required level. Also
# variable, like so: "You need a Herblore level of at least #{required.to_s} to #{action}." # 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) def check_skill(player, required, action)
if (required > player.skill_set.get_skill(Skill::HERBLORE).current_level) if required > player.skill_set.get_skill(Skill::HERBLORE).current_level
player.send_message("You need a Herblore level of at least #{required} to #{action}.") player.send_message("You need a Herblore level of at least #{required} to #{action}.")
return false return false
end end
return true true
end end
# Opens a 'make' dialogue for the specified player, displaying the specified item. Optionally, a listener can be used for the dialogue. # 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) def open_dialogue(player, item, listener = nil)
player.send(SetWidgetItemModelMessage.new(1746, item, 170)) player.send(SetWidgetItemModelMessage.new(1746, item, 170))
player.interface_set.open_dialogue(listener, HERBLORE_DIALOGUE) player.interface_set.open_dialogue(listener, HERBLORE_DIALOGUE)
+20 -22
View File
@@ -18,16 +18,15 @@ class Ingredient
@item = Item.new(item) # Share item instances. @item = Item.new(item) # Share item instances.
end end
# Checks if the specified player has the specified amount of this ingredient. Optionally, they can immediately be removed if that # Checks if the specified player has the specified amount of this ingredient. Optionally, they
# amount was indeed found. # can immediately be removed if that amount was indeed found.
def check_remove(player, amount, remove) def check_remove(player, amount, remove)
inventory = player.inventory inventory = player.inventory
counter = 0 counter = 0
inventory.items.each do |inv_item| inventory.items.each do |inv_item|
break unless counter < amount break unless counter < amount
next if inv_item.nil?
next if inv_item == nil
id = inv_item.id id = inv_item.id
inventory_amount = inv_item.amount inventory_amount = inv_item.amount
@@ -47,7 +46,7 @@ class Ingredient
return true return true
end end
return false false
end end
end end
@@ -59,11 +58,10 @@ class GroundIngredient < Ingredient
def initialize(item_id, raw) def initialize(item_id, raw)
super(item_id) super(item_id)
@raw = raw @raw = raw
end end
def invoke(player, pestle_mortar, ingredient) def invoke(player, _pestle_mortar, _ingredient)
action = GrindingAction.new(player, self) action = GrindingAction.new(player, self)
listener = GrindingDialogueListener.new(player, action) listener = GrindingDialogueListener.new(player, action)
@@ -71,7 +69,8 @@ class GroundIngredient < Ingredient
end end
end end
# A DialogueAdapter used for grinding ingredients. It is also used as an EnterAmountListener for the amount of grinding actions. # A DialogueAdapter used for grinding ingredients. It is also used as an EnterAmountListener for
# the amount of grinding actions.
class GrindingDialogueListener < DialogueAdapter class GrindingDialogueListener < DialogueAdapter
include EnterAmountListener include EnterAmountListener
@@ -79,7 +78,6 @@ class GrindingDialogueListener < DialogueAdapter
def initialize(player, action) def initialize(player, action)
super() super()
@player = player @player = player
@action = action @action = action
end end
@@ -103,7 +101,7 @@ class GrindingDialogueListener < DialogueAdapter
# Called when an amount of grinding actions has been entered. # Called when an amount of grinding actions has been entered.
def amountEntered(amount) def amountEntered(amount)
if amount <= 0 then return else execute(amount) end execute(amount) if amount > 0
end end
# Called to set the action(s) in motion. # Called to set the action(s) in motion.
@@ -129,7 +127,7 @@ class GrindingAction < Action
attr_reader :ingredient, :amount, :pulses, :slot, :listener attr_reader :ingredient, :amount, :pulses, :slot, :listener
def initialize(player, ingredient) def initialize(player, ingredient)
super 0, true, player super(0, true, player)
@ingredient = ingredient @ingredient = ingredient
@pulses = 0 @pulses = 0
@@ -145,7 +143,7 @@ class GrindingAction < Action
if @pulses == 0 if @pulses == 0
mob.play_animation GRINDING_ANIM mob.play_animation GRINDING_ANIM
elsif @pulses == 1 elsif @pulses == 1
if not gather_materials unless gather_materials
stop stop
return return
end end
@@ -163,7 +161,7 @@ class GrindingAction < Action
set_delay(1) set_delay(1)
elsif @pulses == 2 elsif @pulses == 2
mob.stop_animation mob.stop_animation
continue() continue
end end
end end
@@ -176,21 +174,21 @@ class GrindingAction < Action
raw = @ingredient.raw raw = @ingredient.raw
(0...items.length).each do |slot| (0...items.length).each do |slot|
item = items[slot] item = items[slot]
next if item == nil next if item.nil?
id = item.id id = item.id
if id == PESTLE_MORTAR and !pst_mrt if id == PESTLE_MORTAR && !pst_mrt
pst_mrt = true pst_mrt = true
elsif id == raw and !ingr elsif id == raw && !ingr
ingr = true ingr = true
@slot = slot @slot = slot
end end
return true if pst_mrt and ingr return true if pst_mrt && ingr
end end
mob.send_message("You do not have any more #{name_of(raw).downcase}s.") mob.send_message("You do not have any more #{name_of(raw).downcase}s.")
return false false
end end
# Either invokes the stop() method in Action to shut it down # Either invokes the stop() method in Action to shut it down
@@ -213,11 +211,11 @@ class GrindingAction < Action
def stop def stop
super super
mob.inventory.remove_listener(@listener) unless listener == nil mob.inventory.remove_listener(@listener) unless listener.nil?
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @ingredient == other.ingredient) get_class == other.get_class && @ingredient == other.ingredient
end end
end end
@@ -225,7 +223,7 @@ end
def append_ground(id, raw) def append_ground(id, raw)
ground = GroundIngredient.new(id, raw) ground = GroundIngredient.new(id, raw)
append_herblore_item(ground, PESTLE_MORTAR, raw) append_herblore_item(ground, PESTLE_MORTAR, raw)
return ground ground
end end
# Normal ingredients # Normal ingredients
@@ -250,4 +248,4 @@ MAGIC_ROOTS = Ingredient.new(6051)
UNICORN_HORN_DUST = append_ground(235, 237) UNICORN_HORN_DUST = append_ground(235, 237)
DRAGON_SCALE_DUST = append_ground(241, 243) DRAGON_SCALE_DUST = append_ground(241, 243)
CHOCOLATE_DUST = append_ground(1975, 1973) CHOCOLATE_DUST = append_ground(1975, 1973)
# CRUSHED_NEST = append_ground(6693, 5075) # CRUSHED_NEST = append_ground(6693, 5075) # TODO: only in 377
+71 -66
View File
@@ -13,25 +13,26 @@ EMPTY_VIAL_ID = 229
MIXING_ANIM = Animation.new(363) MIXING_ANIM = Animation.new(363)
# Represents an unfinished potion which can be invoked as a HerbloreMethod and used as an ingredient. # Represents an unfinished potion which can be invoked as a HerbloreMethod and used as an
# ingredient.
class UnfinishedPotion < Ingredient class UnfinishedPotion < Ingredient
include HerbloreMethod include HerbloreMethod
attr_reader :herb, :level attr_reader :herb, :level
def initialize(item_id, herb, level) def initialize(item_id, herb, level)
super item_id super(item_id)
@herb = herb @herb = herb
@level = level @level = level
end end
def invoke(player, primary, secondary) def invoke(player, _primary, _secondary)
action = UnfinishedMixingAction.new(player, self) action = UnfinishedMixingAction.new(player, self)
listener = UnfinishedMixingDialogueListener.new(player, action) listener = UnfinishedMixingDialogueListener.new(player, action)
open_dialogue(player, @item_id, listener) open_dialogue(player, @item_id, listener)
end end
end end
# Represents a finished potion which can be invoked as a HerbloreMethod. # Represents a finished potion which can be invoked as a HerbloreMethod.
@@ -55,7 +56,8 @@ class FinishedPotion
end end
end end
# A DialogueAdapter used for mixing potions. It is also used as an EnterAmountListener for the amount of mixing actions. # A DialogueAdapter used for mixing potions. It is also used as an EnterAmountListener for the
# amount of mixing actions.
class MixingDialogueListener < DialogueAdapter class MixingDialogueListener < DialogueAdapter
include EnterAmountListener include EnterAmountListener
@@ -85,12 +87,12 @@ class MixingDialogueListener < DialogueAdapter
amount = calculate_maximum if amount == -2 amount = calculate_maximum if amount == -2
execute(amount) execute(amount)
return true true
end end
# Called when an amount of mixing actions has been entered. # Called when an amount of mixing actions has been entered.
def amountEntered(amount) def amountEntered(amount)
if amount <= 0 then return else execute(amount) end execute(amount) if amount > 0
end end
# Called to set the action(s) in motion. # Called to set the action(s) in motion.
@@ -99,7 +101,7 @@ class MixingDialogueListener < DialogueAdapter
@player.start_action(@action) @player.start_action(@action)
end end
def calculate_maximum(code) def calculate_maximum(_code)
# Override for potion-specific amount calculation. # Override for potion-specific amount calculation.
end end
@@ -118,18 +120,17 @@ end
# A MixingDialogueListener used for mixing unfinished potions. # A MixingDialogueListener used for mixing unfinished potions.
class UnfinishedMixingDialogueListener < MixingDialogueListener class UnfinishedMixingDialogueListener < MixingDialogueListener
def calculate_maximum def calculate_maximum
inventory = @player.inventory inventory = @player.inventory
amount = inventory.get_amount(WATER_VIAL_ID) amount = inventory.get_amount(WATER_VIAL_ID)
return 0 if amount <= 0 return 0 if amount <= 0
herbs = inventory.get_amount(@action.potion.herb.item.id) herbs = inventory.get_amount(@action.potion.herb.item.id)
amount = herbs if amount > herbs [herbs, amount].min
return amount
end end
end end
# A MixingDialogueListener used for mixing finished potions. # A MixingDialogueListener used for mixing finished potions.
@@ -144,7 +145,7 @@ class FinishedMixingDialogueListener < MixingDialogueListener
amount = item_amount if amount > item_amount amount = item_amount if amount > item_amount
end end
return amount amount
end end
end end
@@ -170,6 +171,7 @@ class MixingAction < Action
stop stop
return return
end end
@started = true @started = true
end end
@@ -178,15 +180,17 @@ class MixingAction < Action
return return
end end
end end
mob.play_animation(MIXING_ANIM) mob.play_animation(MIXING_ANIM)
execute_action execute_action
if (@amount -= 1) > 0 then @pulses = 0 else stop end @amount -= 1
@amount > 0 ? @pulses = 0 : stop
end end
def stop def stop
super() super()
mob.inventory.remove_listener(@listener) unless @listener == nil mob.inventory.remove_listener(@listener) unless @listener.nil?
end end
def execute_action def execute_action
@@ -195,7 +199,7 @@ class MixingAction < Action
def gather_materials def gather_materials
# Override for ingredient checking and gathering # Override for ingredient checking and gathering
return false false
end end
# Sets the amount of actions. # Sets the amount of actions.
@@ -204,7 +208,7 @@ class MixingAction < Action
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @potion == other.potion) get_class == other.get_class && @potion == other.potion
end end
end end
@@ -213,7 +217,7 @@ class UnfinishedMixingAction < MixingAction
attr_reader :slots attr_reader :slots
def initialize(player, potion) def initialize(player, potion)
super(player, potion, "use this herb.") super(player, potion, 'use this herb.')
end end
def execute_action def execute_action
@@ -221,7 +225,9 @@ class UnfinishedMixingAction < MixingAction
player = mob player = mob
inventory = player.inventory inventory = player.inventory
player.send_message("You put the #{name} in the water to make an unfinished #{name.sub(/ leaf$/, "")} potion.", true) created = name.sub(/ leaf$/, '')
message = "You put the #{name} in the water to make an unfinished #{created} potion."
player.send_message(message, true)
@slots.each do |slot, amount| @slots.each do |slot, amount|
unless inventory.remove_slot(slot, amount) unless inventory.remove_slot(slot, amount)
@@ -253,8 +259,9 @@ class UnfinishedMixingAction < MixingAction
@slots[vial_slot] = 1 @slots[vial_slot] = 1
@slots[herb_slot] = 1 @slots[herb_slot] = 1
return true true
end end
end end
# A MixingAction which handles the execution of making FinishedPotions. # A MixingAction which handles the execution of making FinishedPotions.
@@ -262,13 +269,12 @@ class FinishedMixingAction < MixingAction
attr_reader :unfinished, :ingredient, :slots attr_reader :unfinished, :ingredient, :slots
def initialize(player, unfinished, ingredient, potion) def initialize(player, unfinished, ingredient, potion)
super(player, potion, "mix this potion") super(player, potion, 'mix this potion')
@unfinished = unfinished @unfinished = unfinished
@ingredient = ingredient @ingredient = ingredient
end end
def execute_action def executeAction
player = mob player = mob
ingredient = name_of(@ingredient).downcase ingredient = name_of(@ingredient).downcase
name = @potion.item.definition.name.sub('(3)', '') name = @potion.item.definition.name.sub('(3)', '')
@@ -279,7 +285,7 @@ class FinishedMixingAction < MixingAction
inventory = player.inventory inventory = player.inventory
@slots.each do |slot, amount| @slots.each do |slot, amount|
if not inventory.remove_slot(slot, amount) unless inventory.remove_slot(slot, amount) # TODO: will this remove stuff incorrectly?
stop stop
return return
end end
@@ -307,60 +313,59 @@ class FinishedMixingAction < MixingAction
@slots[vial_slot] = 1 @slots[vial_slot] = 1
@slots[ingredient_slot] = 1 @slots[ingredient_slot] = 1
return true true
end end
end end
# Appends a finished potion to the ItemOnItemMessage handling interception. # Appends a finished potion to the ItemOnItemMessage handling interception.
def append_finished_potion(item, unfinished, ingredient, level, experience) def finished_potion(item, unfinished, ingredient, level, experience)
potion = FinishedPotion.new(item, [ unfinished, ingredient ], level, experience) potion = FinishedPotion.new(item, [unfinished, ingredient], level, experience)
append_herblore_item(potion, unfinished.item_id, ingredient.item_id) append_herblore_item(potion, unfinished.item_id, ingredient.item_id)
return potion potion
end end
# Appends an unfinished potion to the ItemOnItemMessage handling interception. # Appends an unfinished potion to the ItemOnItemMessage handling interception.
def append_unfinished_potion(item, herb, level) def unfinished_potion(item, herb, level)
potion = UnfinishedPotion.new(item, herb, level) potion = UnfinishedPotion.new(item, herb, level)
append_herblore_item(potion, herb.item_id, WATER_VIAL_ID) append_herblore_item(potion, herb.item_id, WATER_VIAL_ID)
return potion potion
end end
# Unfinished potions # Unfinished potions
UNF_GUAM = append_unfinished_potion(91, GUAM_LEAF, 1) # 3 UNF_GUAM = unfinished_potion(91, GUAM_LEAF, 1) # 3
UNF_MARRENTILL = append_unfinished_potion(93, MARRENTILL, 5) UNF_MARRENTILL = unfinished_potion(93, MARRENTILL, 5)
UNF_TARROMIN = append_unfinished_potion(95, TARROMIN, 12) UNF_TARROMIN = unfinished_potion(95, TARROMIN, 12)
UNF_HARRALANDER = append_unfinished_potion(97, HARRALANDER, 22) UNF_HARRALANDER = unfinished_potion(97, HARRALANDER, 22)
UNF_RANARR = append_unfinished_potion(99, RANARR, 30) UNF_RANARR = unfinished_potion(99, RANARR, 30)
UNF_TOADFLAX = append_unfinished_potion(3002, TOADFLAX, 34) UNF_TOADFLAX = unfinished_potion(3002, TOADFLAX, 34)
UNF_IRIT = append_unfinished_potion(101, IRIT_LEAF, 45) UNF_IRIT = unfinished_potion(101, IRIT_LEAF, 45)
UNF_AVANTOE = append_unfinished_potion(103, AVANTOE, 50) UNF_AVANTOE = unfinished_potion(103, AVANTOE, 50)
UNF_KWUARM = append_unfinished_potion(105, KWUARM, 55) UNF_KWUARM = unfinished_potion(105, KWUARM, 55)
UNF_SNAPDRAGON = append_unfinished_potion(3004, SNAPDRAGON, 63) UNF_SNAPDRAGON = unfinished_potion(3004, SNAPDRAGON, 63)
UNF_CADANTINE = append_unfinished_potion(107, CADANTINE, 66) UNF_CADANTINE = unfinished_potion(107, CADANTINE, 66)
UNF_LANTADYME = append_unfinished_potion(2483, LANTADYME, 69) UNF_LANTADYME = unfinished_potion(2483, LANTADYME, 69)
UNF_DWARF_WEED = append_unfinished_potion(109, DWARF_WEED, 72) UNF_DWARF_WEED = unfinished_potion(109, DWARF_WEED, 72)
UNF_TORSTOL = append_unfinished_potion(111, TORSTOL, 78) UNF_TORSTOL = unfinished_potion(111, TORSTOL, 78)
# Finished potions # Finished potions
ATTACK_POT = append_finished_potion(121, UNF_GUAM, EYE_NEWT, 1, 25) # 3, 25 ATTACK_POT = finished_potion(121, UNF_GUAM, EYE_NEWT, 1, 25) # 3
ANTIPOISON_POT = append_finished_potion(175, UNF_MARRENTILL, UNICORN_HORN_DUST, 5, 37.5) ANTIPOISON_POT = finished_potion(175, UNF_MARRENTILL, UNICORN_HORN_DUST, 5, 37.5)
STRENGTH_POT = append_finished_potion(115, UNF_TARROMIN, LIMPWURT_ROOT, 12, 50) STRENGTH_POT = finished_potion(115, UNF_TARROMIN, LIMPWURT_ROOT, 12, 50)
RESTORE_POT = append_finished_potion(127, UNF_HARRALANDER, RED_SPIDERS_EGGS, 18, 62.5) RESTORE_POT = finished_potion(127, UNF_HARRALANDER, RED_SPIDERS_EGGS, 18, 62.5)
ENERGY_POT = append_finished_potion(3010, UNF_HARRALANDER, CHOCOLATE_DUST, 26, 67.5) ENERGY_POT = finished_potion(3010, UNF_HARRALANDER, CHOCOLATE_DUST, 26, 67.5)
DEFENCE_POT = append_finished_potion(133, UNF_RANARR, WHITE_BERRIES, 30, 75) DEFENCE_POT = finished_potion(133, UNF_RANARR, WHITE_BERRIES, 30, 75)
AGILITY_POT = append_finished_potion(3034, UNF_TOADFLAX, TOADS_LEGS, 34, 80) AGILITY_POT = finished_potion(3034, UNF_TOADFLAX, TOADS_LEGS, 34, 80)
PRAYER_POT = append_finished_potion(139, UNF_RANARR, SNAPE_GRASS, 38, 87.5) PRAYER_POT = finished_potion(139, UNF_RANARR, SNAPE_GRASS, 38, 87.5)
SUPER_ATTACK_POT = append_finished_potion(145, UNF_IRIT, EYE_NEWT, 45, 100) SUPER_ATTACK_POT = finished_potion(145, UNF_IRIT, EYE_NEWT, 45, 100)
SUPER_ANTIPOISON_POT = append_finished_potion(181, UNF_IRIT, UNICORN_HORN_DUST, 48, 106.3) SUPER_ANTIPOISON_POT = finished_potion(181, UNF_IRIT, UNICORN_HORN_DUST, 48, 106.3)
FISHING_POT = append_finished_potion(151, UNF_AVANTOE, SNAPE_GRASS, 50, 112.5) FISHING_POT = 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_ENERGY_POT = finished_potion(3018, UNF_AVANTOE, MORT_MYRE_FUNGI, 52, 117.5)
SUPER_STRENGTH_POT = append_finished_potion(157, UNF_KWUARM, LIMPWURT_ROOT, 55, 125) SUPER_STRENGTH_POT = finished_potion(157, UNF_KWUARM, LIMPWURT_ROOT, 55, 125)
WEAPON_POISON = append_finished_potion(187, UNF_KWUARM, DRAGON_SCALE_DUST, 60, 137.5) WEAPON_POISON = 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_RESTORE_POT = finished_potion(3026, UNF_SNAPDRAGON, RED_SPIDERS_EGGS, 63, 142.5)
SUPER_DEFENCE_POT = append_finished_potion(163, UNF_CADANTINE, WHITE_BERRIES, 66, 150) SUPER_DEFENCE_POT = finished_potion(163, UNF_CADANTINE, WHITE_BERRIES, 66, 150)
ANTIFIRE_POT = append_finished_potion(2428, UNF_LANTADYME, DRAGON_SCALE_DUST, 69, 157.5) ANTIFIRE_POT = 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) RANGING_POT = finished_potion(169, UNF_DWARF_WEED, WINE_ZAMORAK, 72, 162.5)
MAGIC_POT = append_finished_potion(3042, UNF_LANTADYME, POTATO_CACTUS, 76, 172.5) MAGIC_POT = finished_potion(3042, UNF_LANTADYME, POTATO_CACTUS, 76, 172.5)
ZAMORAK_BREW = append_finished_potion(189, UNF_TORSTOL, JANGERBERRIES, 78, 175) ZAMORAK_BREW = finished_potion(189, UNF_TORSTOL, JANGERBERRIES, 78, 175)
+36 -21
View File
@@ -2,33 +2,26 @@ require 'java'
java_import 'org.apollo.game.model.Animation' java_import 'org.apollo.game.model.Animation'
java_import 'org.apollo.game.model.Graphic' java_import 'org.apollo.game.model.Graphic'
java_import 'org.apollo.game.model.entity.Skill'
ALCHEMY_SPELLS = {} ALCHEMY_SPELLS = {}
LOW_ALCH_ANIM = Animation.new(712) ILLEGAL_ALCH_ITEMS = [995, 6529, 6306, 6307, 6308, 6309, 6310]
LOW_ALCH_GRAPHIC = Graphic.new(112, 0, 100)
LOW_ALCH_MULTIPLIER = 0.4
HIGH_ALCH_ANIM = Animation.new(713)
HIGH_ALCH_GRAPHIC = Graphic.new(113, 0, 100)
HIGH_ALCH_MULTIPLIER = 0.6
ILLEGAL_ALCH_ITEMS = [ 995, 6529, 6306, 6307, 6308, 6309, 6310 ]
# A spell that alchemises an item.
class AlchemySpell < Spell class AlchemySpell < Spell
attr_reader :high, :animation, :graphic, :multiplier, :experience, :delay attr_reader :animation, :graphic, :multiplier, :experience
def initialize(level, elements, high, animation, graphic, multiplier, experience, delay) def initialize(level, elements, experience, animation, graphic, multiplier)
super(level, elements, experience) super(level, elements, experience)
@high = high
@animation = animation @animation = animation
@graphic = graphic @graphic = graphic
@multiplier = multiplier @multiplier = multiplier
@delay = delay
end end
end end
# An Action that performs an AlchemySpell.
class AlchemyAction < ItemSpellAction class AlchemyAction < ItemSpellAction
def initialize(player, alchemy, slot, item) def initialize(player, alchemy, slot, item)
@@ -36,10 +29,10 @@ class AlchemyAction < ItemSpellAction
end end
def illegal_item? def illegal_item?
return ILLEGAL_ALCH_ITEMS.include?(@item.id) ILLEGAL_ALCH_ITEMS.include?(@item.id)
end end
def execute_action def executeAction
if @pulses == 0 if @pulses == 0
mob.play_animation(@spell.animation) mob.play_animation(@spell.animation)
mob.play_graphic(@spell.graphic) mob.play_graphic(@spell.graphic)
@@ -51,8 +44,8 @@ class AlchemyAction < ItemSpellAction
inventory.remove(inventory.get(@slot).id, 1) inventory.remove(inventory.get(@slot).id, 1)
inventory.add(995, gold) inventory.add(995, gold)
mob.skill_set.add_experience(MAGIC_SKILL_ID, @spell.experience) mob.skill_set.add_experience(Skill::MAGIC, @spell.experience)
set_delay(@spell.delay) set_delay(ALCHEMY_DELAY)
elsif @pulses == 1 elsif @pulses == 1
mob.stop_animation mob.stop_animation
mob.stop_graphic mob.stop_graphic
@@ -62,9 +55,31 @@ class AlchemyAction < ItemSpellAction
end end
def append_alchemy(button, level, elements, high, animation, graphic, multiplier, experience, delay) private
ALCHEMY_SPELLS[button] = AlchemySpell.new(level, elements, high, animation, graphic, multiplier, experience, delay)
# The delay of an alchemy spell.
ALCHEMY_DELAY = 4
# The height of the graphic.
GRAPHIC_HEIGHT = 100
# Inserts an `AlchemySpell` into the hash of available alchemy spells.
def alchemy(_name, hash)
unless hash.has_keys?(:button, :level, :runes, :animation, :graphic, :multiplier, :experience)
fail 'Hash must have button, level, runes, animation, graphic, multiplier, experience keys.'
end
id, multiplier = hash[:button], hash[:multiplier]
level, runes, experience = hash[:level], hash[:runes], hash[:experience]
animation = Animation.new(hash[:animation])
graphic = Graphic.new(hash[:graphic], 0, GRAPHIC_HEIGHT)
ALCHEMY_SPELLS[id] = AlchemySpell.new(level, runes, experience, animation, graphic, multiplier)
end end
append_alchemy(1162, 21, { FIRE => 3, NATURE => 1 }, false, LOW_ALCH_ANIM, LOW_ALCH_GRAPHIC, 0.48, 31, 1) # Low level alchemy alchemy :low_level, button: 1_162, level: 21, runes: { FIRE => 3, NATURE => 1 }, animation: 712,
append_alchemy(1178, 55, { FIRE => 5, NATURE => 1 }, true, HIGH_ALCH_ANIM, HIGH_ALCH_GRAPHIC, 0.72, 65, 4) # High level alchemy graphic: 112, multiplier: 0.48, experience: 31
alchemy :high_level, button: 1_178, level: 55, runes: { FIRE => 5, NATURE => 1 }, animation: 713,
graphic: 113, multiplier: 0.72, experience: 65
+12 -10
View File
@@ -3,6 +3,7 @@ require 'java'
java_import 'org.apollo.game.model.Animation' java_import 'org.apollo.game.model.Animation'
java_import 'org.apollo.game.model.Graphic' java_import 'org.apollo.game.model.Graphic'
java_import 'org.apollo.game.model.Item' java_import 'org.apollo.game.model.Item'
java_import 'org.apollo.game.model.entity.Skill'
CONVERT_SPELLS = {} CONVERT_SPELLS = {}
BONES_ID = 526 BONES_ID = 526
@@ -10,6 +11,7 @@ BONES_ID = 526
CONVERT_ANIM = Animation.new(722) CONVERT_ANIM = Animation.new(722)
CONVERT_GRAPHIC = Graphic.new(141, 0, 100) CONVERT_GRAPHIC = Graphic.new(141, 0, 100)
# A `Spell` for converting items.
class ConvertSpell < Spell class ConvertSpell < Spell
attr_reader :reward attr_reader :reward
@@ -20,6 +22,7 @@ class ConvertSpell < Spell
end end
# A `SpellAction` for a `ConvertSpell`.
class ConvertingAction < SpellAction class ConvertingAction < SpellAction
attr_reader :slots attr_reader :slots
@@ -36,19 +39,17 @@ class ConvertingAction < SpellAction
inventory = mob.inventory inventory = mob.inventory
firing = (@slots.length * 2) < inventory.capacity firing = (@slots.length * 2) < inventory.capacity
inventory.stop_firing_events unless firing # In the case of many changes, wait with firing events inventory.stop_firing_events unless firing # In case of many changes, wait with firing events
reward = @spell.reward reward = @spell.reward
@slots.each do |slot| @slots.each { |slot| inventory.set(slot, reward) }
inventory.set(slot, reward) # Share the instance
end
unless firing # If we waited with firing events, restore it now and force a refresh unless firing # If we waited with firing events, restore it now and force a refresh
inventory.start_firing_events inventory.start_firing_events
inventory.force_refresh inventory.force_refresh
end end
mob.skill_set.add_experience(MAGIC_SKILL_ID, @spell.experience) mob.skill_set.add_experience(Skill::MAGIC, @spell.experience)
set_delay(2) set_delay(2)
elsif @pulses == 1 elsif @pulses == 1
mob.stop_animation mob.stop_animation
@@ -66,21 +67,22 @@ def bone_slots(player)
counter = 0 counter = 0
slots = [] slots = []
(0...inventory.capacity).each do |slot| (0...inventory.capacity).each do |slot|
break unless counter <= size break unless counter <= size
item = items[slot] item = items[slot]
slots << slot if (item != nil and item.id == BONES_ID) slots << slot if !item.nil? && item.id == BONES_ID
counter += 1 counter += 1
end end
return slots slots
end end
def append_convert(button, level, elements, experience, reward) def convert(button, level, elements, experience, reward)
CONVERT_SPELLS[button] = ConvertSpell.new(level, elements, experience, reward) CONVERT_SPELLS[button] = ConvertSpell.new(level, elements, experience, reward)
end end
append_convert 1159, 15, { EARTH => 2, WATER => 2, NATURE => 1 }, 25, 1963 # Bones to bananas convert 1159, 15, { EARTH => 2, WATER => 2, NATURE => 1 }, 25, 1963 # Bones to bananas
#append_convert 15877, 60, { NATURE => 2, WATER => 4, EARTH => 4 }, 35.5, 6883 # Bones to peaches # convert 15877, 60, { NATURE => 2, WATER => 4, EARTH => 4 }, 35.5, 6883 # Bones to peaches
+27 -32
View File
@@ -29,10 +29,11 @@ MUD_RUNE = 4698
STEAM_RUNE = 4694 STEAM_RUNE = 4694
LAVA_RUNE = 4699 LAVA_RUNE = 4699
# An element of a spell.
class Element class Element
attr_reader :runes, :staffs, :name attr_reader :runes, :staffs, :name
def initialize(runes, staffs, name="Null") def initialize(runes, staffs, name = 'Null')
@runes = runes @runes = runes
@staffs = staffs @staffs = staffs
@name = name @name = name
@@ -40,10 +41,8 @@ class Element
def check_remove(player, amount, remove) def check_remove(player, amount, remove)
weapon = player.equipment.get(EquipmentConstants::WEAPON) weapon = player.equipment.get(EquipmentConstants::WEAPON)
if @staffs != nil && weapon != nil unless @staffs.nil? || weapon.nil?
@staffs.each do |staff| @staffs.each { |staff| return true if weapon.id == staff }
return true if weapon.id == staff
end
end end
inventory = player.inventory inventory = player.inventory
@@ -53,7 +52,7 @@ class Element
inventory.items.each do |item| inventory.items.each do |item|
break unless counter < amount break unless counter < amount
next if item == nil next if item.nil?
amt = item.amount amt = item.amount
@runes.each do |rune| @runes.each do |rune|
@@ -73,40 +72,36 @@ class Element
end end
if counter >= amount if counter >= amount
if remove found.each { |id, amt| inventory.remove(id, amt) } if remove
found.each do |id, amt|
inventory.remove(id, amt)
end
end
return true return true
end end
return false false
end end
end end
AIR_RUNES = [ 556, 4695, 4696, 4697 ] AIR_RUNES = [556, 4695, 4696, 4697]
WATER_RUNES = [ 555, 4695, 4698, 4694 ] WATER_RUNES = [555, 4695, 4698, 4694]
EARTH_RUNES = [ 557, 4696, 4697, 4698 ] EARTH_RUNES = [557, 4696, 4697, 4698]
FIRE_RUNES = [ 554, 4697, 4694, 4699 ] FIRE_RUNES = [554, 4697, 4694, 4699]
AIR_STAFFS = [ 1381, 1397, 1405 ] AIR_STAFFS = [1381, 1397, 1405]
WATER_STAFFS = [ 1383, 1395, 1403 ] WATER_STAFFS = [1383, 1395, 1403]
EARTH_STAFFS = [ 1385, 1399, 1407, 3053, 3054 ] EARTH_STAFFS = [1385, 1399, 1407, 3053, 3054]
FIRE_STAFFS = [ 1387, 1393, 1401, 3053, 3054 ] FIRE_STAFFS = [1387, 1393, 1401, 3053, 3054]
AIR = Element.new(AIR_RUNES, AIR_STAFFS, "Air rune") AIR = Element.new(AIR_RUNES, AIR_STAFFS, 'Air rune')
WATER = Element.new(WATER_RUNES, WATER_STAFFS, "Water rune") WATER = Element.new(WATER_RUNES, WATER_STAFFS, 'Water rune')
EARTH = Element.new(EARTH_RUNES, EARTH_STAFFS, "Earth rune") EARTH = Element.new(EARTH_RUNES, EARTH_STAFFS, 'Earth rune')
FIRE = Element.new(FIRE_RUNES, FIRE_STAFFS, "Fire rune") FIRE = Element.new(FIRE_RUNES, FIRE_STAFFS, 'Fire rune')
MIND = Element.new([MIND_RUNE], nil, "Mind rune") MIND = Element.new([MIND_RUNE], nil, 'Mind rune')
CHAOS = Element.new([CHAOS_RUNE], nil, "Chaos rune") CHAOS = Element.new([CHAOS_RUNE], nil, 'Chaos rune')
DEATH = Element.new([DEATH_RUNE], nil, "Death rune") DEATH = Element.new([DEATH_RUNE], nil, 'Death rune')
BLOOD = Element.new([BLOOD_RUNE], nil, "Blood rune") BLOOD = Element.new([BLOOD_RUNE], nil, 'Blood rune')
COSMIC = Element.new([COSMIC_RUNE], nil, "Cosmic rune") COSMIC = Element.new([COSMIC_RUNE], nil, 'Cosmic rune')
LAW = Element.new([LAW_RUNE], nil, "Law rune") LAW = Element.new([LAW_RUNE], nil, 'Law rune')
NATURE = Element.new([NATURE_RUNE], nil, "Nature rune") NATURE = Element.new([NATURE_RUNE], nil, 'Nature rune')
SOUL = Element.new([SOUL_RUNE], nil, "Soul rune") SOUL = Element.new([SOUL_RUNE], nil, 'Soul rune')
+20 -22
View File
@@ -8,7 +8,7 @@ ENCHANT_SPELLS = {}
ENCHANT_ITEMS = {} ENCHANT_ITEMS = {}
RING_GFX = Graphic.new(238, 0, 100) RING_GFX = Graphic.new(238, 0, 100)
RING_ANIM = Animation.new(713) # TODO: No way we need one of the alchemy anims for enchanting... RING_ANIM = Animation.new(713) # TODO: an alchemy animation for enchanting?
LOW_NECK_GFX = Graphic.new(114, 0, 100) LOW_NECK_GFX = Graphic.new(114, 0, 100)
LOW_NECK_ANIM = Animation.new(719) LOW_NECK_ANIM = Animation.new(719)
@@ -21,6 +21,7 @@ HIGH_NECK_ANIM = Animation.new(721)
ONYX_NECK_GFX = Graphic.new(452, 0, 100) ONYX_NECK_GFX = Graphic.new(452, 0, 100)
# A `Spell` for enchanting an item.
class EnchantSpell < Spell class EnchantSpell < Spell
attr_reader :button, :animation, :graphic, :delay attr_reader :button, :animation, :graphic, :delay
@@ -34,6 +35,7 @@ class EnchantSpell < Spell
end end
# A `SpellAction` for an `EnchantSpell`.
class EnchantAction < ItemSpellAction class EnchantAction < ItemSpellAction
attr_reader :reward attr_reader :reward
@@ -43,10 +45,10 @@ class EnchantAction < ItemSpellAction
end end
def illegal_item? def illegal_item?
return ENCHANT_ITEMS[@item.id] == nil ENCHANT_ITEMS[@item.id].nil?
end end
def execute_action def executeAction
if @pulses == 0 if @pulses == 0
mob.play_animation(@spell.animation) mob.play_animation(@spell.animation)
mob.play_graphic(@spell.graphic) mob.play_graphic(@spell.graphic)
@@ -65,7 +67,7 @@ class EnchantAction < ItemSpellAction
end end
def append_enchant(button, level, elements, item, animation, graphic, delay, experience, reward) def enchant(button, level, elements, item, animation, graphic, delay, experience, reward)
enchant = EnchantSpell.new(button, level, elements, animation, graphic, delay, experience) enchant = EnchantSpell.new(button, level, elements, animation, graphic, delay, experience)
ENCHANT_SPELLS[item] = enchant ENCHANT_SPELLS[item] = enchant
ENCHANT_ITEMS[item] = reward ENCHANT_ITEMS[item] = reward
@@ -79,31 +81,27 @@ DSTONE_ELEMENTS = { WATER => 15, EARTH => 15, COSMIC => 1 }
ONYX_ELEMENTS = { EARTH => 20, FIRE => 20, COSMIC => 1 } ONYX_ELEMENTS = { EARTH => 20, FIRE => 20, COSMIC => 1 }
# Sapphire # Sapphire
append_enchant 1155, 7, SAPPHIRE_ELEMENTS, 1637, RING_ANIM, RING_GFX, 2, 17.5, 2550 # Ring enchant 1155, 7, SAPPHIRE_ELEMENTS, 1637, RING_ANIM, RING_GFX, 2, 17.5, 2550 # Ring
append_enchant 1155, 7, SAPPHIRE_ELEMENTS, 1656, LOW_NECK_ANIM, LOW_NECK_GFX, 1, 17.5, 3853 # Necklace enchant 1155, 7, SAPPHIRE_ELEMENTS, 1656, LOW_NECK_ANIM, LOW_NECK_GFX, 1, 17.5, 3853 # Necklace
append_enchant 1155, 7, SAPPHIRE_ELEMENTS, 1692, LOW_NECK_ANIM, LOW_NECK_GFX, 1, 17.5, 1727 # Amulet enchant 1155, 7, SAPPHIRE_ELEMENTS, 1692, LOW_NECK_ANIM, LOW_NECK_GFX, 1, 17.5, 1727 # Amulet
# Emerald # Emerald
append_enchant 1165, 27, EMERALD_ELEMENTS, 1639, RING_ANIM, RING_GFX, 2, 37, 2552 # Ring enchant 1165, 27, EMERALD_ELEMENTS, 1639, RING_ANIM, RING_GFX, 2, 37, 2552 # Ring
append_enchant 1165, 27, EMERALD_ELEMENTS, 1658, LOW_NECK_ANIM, LOW_NECK_GFX, 1, 37, 5521 # Necklace enchant 1165, 27, EMERALD_ELEMENTS, 1658, LOW_NECK_ANIM, LOW_NECK_GFX, 1, 37, 5521 # Necklace
append_enchant 1165, 27, EMERALD_ELEMENTS, 1696, LOW_NECK_ANIM, LOW_NECK_GFX, 1, 37, 1729 # Amulet enchant 1165, 27, EMERALD_ELEMENTS, 1696, LOW_NECK_ANIM, LOW_NECK_GFX, 1, 37, 1729 # Amulet
# Ruby # Ruby
append_enchant 1176, 49, RUBY_ELEMENTS, 1641, RING_ANIM, RING_GFX, 2, 59, 2568 # Ring enchant 1176, 49, RUBY_ELEMENTS, 1641, RING_ANIM, RING_GFX, 2, 59, 2568 # Ring
# append_enchant 1176, 49, RUBY_ELEMENTS, 1660, MED_NECK_ANIM, MED_NECK_GFX, 2, 59, # Necklace - not found in 317 or 377 enchant 1176, 49, RUBY_ELEMENTS, 1698, MED_NECK_ANIM, MED_NECK_GFX, 2, 59, 1725 # Amulet
append_enchant 1176, 49, RUBY_ELEMENTS, 1698, MED_NECK_ANIM, MED_NECK_GFX, 2, 59, 1725 # Amulet
# Diamond # Diamond
append_enchant 1180, 57, DIAMOND_ELEMENTS, 1643, RING_ANIM, RING_GFX, 2, 67, 2570 # Ring enchant 1180, 57, DIAMOND_ELEMENTS, 1643, RING_ANIM, RING_GFX, 2, 67, 2570 # Ring
# append_enchant 1180, 57, DIAMOND_ELEMENTS, 1662, MED_NECK_ANIM, MED_NECK_GFX, 2, 67, # Necklace - not found in 317 or 377 enchant 1180, 57, DIAMOND_ELEMENTS, 1700, MED_NECK_ANIM, MED_NECK_GFX, 2, 67, 1731 # Amulet
append_enchant 1180, 57, DIAMOND_ELEMENTS, 1700, MED_NECK_ANIM, MED_NECK_GFX, 2, 67, 1731 # Amulet
# Dragonstone # Dragonstone
append_enchant 1187, 68, DSTONE_ELEMENTS, 1645, RING_ANIM, RING_GFX, 2, 78, 2572 # Ring enchant 1187, 68, DSTONE_ELEMENTS, 1645, RING_ANIM, RING_GFX, 2, 78, 2572 # Ring
# append_enchant 1187, 68, DSTONE_ELEMENTS, 1664, HIGH_NECK_ANIM, HIGH_NECK_GFX, 3, 78, # Necklace - not found in 317 or 377 enchant 1187, 68, DSTONE_ELEMENTS, 1702, HIGH_NECK_ANIM, HIGH_NECK_GFX, 3, 78, 1712 # Amulet
append_enchant 1187, 68, DSTONE_ELEMENTS, 1702, HIGH_NECK_ANIM, HIGH_NECK_GFX, 3, 78, 1712 # Amulet
# Onyx # Onyx
append_enchant 6003, 87, ONYX_ELEMENTS, 6575, RING_ANIM, RING_GFX, 2, 97, 6583 # Ring enchant 6003, 87, ONYX_ELEMENTS, 6575, RING_ANIM, RING_GFX, 2, 97, 6583 # Ring
# append_enchant 6003, 87, ONYX_ELEMENTS, 6577, HIGH_NECK_ANIM, ONYX_NECK_GFX, 3, 97, # Necklace - not found in 317 or 377 enchant 6003, 87, ONYX_ELEMENTS, 6581, HIGH_NECK_ANIM, ONYX_NECK_GFX, 2, 97, 6585 # Amulet
append_enchant 6003, 87, ONYX_ELEMENTS, 6581, HIGH_NECK_ANIM, ONYX_NECK_GFX, 2, 97, 6585 # Amulet
+19 -10
View File
@@ -5,8 +5,10 @@ java_import 'org.apollo.game.message.impl.DisplayTabInterfaceMessage'
java_import 'org.apollo.game.model.entity.EquipmentConstants' java_import 'org.apollo.game.model.entity.EquipmentConstants'
java_import 'org.apollo.game.model.entity.Skill' java_import 'org.apollo.game.model.entity.Skill'
# A `Message` to display the magic spellbook.
DISPLAY_SPELLBOOK = DisplayTabInterfaceMessage.new(6) DISPLAY_SPELLBOOK = DisplayTabInterfaceMessage.new(6)
# A spell that can be cast.
class Spell class Spell
attr_reader :level, :elements, :experience attr_reader :level, :elements, :experience
@@ -18,23 +20,24 @@ class Spell
end end
# An `Action` for casting a `Spell`.
class SpellAction < Action class SpellAction < Action
attr_reader :spell, :pulses attr_reader :spell, :pulses
def initialize(mob, spell) def initialize(mob, spell)
super(0, true, mob) super(0, true, mob)
@spell = spell @spell = spell
@pulses = 0 @pulses = 0
end end
def execute def execute
if @pulses == 0 if @pulses == 0
unless (check_skill and process_elements) unless check_skill && process_elements
stop stop
return return
end end
end end
execute_action execute_action
@pulses += 1 @pulses += 1
end end
@@ -50,7 +53,7 @@ class SpellAction < Action
return false return false
end end
return true true
end end
def process_elements def process_elements
@@ -64,16 +67,16 @@ class SpellAction < Action
end end
elements.each { |element, amount| element.check_remove(mob, amount, true) } elements.each { |element, amount| element.check_remove(mob, amount, true) }
true
return true
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @spell == other.spell) get_class == other.get_class && @spell == other.spell
end end
end end
# A `SpellAction` that verifies an input `Item` is legal.
class ItemSpellAction < SpellAction class ItemSpellAction < SpellAction
attr_reader :slot, :item attr_reader :slot, :item
@@ -112,7 +115,7 @@ class ItemSpellAction < SpellAction
def illegal_item? def illegal_item?
# Override this method if necessary # Override this method if necessary
return false false
end end
end end
@@ -131,7 +134,7 @@ on :message, :magic_on_item do |player, message|
end end
ench = ENCHANT_SPELLS[message.id] ench = ENCHANT_SPELLS[message.id]
if !ench.nil? and ench.button == spell if !ench.nil? && ench.button == spell
slot = message.slot slot = message.slot
item = player.inventory.get(slot) item = player.inventory.get(slot)
player.start_action(EnchantAction.new(player, ench, slot, item, ENCHANT_ITEMS[item.id])) player.start_action(EnchantAction.new(player, ench, slot, item, ENCHANT_ITEMS[item.id]))
@@ -152,9 +155,15 @@ on :message, :button do |player, message|
conv = CONVERT_SPELLS[button] conv = CONVERT_SPELLS[button]
unless conv.nil? unless conv.nil?
slots = bone_slots player slots = bone_slots(player)
if slots.length == 0
player.send_message("You can't convert these bones!")
else
player.start_action(ConvertingAction.new(player, conv, slots))
end
if slots.length == 0 then player.send_message("You can't convert these bones!") else player.start_action(ConvertingAction.new(player, conv, slots)) end
message.terminate message.terminate
end end
end end
+32 -22
View File
@@ -1,10 +1,12 @@
# Thanks to phl0w <http://www.rune-server.org/members/phl0w/> for providing # Thanks to phl0w <http://www.rune-server.org/members/phl0w> for providing
# the correct destination coordinates of the ancient teleports. # the correct destination coordinates of the ancient teleports.
require 'java' require 'java'
java_import 'org.apollo.game.model.Animation' java_import 'org.apollo.game.model.Animation'
java_import 'org.apollo.game.model.Graphic' java_import 'org.apollo.game.model.Graphic'
java_import 'org.apollo.game.model.Position' java_import 'org.apollo.game.model.Position'
java_import 'org.apollo.game.model.entity.Skill'
TELEPORT_SPELLS = {} TELEPORT_SPELLS = {}
@@ -16,6 +18,7 @@ ANCIENT_TELE_END_GRAPHIC = Graphic.new(455)
ANCIENT_TELE_ANIM = Animation.new(1979) ANCIENT_TELE_ANIM = Animation.new(1979)
ANCIENT_TELE_GRAPHIC = Graphic.new(392) ANCIENT_TELE_GRAPHIC = Graphic.new(392)
# A `Spell` that teleports a `Player` to another `Position`.
class TeleportSpell < Spell class TeleportSpell < Spell
attr_reader :ancient, :destination, :experience, :name attr_reader :ancient, :destination, :experience, :name
@@ -28,6 +31,7 @@ class TeleportSpell < Spell
end end
# A `SpellAction` for a `TeleportSpell`.
class TeleportingAction < SpellAction class TeleportingAction < SpellAction
def initialize(mob, spell) def initialize(mob, spell)
@@ -43,7 +47,7 @@ class TeleportingAction < SpellAction
mob.play_animation(MODERN_TELE_ANIM) mob.play_animation(MODERN_TELE_ANIM)
elsif @pulses == 1 elsif @pulses == 1
mob.play_graphic(MODERN_TELE_GRAPHIC) mob.play_graphic(MODERN_TELE_GRAPHIC)
delay = 1 set_delay(1)
elsif @pulses == 2 elsif @pulses == 2
mob.stop_graphic mob.stop_graphic
mob.play_animation(MODERN_TELE_END_ANIM) mob.play_animation(MODERN_TELE_END_ANIM)
@@ -57,38 +61,44 @@ class TeleportingAction < SpellAction
if @pulses == 0 if @pulses == 0
mob.play_graphic(ANCIENT_TELE_GRAPHIC) mob.play_graphic(ANCIENT_TELE_GRAPHIC)
mob.play_animation(ANCIENT_TELE_ANIM) mob.play_animation(ANCIENT_TELE_ANIM)
delay = 2 set_delay(2)
elsif @pulses == 2 elsif @pulses == 2
mob.stop_graphic mob.stop_graphic
mob.stop_animation mob.stop_animation
mob.teleport(@spell.destination) mob.teleport(@spell.destination)
mob.skill_set.add_experience(MAGIC_SKILL_ID, @spell.experience) mob.skill_set.add_experience(Skill::MAGIC, @spell.experience)
stop stop
end end
end end
end end
def append_tele(ancient, button, level, elements, x, y, experience, name) def tele(ancient = false, button, level, elements, x, y, experience, name)
TELEPORT_SPELLS[button] = TeleportSpell.new(ancient, level, elements, Position.new(x, y), experience, name) position = Position.new(x, y)
TELEPORT_SPELLS[button] = TeleportSpell.new(ancient, level, elements, position, experience, name)
end
def ancient_tele(*args)
tele(true, *args)
end end
# Modern teleports # Modern teleports
append_tele(false, 1164, 25, { FIRE => 1, AIR => 3, LAW => 1 }, 3213, 3424, 35, "Varrock") tele 1_164, 25, { FIRE => 1, AIR => 3, LAW => 1 }, 3213, 3424, 35, 'Varrock'
append_tele(false, 1167, 31, { EARTH => 1, AIR => 3, LAW => 1 }, 3222, 3219, 41, "Lumbridge") tele 1_167, 31, { EARTH => 1, AIR => 3, LAW => 1 }, 3222, 3219, 41, 'Lumbridge'
append_tele(false, 1170, 37, { WATER => 1, AIR => 3, LAW => 1 }, 2965, 3379, 47, "Falador") tele 1_170, 37, { WATER => 1, AIR => 3, LAW => 1 }, 2965, 3379, 47, 'Falador'
append_tele(false, 1174, 45, { AIR => 5, LAW => 1 }, 2757, 3478, 55.5, "Camelot") tele 1_174, 45, { AIR => 5, LAW => 1 }, 2757, 3478, 55.5, 'Camelot'
append_tele(false, 1540, 51, { WATER => 2, LAW => 2 }, 2662, 3306, 61, "Ardougne") tele 1_540, 51, { WATER => 2, LAW => 2 }, 2662, 3306, 61, 'Ardougne'
append_tele(false, 1541, 58, { EARTH => 2, LAW => 2 }, 2549, 3114, 68, "the Watchtower") tele 1_541, 58, { EARTH => 2, LAW => 2 }, 2549, 3114, 68, 'the Watchtower'
append_tele(false, 7455, 61, { FIRE => 2, LAW => 2 }, 2871, 3590, 68, "Trollheim") tele 7_455, 61, { FIRE => 2, LAW => 2 }, 2871, 3590, 68, 'Trollheim'
append_tele(false, 18470, 64, { FIRE => 2, WATER => 2, LAW => 2, Element.new([1963], nil, "Banana") => 1 }, 2754, 2785, 76, "Ape Atoll") tele 18_470, 64, { FIRE => 2, WATER => 2, LAW => 2, Element.new([1963], nil, 'Banana') => 1 },
2_754, 2_785, 76, 'Ape Atoll'
# Ancient teleports # Ancient teleports
append_tele(true, 13035, 54, { LAW => 2, FIRE => 1, AIR => 1 }, 3098, 9882, 64, "Paddewwa") ancient_tele 13_035, 54, { LAW => 2, FIRE => 1, AIR => 1 }, 3098, 9882, 64, 'Paddewwa'
append_tele(true, 13045, 60, { LAW => 2, SOUL => 2 }, 3320, 3338, 70, "Senntisten") ancient_tele 13_045, 60, { LAW => 2, SOUL => 2 }, 3320, 3338, 70, 'Senntisten'
append_tele(true, 13053, 66, { LAW => 2, BLOOD => 1 }, 3493, 3472, 76, "Kharyll") ancient_tele 13_053, 66, { LAW => 2, BLOOD => 1 }, 3493, 3472, 76, 'Kharyll'
append_tele(true, 13061, 72, { LAW => 2, WATER => 4 }, 3003, 3470, 82, "Lassar") ancient_tele 13_061, 72, { LAW => 2, WATER => 4 }, 3003, 3470, 82, 'Lassar'
append_tele(true, 13069, 78, { LAW => 2, FIRE => 3, AIR => 2 }, 2966, 3696, 88, "Dareeyak") ancient_tele 13_069, 78, { LAW => 2, FIRE => 3, AIR => 2 }, 2966, 3_696, 88, 'Dareeyak'
append_tele(true, 13079, 84, { LAW => 2, SOUL => 2 }, 3163, 3664, 94, "Carrallangar") ancient_tele 13_079, 84, { LAW => 2, SOUL => 2 }, 3163, 3664, 94, 'Carrallangar'
append_tele(true, 13087, 90, { LAW => 2, BLOOD => 2 }, 3287, 3883, 100, "Annakarl") ancient_tele 13_087, 90, { LAW => 2, BLOOD => 2 }, 3287, 3883, 100, 'Annakarl'
append_tele(true, 13095, 96, { LAW => 2, WATER => 8 }, 2972, 3873, 106, "Ghorrock") ancient_tele 13_095, 96, { LAW => 2, WATER => 8 }, 2972, 3873, 106, 'Ghorrock'
+6 -5
View File
@@ -1,5 +1,6 @@
GEMSTONES = {} GEMSTONES = {}
# A gemstone that can be received when mining.
class Gemstone class Gemstone
attr_reader :id, :chance attr_reader :id, :chance
@@ -9,11 +10,11 @@ class Gemstone
end end
end end
def append_gem(gem) def gem(gem)
GEMSTONES[gem.id] = gem GEMSTONES[gem.id] = gem
end end
append_gem(Gemstone.new(1623, 0)) # uncut sapphire gem(Gemstone.new(1623, 0)) # uncut sapphire
append_gem(Gemstone.new(1605, 0)) # uncut emerald gem(Gemstone.new(1605, 0)) # uncut emerald
append_gem(Gemstone.new(1619, 0)) # uncut ruby gem(Gemstone.new(1619, 0)) # uncut ruby
append_gem(Gemstone.new(1617, 0)) # uncut diamond gem(Gemstone.new(1617, 0)) # uncut diamond
+24 -20
View File
@@ -8,6 +8,7 @@ PROSPECT_PULSES = 3
ORE_SIZE = 1 ORE_SIZE = 1
# TODO: finish implementing this # TODO: finish implementing this
# A `DistancedAction` for mining ore.
class MiningAction < DistancedAction class MiningAction < DistancedAction
attr_reader :position, :ore, :counter, :started attr_reader :position, :ore, :counter, :started
@@ -21,9 +22,11 @@ class MiningAction < DistancedAction
def find_pickaxe def find_pickaxe
weapon = mob.equipment.get(EquipmentConstants::WEAPON) weapon = mob.equipment.get(EquipmentConstants::WEAPON)
PICKAXE_IDS.each { |id| return PICKAXES[id] if (!weapon.nil? && weapon.id == id) || mob.inventory.contains(id) } PICKAXE_IDS.each do |id|
return PICKAXES[id] if (!weapon.nil? && weapon.id == id) || mob.inventory.contains(id)
end
return nil nil
end end
# starts the mining animation, sets counters/flags and turns the mob to # starts the mining animation, sets counters/flags and turns the mob to
@@ -42,7 +45,7 @@ class MiningAction < DistancedAction
mob.turn_to(@position) mob.turn_to(@position)
# verify the mob can mine with their pickaxe # verify the mob can mine with their pickaxe
unless (!pickaxe.nil? and level >= pickaxe.level) if pickaxe.nil? || level < pickaxe.level
mob.send_message('You do not have a pickaxe for which you have the level to use.') mob.send_message('You do not have a pickaxe for which you have the level to use.')
stop stop
return return
@@ -56,9 +59,7 @@ class MiningAction < DistancedAction
end end
# check if we need to kick start things # check if we need to kick start things
unless @started if @started
start_mine(pickaxe)
else
# count down and check if we can have a chance at some ore now # count down and check if we can have a chance at some ore now
if @counter == 0 if @counter == 0
# TODO: calculate the chance that the player can actually get the rock # TODO: calculate the chance that the player can actually get the rock
@@ -73,16 +74,20 @@ class MiningAction < DistancedAction
stop stop
end end
@counter -= 1
end
@counter -= 1
else
start_mine(pickaxe)
end
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @position == other.position and @ore == other.ore) get_class == other.get_class && @position == other.position && @ore == other.ore
end end
end end
# A `DistancedAction` for a rock with no available ore.
class ExpiredProspectingAction < DistancedAction class ExpiredProspectingAction < DistancedAction
attr_reader :position attr_reader :position
@@ -96,11 +101,12 @@ class ExpiredProspectingAction < DistancedAction
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @position == other.position) get_class == other.get_class && @position == other.position
end end
end end
# A `DistancedAction` for prospecting a rock.
class ProspectingAction < DistancedAction class ProspectingAction < DistancedAction
attr_reader :position, :ore attr_reader :position, :ore
@@ -112,22 +118,22 @@ class ProspectingAction < DistancedAction
end end
def executeAction def executeAction
unless @started if @started
@started = true
mob.send_message('You examine the rock for ores...')
mob.turn_to(@position)
else
ore_def = ItemDefinition.lookup(@ore.id) ore_def = ItemDefinition.lookup(@ore.id)
name = ore_def.name.sub(/ ore$/, '').downcase name = ore_def.name.sub(/ ore$/, '').downcase
mob.send_message("This rock contains #{name}.") mob.send_message("This rock contains #{name}.")
stop stop
else
@started = true
mob.send_message('You examine the rock for ores...')
mob.turn_to(@position)
end end
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @position == other.position and @ore == other.ore) get_class == other.get_class && @position == other.position && @ore == other.ore
end end
end end
@@ -135,9 +141,7 @@ end
on :message, :first_object_action do |mob, message| on :message, :first_object_action do |mob, message|
ore = ORES[message.id] ore = ORES[message.id]
unless ore.nil? mob.start_action(MiningAction.new(mob, message.position, ore)) unless ore.nil?
mob.start_action(MiningAction.new(mob, message.position, ore))
end
end end
on :message, :second_object_action do |mob, message| on :message, :second_object_action do |mob, message|
+34 -35
View File
@@ -7,6 +7,7 @@
ORES = {} ORES = {}
EXPIRED_ORES = {} EXPIRED_ORES = {}
# An ore that can be mined.
class Ore class Ore
attr_reader :id, :objects, :level, :exp, :respawn attr_reader :id, :objects, :level, :exp, :respawn
@@ -27,70 +28,68 @@ def append_ore(ore)
end end
CLAY_OBJECTS = { CLAY_OBJECTS = {
2180 => 450 , 2109 => 451 , 14904 => 14896, 14905 => 14897 2180 => 450, 2109 => 451, 14_904 => 14_896, 14_905 => 14_897
} }
COPPER_OBJECTS = { COPPER_OBJECTS = {
11960 => 11555, 11961 => 11556, 11962 => 11557, 11936 => 11552, 11_960 => 11_555, 11_961 => 11_556, 11_962 => 11_557, 11_936 => 11_552,
11937 => 11553, 11938 => 11554, 2090 => 450 , 2091 => 451 , 11_937 => 11_553, 11_938 => 11_554, 2090 => 450, 2091 => 451,
14906 => 14898, 14907 => 14899, 14856 => 14832, 14857 => 14833, 14_906 => 14_898, 14_907 => 14_899, 14_856 => 14_832, 14_857 => 14_833,
14858 => 14834 14_858 => 14_834
} }
TIN_OBJECTS = { TIN_OBJECTS = {
11597 => 11555, 11958 => 11556, 11959 => 11557, 11933 => 11552, 11_597 => 11_555, 11_958 => 11_556, 11_959 => 11_557, 11_933 => 11_552,
11934 => 11553, 11935 => 11554, 2094 => 450 , 2095 => 451 , 11_934 => 11_553, 11_935 => 11_554, 2094 => 450, 2095 => 451,
14092 => 14894, 14903 => 14895 14_092 => 14_894, 14_903 => 14_895
} }
IRON_OBJECTS = { IRON_OBJECTS = {
11954 => 11555, 11955 => 11556, 11956 => 11557, 2092 => 450 , 11_954 => 11_555, 11_955 => 11_556, 11_956 => 11_557, 2092 => 450,
2093 => 451 , 14900 => 14892, 14901 => 14893, 14913 => 14915, 2093 => 451, 14_900 => 14_892, 14_901 => 14_893, 14_913 => 14_915,
14914 => 14916 14_914 => 14_916
} }
COAL_OBJECTS = { COAL_OBJECTS = {
11963 => 11555, 11964 => 11556, 11965 => 11557, 11930 => 11552, 11_963 => 11_555, 11_964 => 11_556, 11_965 => 11_557, 11_930 => 11_552,
11931 => 11553, 11932 => 11554, 2096 => 450 , 2097 => 451 , 11_931 => 11_553, 11_932 => 11_554, 2096 => 450, 2097 => 451,
14850 => 14832, 14851 => 14833, 14852 => 14834 14_850 => 14_832, 14_851 => 14_833, 14_852 => 14_834
} }
SILVER_OBJECTS = { SILVER_OBJECTS = {
11948 => 11555, 11949 => 11556, 11950 => 11557, 2100 => 450 , 11_948 => 11_555, 11_949 => 11_556, 11_950 => 11_557, 2100 => 450, 2101 => 451
2101 => 451
} }
GOLD_OBJECTS = { GOLD_OBJECTS = {
11951 => 11555, 11952 => 11556, 11953 => 11557, 2098 => 450 , 11_951 => 11_555, 11_952 => 11_556, 11_953 => 11_557, 2098 => 450, 2099 => 451
2099 => 451
} }
MITHRIL_OBJECTS = { MITHRIL_OBJECTS = {
11945 => 11555, 11946 => 11556, 11947 => 11557, 11942 => 11552, 11_945 => 11_555, 11_946 => 11_556, 11_947 => 11_557, 11_942 => 11_552,
11943 => 11553, 11944 => 11554, 2102 => 450 , 2103 => 451 , 11_943 => 11_553, 11_944 => 11_554, 2102 => 450, 2103 => 451,
14853 => 14832, 14854 => 14833, 14855 => 14834 14_853 => 14_832, 14_854 => 14_833, 14_855 => 14_834
} }
ADAMANT_OBJECTS = { ADAMANT_OBJECTS = {
11939 => 11552, 11940 => 11553, 11941 => 11554, 2104 => 450 , 11_939 => 11_552, 11_940 => 11_553, 11_941 => 11_554, 2104 => 450,
2105 => 451 , 14862 => 14832, 14863 => 14833, 14864 => 14834 2105 => 451, 14_862 => 14_832, 14_863 => 14_833, 14_864 => 14_834
} }
RUNITE_OBJECTS = { RUNITE_OBJECTS = {
2106 => 450 , 2107 => 451 , 14859 => 14832, 14860 => 14833, 2106 => 450, 2107 => 451, 14_859 => 14_832, 14_860 => 14_833,
14861 => 14834 14_861 => 14_834
} }
append_ore Ore.new(434, CLAY_OBJECTS, 1, 5, 3 ) # clay append_ore Ore.new 434, CLAY_OBJECTS, 1, 5, 3 # clay
append_ore Ore.new(436, COPPER_OBJECTS, 1, 17.5, 6 ) # copper ore append_ore Ore.new 436, COPPER_OBJECTS, 1, 17.5, 6 # copper ore
append_ore Ore.new(438, TIN_OBJECTS, 1, 17.5, 6 ) # tin ore append_ore Ore.new 438, TIN_OBJECTS, 1, 17.5, 6 # tin ore
append_ore Ore.new(440, IRON_OBJECTS, 15, 35, 16 ) # iron ore append_ore Ore.new 440, IRON_OBJECTS, 15, 35, 16 # iron ore
append_ore Ore.new(453, COAL_OBJECTS, 30, 50, 100 ) # coal append_ore Ore.new 453, COAL_OBJECTS, 30, 50, 100 # coal
append_ore Ore.new(444, GOLD_OBJECTS, 40, 65, 200 ) # gold ore append_ore Ore.new 444, GOLD_OBJECTS, 40, 65, 200 # gold ore
append_ore Ore.new(442, SILVER_OBJECTS, 20, 40, 200 ) # silver ore append_ore Ore.new 442, SILVER_OBJECTS, 20, 40, 200 # silver ore
append_ore Ore.new(447, MITHRIL_OBJECTS, 55, 80, 400 ) # mithril ore append_ore Ore.new 447, MITHRIL_OBJECTS, 55, 80, 400 # mithril ore
append_ore Ore.new(449, ADAMANT_OBJECTS, 70, 95, 800 ) # adamant ore append_ore Ore.new 449, ADAMANT_OBJECTS, 70, 95, 800 # adamant ore
append_ore Ore.new(451, RUNITE_OBJECTS, 85, 125, 2500) # runite ore append_ore Ore.new 451, RUNITE_OBJECTS, 85, 125, 2500 # runite ore
# TODO: rune essence object id = 2491 # TODO: rune essence object id = 2491
# level 1, exp 5, rune ess = 1436, pure ess = 7936 # level 1, exp 5, rune ess = 1436, pure ess = 7936
+1
View File
@@ -5,6 +5,7 @@ java_import 'org.apollo.game.model.Animation'
PICKAXES = {} PICKAXES = {}
PICKAXE_IDS = [] PICKAXE_IDS = []
# A pickaxe that can be mined with.
class Pickaxe class Pickaxe
attr_reader :id, :level, :animation, :pulses attr_reader :id, :level, :animation, :pulses
+30 -27
View File
@@ -4,12 +4,12 @@ java_import 'org.apollo.game.action.Action'
java_import 'org.apollo.game.model.Animation' java_import 'org.apollo.game.model.Animation'
java_import 'org.apollo.game.model.entity.Skill' java_import 'org.apollo.game.model.entity.Skill'
BURY_BONE_ANIMATION = 827 BURY_BONE_ANIMATION = Animation.new(827)
BONES = {} BONES = {}
# A bone with an id and experience value. # A bone with an id and experience value.
class Bone class Bone
attr_reader :id, :experience attr_reader :id, :experience
def initialize(id, experience) def initialize(id, experience)
@id = id @id = id
@@ -18,7 +18,6 @@ class Bone
end end
# An action where a bone in a player's inventory is buried. # An action where a bone in a player's inventory is buried.
class BuryBoneAction < Action class BuryBoneAction < Action
attr_reader :slot, :bone attr_reader :slot, :bone
@@ -36,24 +35,28 @@ class BuryBoneAction < Action
@executions += 1 @executions += 1
elsif @executions == 1 elsif @executions == 1
if mob.inventory.get(@slot).id == @bone.id if mob.inventory.get(@slot).id == @bone.id
mob.play_animation(Animation.new(BURY_BONE_ANIMATION)) mob.play_animation(BURY_BONE_ANIMATION)
mob.send_message('You bury the bones.') mob.send_message('You bury the bones.')
mob.inventory.reset(@slot) mob.inventory.reset(@slot)
mob.skill_set.add_experience(Skill::PRAYER, @bone.experience) mob.skill_set.add_experience(Skill::PRAYER, @bone.experience)
end end
stop stop
end end
end end
def equals(other) def equals(other)
return (get_class == other.get_class and @bone == other.bone) get_class == other.get_class && @bone == other.bone
end end
end end
# Intercepts the first item option message. # Intercepts the first item option message.
on :message, :first_item_option do |player, message| on :message, :first_item_option do |player, message|
bone = BONES[message.id] bone = BONES[message.id]
unless bone == nil
unless bone.nil?
player.start_action(BuryBoneAction.new(player, message.slot, bone)) player.start_action(BuryBoneAction.new(player, message.slot, bone))
message.terminate message.terminate
end end
@@ -61,28 +64,28 @@ end
# Appends a bone to the array # Appends a bone to the array
def append_bone(hash) def append_bone(hash)
raise 'Hash must contain an id and an experience value.' unless hash.has_key?(:id) && hash.has_key?(:experience) fail 'Hash must contain an id and an experience value.' unless hash.has_keys?(:id, :experience)
id = hash[:id] id = hash[:id]
BONES[id] = Bone.new(id, hash[:experience]) BONES[id] = Bone.new(id, hash[:experience])
end end
append_bone :name => :regular_bones, :id => 526, :experience => 5 append_bone name: :regular_bones, id: 526, experience: 5
append_bone :name => :burnt_bones, :id => 528, :experience => 5 append_bone name: :burnt_bones, id: 528, experience: 5
append_bone :name => :bat_bones, :id => 530, :experience => 4 append_bone name: :bat_bones, id: 530, experience: 4
append_bone :name => :big_bones, :id => 532, :experience => 45 append_bone name: :big_bones, id: 532, experience: 45
append_bone :name => :babydragon_bones, :id => 534, :experience => 30 append_bone name: :babydragon_bones, id: 534, experience: 30
append_bone :name => :dragon_bones, :id => 536, :experience => 72 append_bone name: :dragon_bones, id: 536, experience: 72
append_bone :name => :wolf_bones, :id => 2859, :experience => 14 append_bone name: :wolf_bones, id: 2859, experience: 14
append_bone :name => :shaikahan_bones, :id => 3123, :experience => 25 append_bone name: :shaikahan_bones, id: 3123, experience: 25
append_bone :name => :jogre_bones, :id => 3125, :experience => 15 append_bone name: :jogre_bones, id: 3125, experience: 15
append_bone :name => :burnt_zogre_bones, :id => 3127, :experience => 25 append_bone name: :burnt_zogre_bones, id: 3127, experience: 25
append_bone :name => :monkey_bones, :id => 3179, :experience => 14 # smallish append_bone name: :monkey_bones, id: 3179, experience: 14 # smallish
append_bone :name => :monkey_bones, :id => 3180, :experience => 14 # medium append_bone name: :monkey_bones, id: 3180, experience: 14 # medium
append_bone :name => :monkey_bones, :id => 3181, :experience => 14 # quite large append_bone name: :monkey_bones, id: 3181, experience: 14 # quite large
append_bone :name => :monkey_bones, :id => 3182, :experience => 14 # quite large append_bone name: :monkey_bones, id: 3182, experience: 14 # quite large
append_bone :name => :monkey_bones, :id => 3183, :experience => 14 # small append_bone name: :monkey_bones, id: 3183, experience: 14 # small
append_bone :name => :shaking_bones, :id => 3187, :experience => 14 append_bone name: :shaking_bones, id: 3187, experience: 14
append_bone :name => :zogre_bones, :id => 4812, :experience => 23 append_bone name: :zogre_bones, id: 4812, experience: 23
append_bone :name => :fayrg_bones, :id => 4830, :experience => 84 append_bone name: :fayrg_bones, id: 4830, experience: 84
append_bone :name => :raurg_bones, :id => 4832, :experience => 96 append_bone name: :raurg_bones, id: 4832, experience: 96
append_bone :name => :ourg_bones, :id => 4834, :experience => 140 append_bone name: :ourg_bones, id: 4834, experience: 140
+53 -54
View File
@@ -4,86 +4,85 @@ java_import 'org.apollo.game.message.impl.ConfigMessage'
# Declares the active prayer attribute. # Declares the active prayer attribute.
declare_attribute(:active_prayer, -1, :persistent) declare_attribute(:active_prayer, -1, :persistent)
# The hash of button ids to prayers. # The hash of button ids to prayers.
PRAYERS = {} PRAYERS = {}
# Intercept the ButtonMessage to toggle a prayer. # Intercept the ButtonMessage to toggle a prayer.
on :message, :button do |player, message| on :message, :button do |player, message|
button = message.widget_id button = message.widget_id
prayer = PRAYERS[button] prayer = PRAYERS[button]
unless prayer.nil? unless prayer.nil?
if (prayer.level > player.skill_set.get_maximum_level(Skill::PRAYER)) if prayer.level > player.skill_set.get_maximum_level(Skill::PRAYER)
update_setting(player, prayer, :off) update_setting(player, prayer, :off)
next next
end
player.send_message("after level check")
previous = player.active_prayer
unless previous == -1
update_setting(player, PRAYERS[previous], :off)
end
if previous != button
player.send_message("Previous: #{previous}, new: #{button}.")
update_setting(player, prayer, :on)
player.active_prayer = button
end
end end
player.send_message('after level check')
previous = player.active_prayer
update_setting(player, PRAYERS[previous], :off) unless previous == -1
if previous != button
player.send_message("Previous: #{previous}, new: #{button}.")
update_setting(player, prayer, :on)
player.active_prayer = button
end
end
end end
private private
# A Prayer that can be activated by a player. # A Prayer that can be activated by a player.
class Prayer class Prayer
attr_reader :name, :level, :button, :setting, :drain attr_reader :name, :level, :button, :setting, :drain
def initialize(name, level, button, setting, drain) def initialize(name, level, button, setting, drain)
@name = name @name = name
@level = level @level = level
@button = button @button = button
@setting = setting @setting = setting
@drain = drain @drain = drain
end end
end end
def update_setting(player, prayer, state) def update_setting(player, prayer, state)
value = (state == :on) ? 1 : 0 value = (state == :on) ? 1 : 0
player.send_message("Toggling prayer #{prayer.name}, state: #{state}.") player.send_message("Toggling prayer #{prayer.name}, state: #{state}.")
player.send(ConfigMessage.new(prayer.setting, value)) player.send(ConfigMessage.new(prayer.setting, value))
end end
# Appends a Prayer to the hash. # Appends a Prayer to the hash.
def append_prayer(properties) def append_prayer(name, hash)
raise 'Error: prayer properties hash must contain a name, level, button, setting, and drain.' unless properties.has_keys?(:name, :level, :button, :setting, :drain) unless hash.has_keys?(:level, :button, :setting, :drain)
fail 'Error: prayer hash hash must contain a level, button, setting, and drain.'
end
button = properties[:button] button = hash[:button]
PRAYERS[button] = Prayer.new(properties[:name], properties[:level], button, properties[:setting], properties[:drain]) PRAYERS[button] = Prayer.new(name, hash[:level], button, hash[:setting], hash[:drain])
end end
# Don't deal with the actual effect here to avoid mess (TODO do it, but with attributes?). # Don't deal with the actual effect here to avoid mess (TODO do it, but with attributes?).
append_prayer name: :thick_skin, level: 1, button: 5609, setting: 83, drain: 0.01 append_prayer :thick_skin, level: 1, button: 5609, setting: 83, drain: 0.01
append_prayer name: :burst_of_strength, level: 4, button: 5610, setting: 84, drain: 0.01 append_prayer :burst_of_strength, level: 4, button: 5610, setting: 84, drain: 0.01
append_prayer name: :clarity_of_thought, level: 7, button: 5611, setting: 85, drain: 0.01 append_prayer :clarity_of_thought, level: 7, button: 5611, setting: 85, drain: 0.01
append_prayer name: :rock_skin, level: 10, button: 5612, setting: 86, drain: 0.04 append_prayer :rock_skin, level: 10, button: 5612, setting: 86, drain: 0.04
append_prayer name: :superhuman_strength, level: 13, button: 5613, setting: 87, drain: 0.04 append_prayer :superhuman_strength, level: 13, button: 5613, setting: 87, drain: 0.04
append_prayer name: :improved_reflexes, level: 16, button: 5614, setting: 88, drain: 0.04 append_prayer :improved_reflexes, level: 16, button: 5614, setting: 88, drain: 0.04
append_prayer name: :rapid_restore, level: 19, button: 5615, setting: 89, drain: 0.01 append_prayer :rapid_restore, level: 19, button: 5615, setting: 89, drain: 0.01
append_prayer name: :rapid_heal, level: 22, button: 5615, setting: 90, drain: 0.01 append_prayer :rapid_heal, level: 22, button: 5615, setting: 90, drain: 0.01
append_prayer name: :protect_item, level: 25, button: 5617, setting: 91, drain: 0.01 append_prayer :protect_item, level: 25, button: 5617, setting: 91, drain: 0.01
append_prayer name: :steel_skin, level: 28, button: 5618, setting: 92, drain: 0.1 append_prayer :steel_skin, level: 28, button: 5618, setting: 92, drain: 0.1
append_prayer name: :ultimate_strength, level: 31, button: 5619, setting: 93, drain: 0.1 append_prayer :ultimate_strength, level: 31, button: 5619, setting: 93, drain: 0.1
append_prayer name: :incredible_reflexes, level: 34, button: 5620, setting: 94, drain: 0.1 append_prayer :incredible_reflexes, level: 34, button: 5620, setting: 94, drain: 0.1
append_prayer name: :protect_from_magic, level: 37, button: 5621, setting: 95, drain: 0.15 append_prayer :protect_from_magic, level: 37, button: 5621, setting: 95, drain: 0.15
append_prayer name: :protect_from_missiles, level: 40, button: 5622, setting: 96, drain: 0.15 append_prayer :protect_from_missiles, level: 40, button: 5622, setting: 96, drain: 0.15
append_prayer name: :protect_from_melee, level: 43, button: 5633, setting: 97, drain: 0.15 append_prayer :protect_from_melee, level: 43, button: 5633, setting: 97, drain: 0.15
append_prayer name: :retribution, level: 46, button: 683, setting: 98, drain: 0.15 append_prayer :retribution, level: 46, button: 683, setting: 98, drain: 0.15
append_prayer name: :redemption, level: 49, button: 684, setting: 99, drain: 0.15 append_prayer :redemption, level: 49, button: 684, setting: 99, drain: 0.15
append_prayer name: :smite, level: 52, button: 685, setting: 100, drain: 0.2 append_prayer :smite, level: 52, button: 685, setting: 100, drain: 0.2
+67 -29
View File
@@ -9,11 +9,12 @@ CRAFTING_ALTARS = {}
# Represents a runecrafting altar. # Represents a runecrafting altar.
class Altar class Altar
attr_reader :entrance_altar, :crafting_altar, :portal_id, :entrance_position, :exit_position, :crafting_centre attr_reader :entrance_altar, :crafting, :portal_id, :entrance, :exit, :crafting_centre
def initialize(entrance_altar, crafting_altar, portal_id, entrance_position, exit_position,crafting_centre) def initialize(entrance_altar, crafting, portal_id, entrance_position, exit_position,
crafting_centre)
@entrance_altar = entrance_altar @entrance_altar = entrance_altar
@altar = crafting_altar @altar = crafting
@portal_id = portal_id @portal_id = portal_id
@entrance_position = entrance_position @entrance_position = entrance_position
@exit_position = exit_position @exit_position = exit_position
@@ -22,11 +23,12 @@ class Altar
end end
# Intercepts the item on object message. # Intercepts the item on object message.
on :message, :item_on_object do |player, message| on :message, :item_on_object do |player, message|
talisman = TALISMANS[message.id]; altar = ENTRANCE_ALTARS[message.object_id] talisman = TALISMANS[message.id]
unless (talisman.nil? || altar.nil?) altar = ENTRANCE_ALTARS[message.object_id]
unless talisman.nil? || altar.nil?
player.start_action(TeleportAction.new(player, message.position, 2, altar.entrance_position)) player.start_action(TeleportAction.new(player, message.position, 2, altar.entrance_position))
message.terminate message.terminate
end end
@@ -34,22 +36,27 @@ end
# Intercepts the first object action message. # Intercepts the first object action message.
on :message, :object_action do |player, message| on :message, :object_action do |player, message|
if (message.option == 1) if message.option == 1
object_id = message.id object_id = message.id
if (altar = PORTALS[object_id]) != nil # Get the altar associated with this exit portal. if PORTALS.key?(object_id)
player.start_action(TeleportAction.new(player, altar.entrance_position, 1, altar.exit_position)) altar = PORTALS[object_id]
entrance = altar.entrance_position
player.start_action(TeleportAction.new(player, entrance, 1, altar.exit_position))
message.terminate message.terminate
elsif (rune = RUNES[object_id]) != nil # Get the rune associated with this altar. elsif RUNES.key?(object_id)
rune = RUNES[object_id]
altar = CRAFTING_ALTARS[object_id] altar = CRAFTING_ALTARS[object_id]
player.start_action(RunecraftingAction.new(player, rune, altar.crafting_centre)) player.start_action(RunecraftingAction.new(player, rune, altar.crafting_centre))
message.terminate message.terminate
end end
end end
end end
# An action that causes a mob to teleport when it comes within the specified distance of a
# An action that causes a mob to teleport when it comes within the specified distance of a specified position. # specified position.
class TeleportAction < DistancedAction class TeleportAction < DistancedAction
attr_reader :teleport_position attr_reader :teleport_position
@@ -64,28 +71,59 @@ class TeleportAction < DistancedAction
end end
def equals(other) def equals(other)
return (get_class == other.get_class && mob == other.mob && @teleport_position == other.teleport_position) get_class == other.get_class && mob == other.mob &&
@teleport_position == other.teleport_position
end end
end end
# Appends an altar to the list. # Appends an altar to the list.
def append_altar(hash) def altar(name, hash)
#raise 'Hash must contain an entrance altar id, crafting altar id, entrance portal position, and altar centre position.' unless hash.has_keys?(:entrance_altar, :crafting, :portal, :entrance, :exit, :altar_centre)
entrance_altar = hash[:entrance_altar]; crafting_altar = hash[:crafting_altar]; portal_id = hash[:exit_portal]; entrance_position = hash[:entrance_position]; exit_position = hash[:exit_position]; altar_centre = hash[:altar_centre] fail "#{name} is missing one of: entrance altar id, crafting altar id, entrance portal position, "\
"and altar centre position."
end
PORTALS[portal_id] = ENTRANCE_ALTARS[entrance_altar] = CRAFTING_ALTARS[crafting_altar] = Altar.new(entrance_altar, crafting_altar, portal_id, Position.new(*entrance_position), Position.new(*exit_position), Position.new(*altar_centre)) entrance_altar, crafting = hash[:entrance_altar], hash[:crafting]
portal_id = hash[:portal]
entrance = Position.new(*hash[:entrance])
exit_position = Position.new(*hash[:exit])
centre = Position.new(*hash[:altar_centre])
altar = Altar.new(entrance_altar, crafting, portal_id, entrance, exit_position, centre)
PORTALS[portal_id] = ENTRANCE_ALTARS[entrance_altar] = CRAFTING_ALTARS[crafting] = altar
end end
# Appends an altar to the list. altar :air, entrance_altar: 2452, crafting: 2478, portal: 2465,
append_altar :name => :air_altar, :entrance_altar => 2452, :crafting_altar => 2478, :exit_portal => 2465, :entrance_position => [ 2841, 4829 ], :exit_position => [ 2983, 3292 ], :altar_centre => [ 2844, 4834 ] entrance: [2841, 4829], exit: [2983, 3292], altar_centre: [2844, 4834]
append_altar :name => :mind_altar, :entrance_altar => 2453, :crafting_altar => 2479, :exit_portal => 2466, :entrance_position => [ 2793, 4828 ], :exit_position => [ 2980, 3514 ], :altar_centre => [ 2786, 4841 ]
append_altar :name => :water_altar, :entrance_altar => 2454, :crafting_altar => 2480, :exit_portal => 2467, :entrance_position => [ 2726, 4832 ], :exit_position => [ 3187, 3166 ], :altar_centre => [ 2716, 4836 ] altar :mind, entrance_altar: 2453, crafting: 2479, portal: 2466,
append_altar :name => :earth_altar, :entrance_altar => 2455, :crafting_altar => 2481, :exit_portal => 2468, :entrance_position => [ 2655, 4830 ], :exit_position => [ 3304, 3474 ], :altar_centre => [ 2658, 4841 ] entrance: [2793, 4828], exit: [2980, 3514], altar_centre: [2786, 4841]
append_altar :name => :fire_altar, :entrance_altar => 2456, :crafting_altar => 2482, :exit_portal => 2469, :entrance_position => [ 2574, 4849 ], :exit_position => [ 3311, 3256 ], :altar_centre => [ 2585, 4838 ]
append_altar :name => :body_altar, :entrance_altar => 2457, :crafting_altar => 2483, :exit_portal => 2470, :entrance_position => [ 2524, 4825 ], :exit_position => [ 3051, 3445 ], :altar_centre => [ 2525, 4832 ] altar :water, entrance_altar: 2454, crafting: 2480, portal: 2467,
append_altar :name => :cosmic_altar, :entrance_altar => 2458, :crafting_altar => 2484, :exit_portal => 2471, :entrance_position => [ 2142, 4813 ], :exit_position => [ 2408, 4379 ], :altar_centre => [ 2142, 4833 ] entrance: [2726, 4832], exit: [3187, 3166], altar_centre: [2716, 4836]
append_altar :name => :law_altar, :entrance_altar => 2459, :crafting_altar => 2485, :exit_portal => 2472, :entrance_position => [ 2464, 4818 ], :exit_position => [ 2858, 3379 ], :altar_centre => [ 2464, 4832 ]
append_altar :name => :nature_altar, :entrance_altar => 2460, :crafting_altar => 2486, :exit_portal => 2473, :entrance_position => [ 2400, 4835 ], :exit_position => [ 2867, 3019 ], :altar_centre => [ 2400, 4841 ] altar :earth, entrance_altar: 2455, crafting: 2481, portal: 2468,
append_altar :name => :chaos_altar, :entrance_altar => 2461, :crafting_altar => 2487, :exit_portal => 2474, :entrance_position => [ 2268, 4842 ], :exit_position => [ 3058, 3591 ], :altar_centre => [ 2271, 4842 ] entrance: [2655, 4830], exit: [3304, 3474], altar_centre: [2658, 4841]
append_altar :name => :death_altar, :entrance_altar => 2462, :crafting_altar => 2488, :exit_portal => 2475, :entrance_position => [ 2208, 4830 ], :exit_position => [ 3222, 3222 ], :altar_centre => [ 2205, 4836 ]
altar :fire, entrance_altar: 2456, crafting: 2482, portal: 2469,
entrance: [2574, 4849], exit: [3311, 3256], altar_centre: [2585, 4838]
altar :body, entrance_altar: 2457, crafting: 2483, portal: 2470,
entrance: [2524, 4825], exit: [3051, 3445], altar_centre: [2525, 4832]
altar :cosmic, entrance_altar: 2458, crafting: 2484, portal: 2471,
entrance: [2142, 4813], exit: [2408, 4379], altar_centre: [2142, 4833]
altar :law, entrance_altar: 2459, crafting: 2485, portal: 2472,
entrance: [2464, 4818], exit: [2858, 3379], altar_centre: [2464, 4832]
altar :nature, entrance_altar: 2460, crafting: 2486, portal: 2473,
entrance: [2400, 4835], exit: [2867, 3019], altar_centre: [2400, 4841]
altar :chaos, entrance_altar: 2461, crafting: 2487, portal: 2474,
entrance: [2268, 4842], exit: [3058, 3591], altar_centre: [2271, 4842]
altar :death, entrance_altar: 2462, crafting: 2488, portal: 2475,
entrance: [2208, 4830], exit: [3222, 3222], altar_centre: [2205, 4836]
+25 -19
View File
@@ -15,32 +15,38 @@ class Rune
@multiplier = multiplier @multiplier = multiplier
end end
def multiplier(level) def equals(other)
return @multiplier.call(level) get_class == other.get_class && id == other.id
end end
def equals(other) def multiplier(level)
return (get_class == other.get_class && id == other.id) @multiplier.call(level)
end end
end end
# Appends a rune to the list. # Appends a rune to the list.
def append_rune(hash) def rune(name, hash)
raise 'Hash must contain an id, level, experience, and multiplier.' unless hash.has_keys?(:id, :level, :experience, :multiplier) unless hash.has_keys?(:altar, :id, :level, :reward)
id = hash[:id]; altar = hash[:altar]; level = hash[:level]; experience = hash[:experience]; multiplier = hash[:multiplier] fail "#{name} is missing one of id, altar, level, or reward."
end
RUNES[altar] = Rune.new(id, level, experience, multiplier) id, altar, level, experience = hash[:id], hash[:altar], hash[:level], hash[:reward]
bonus = hash[:bonus] || ->(_) { 1 }
RUNES[altar] = Rune.new(id, level, experience, bonus)
end end
append_rune(:name => :air_rune, :altar => 2478, :id => 556, :level => 1, :experience => 5, :multiplier => lambda { |level| (level / 11).floor + 1 }) rune :air, altar: 2478, id: 556, level: 1, reward: 5, bonus: ->(level) { (level / 11).floor + 1 }
append_rune(:name => :mind_rune, :altar => 2479, :id => 558, :level => 1, :experience => 5.5, :multiplier => lambda { |level| (level / 14).floor + 1 }) rune :mind, altar: 2479, id: 558, level: 1, reward: 5.5, bonus: ->(level) { (level / 14).floor + 1 }
append_rune(:name => :water_rune, :altar => 2480, :id => 555, :level => 5, :experience => 6, :multiplier => lambda { |level| (level / 19).floor + 1 }) rune :water, altar: 2480, id: 555, level: 5, reward: 6, bonus: ->(level) { (level / 19).floor + 1 }
append_rune(:name => :earth_rune, :altar => 2481, :id => 557, :level => 9, :experience => 6.5, :multiplier => lambda { |level| (level / 26).floor + 1 }) rune :earth, altar: 2481, id: 557, level: 9, reward: 6.5,
append_rune(:name => :fire_rune, :altar => 2482, :id => 554, :level => 14, :experience => 7, :multiplier => lambda { |level| (level / 35).floor + 1 }) bonus: ->(level) { (level / 26).floor + 1 }
append_rune(:name => :body_rune, :altar => 2483, :id => 559, :level => 20, :experience => 7.5, :multiplier => lambda { |level| (level / 46).floor + 1 }) rune :fire, altar: 2482, id: 554, level: 14, reward: 7, bonus: ->(level) { (level / 35).floor + 1 }
append_rune(:name => :cosmic_rune, :altar => 2484, :id => 564, :level => 27, :experience => 8, :multiplier => lambda { |level| level >= 59 ? 2 : 1 }) rune :body, altar: 2483, id: 559, level: 20, reward: 7.5,
append_rune(:name => :chaos_rune, :altar => 2487, :id => 562, :level => 35, :experience => 8.5, :multiplier => lambda { |level| level >= 74 ? 2 : 1 }) bonus: ->(level) { (level / 46).floor + 1 }
append_rune(:name => :nature_rune, :altar => 2486, :id => 561, :level => 44, :experience => 9, :multiplier => lambda { |level| level >= 91 ? 2 : 1 }) rune :cosmic, altar: 2484, id: 564, level: 27, reward: 8, bonus: ->(level) { level >= 59 ? 2 : 1 }
append_rune(:name => :law_rune, :altar => 2485, :id => 563, :level => 54, :experience => 9.5, :multiplier => lambda { |level| 1 }) rune :chaos, altar: 2487, id: 562, level: 35, reward: 8.5, bonus: ->(level) { level >= 74 ? 2 : 1 }
append_rune(:name => :death_rune, :altar => 2488, :id => 560, :level => 65, :experience => 10, :multiplier => lambda { |level| 1 }) rune :nature, altar: 2486, id: 561, level: 44, reward: 9, bonus: ->(level) { level >= 91 ? 2 : 1 }
rune :law, altar: 2485, id: 563, level: 54, reward: 9.5
rune :death, altar: 2488, id: 560, level: 65, reward: 10
+10 -6
View File
@@ -25,7 +25,7 @@ class RunecraftingAction < DistancedAction
def executeAction def executeAction
runecrafting_level = @player.skill_set.get_skill(Skill::RUNECRAFT).current_level runecrafting_level = @player.skill_set.get_skill(Skill::RUNECRAFT).current_level
if (runecrafting_level < @rune.level) if runecrafting_level < @rune.level
@player.send_message("You need a runecrafting level of #{@rune.level} to craft this rune.") @player.send_message("You need a runecrafting level of #{@rune.level} to craft this rune.")
stop stop
elsif !@player.inventory.contains(RUNE_ESSENCE_ID) elsif !@player.inventory.contains(RUNE_ESSENCE_ID)
@@ -37,18 +37,22 @@ class RunecraftingAction < DistancedAction
@player.play_graphic(RUNECRAFTING_GRAPHIC) @player.play_graphic(RUNECRAFTING_GRAPHIC)
@executions += 1 @executions += 1
elsif @executions == 1 elsif @executions == 1
removed = @player.inventory.remove(RUNE_ESSENCE_ID, @player.inventory.get_amount(RUNE_ESSENCE_ID)) inventory = @player.inventory
added = removed * @rune.multiplier(runecrafting_level) removed = inventory.remove(RUNE_ESSENCE_ID, inventory.get_amount(RUNE_ESSENCE_ID))
@player.inventory.add(@rune.id, added)
added = removed * @rune.multiplier(runecrafting_level)
inventory.add(@rune.id, added)
name = added > 1 ? 'some ' + @rune.name + 's' : 'an ' + @rune.name
@player.send_message("Your craft the rune essence into #{name}.", true)
@player.send_message("Your craft the rune essence into #{added > 1 ? 'some ' + @rune.name + 's' : 'an ' + @rune.name}.", true)
@player.skill_set.add_experience(Skill::RUNECRAFT, removed * @rune.experience) @player.skill_set.add_experience(Skill::RUNECRAFT, removed * @rune.experience)
stop stop
end end
end end
def equals(other) def equals(other)
return (get_class == other.get_class && @player == other.player && @rune == other.rune) get_class == other.get_class && @player == other.player && @rune == other.rune
end end
end end
+27 -25
View File
@@ -12,41 +12,43 @@ class Talisman
@locate_position = entrance_altar_position @locate_position = entrance_altar_position
end end
def get_message(player_position) def get_message(position)
return 'Your talisman glows brightly.' if player_position.is_within_distance(@locate_position, 10) return 'Your talisman glows brightly.' if position.is_within_distance(@locate_position, 10)
direction = (player_position.y > @locate_position.y ? 'North' : 'South') + '-' + (player_position.x > @locate_position.x ? 'East' : 'West') direction = (position.y > @locate_position.y ? 'North' : 'South') + '-'
return "The talisman pulls toward the #{direction}." direction += (position.x > @locate_position.x ? 'East' : 'West')
"The talisman pulls toward the #{direction}."
end end
end end
# Appends a talisman to the list.
def append_talisman(hash)
raise 'Hash must contain an id and an altar position.' unless hash.has_key?(:id) && hash.has_key?(:altar)
id = hash[:id]; altar_position = Position.new(*hash[:altar])
TALISMANS[id] = Talisman.new(altar_position)
end
# Intercepts the item option message. # Intercepts the item option message.
on :message, :fourth_item_option do |player, message| on :message, :fourth_item_option do |player, message|
talisman = TALISMANS[message.id] talisman = TALISMANS[message.id]
if (talisman != nil)
unless talisman.nil?
player.send_message(talisman.get_message(player.position)) player.send_message(talisman.get_message(player.position))
message.terminate message.terminate
end end
end end
# Appends talismans to the list. # Appends a talisman to the list.
append_talisman :name => :air_talisman, :id => 1438, :altar => [ 2985, 3292 ] def talisman(name, hash)
append_talisman :name => :earth_talisman, :id => 1440, :altar => [ 3306, 3474 ] fail 'Hash must contain an id and an altar position.' unless hash.has_keys?(:id, :altar)
append_talisman :name => :fire_talisman, :id => 1442, :altar => [ 3313, 3255 ] id, altar_position = hash[:id], Position.new(*hash[:altar])
append_talisman :name => :water_talisman, :id => 1444, :altar => [ 3185, 3165 ]
append_talisman :name => :body_talisman, :id => 1446, :altar => [ 3053, 3445 ] TALISMANS[id] = Talisman.new(altar_position)
append_talisman :name => :mind_talisman, :id => 1448, :altar => [ 2982, 3514 ] end
append_talisman :name => :chaos_talisman, :id => 1452, :altar => [ 3059, 3590 ]
append_talisman :name => :cosmic_talisman, :id => 1454, :altar => [ 2408, 4377 ] talisman :air_talisman, id: 1438, altar: [2985, 3292]
append_talisman :name => :death_talisman, :id => 1456, :altar => [ 0, 0 ] talisman :earth_talisman, id: 1440, altar: [3306, 3474]
append_talisman :name => :law_talisman, :id => 1458, :altar => [ 2858, 3381 ] talisman :fire_talisman, id: 1442, altar: [3313, 3255]
append_talisman :name => :nature_talisman, :id => 1462, :altar => [ 2869, 3019 ] talisman :water_talisman, id: 1444, altar: [3185, 3165]
talisman :body_talisman, id: 1446, altar: [3053, 3445]
talisman :mind_talisman, id: 1448, altar: [2982, 3514]
talisman :chaos_talisman, id: 1452, altar: [3059, 3590]
talisman :cosmic_talisman, id: 1454, altar: [2408, 4377]
talisman :death_talisman, id: 1456, altar: [0, 0]
talisman :law_talisman, id: 1458, altar: [2858, 3381]
talisman :nature_talisman, id: 1462, altar: [2869, 3019]
+51 -43
View File
@@ -4,27 +4,27 @@ java_import 'org.apollo.game.message.impl.ConfigMessage'
java_import 'org.apollo.game.model.entity.EquipmentConstants' java_import 'org.apollo.game.model.entity.EquipmentConstants'
java_import 'org.apollo.game.action.DistancedAction' java_import 'org.apollo.game.action.DistancedAction'
# The list of tiaras. # The hash of tiaras.
TIARAS_BY_ALTAR = {} TIARAS_BY_ALTAR = {}
TIARAS_BY_ID = {} TIARAS_BY_ID = {}
TIARAS_BY_TALISMAN = {} TIARAS_BY_TALISMAN = {}
# A tiara will make an altar accessible with 1 click # A tiara will make an altar accessible with a single click.
class Tiara class Tiara
attr_reader :altar, :bitshift, :tiara_id, :experience, :talisman attr_reader :altar, :bitshift, :tiara_id, :experience, :talisman
def initialize(tiara_id, altar, talisman, bitshift, experience) def initialize(tiara_id, altar, talisman, bitshift, experience)
@tiara_id = tiara_id @tiara_id = tiara_id
@name = name_of(:item, tiara_id) @name = name_of(:item, tiara_id)
@altar = altar @altar = altar
@talisman = talisman @talisman = talisman
@bitshift = bitshift @bitshift = bitshift
@experience = experience @experience = experience
end end
# Sends a config message to change the altar object. # Sends a config message to change the altar object.
def send_config(player) def send_config(player)
player.send(ConfigMessage.new(CHANGE_ALTAR_OBJECT_CONFIG, 1 << @bitshift)) player.send(ConfigMessage.new(CHANGE_ALTAR_OBJECT_CONFIG, 1 << @bitshift))
end end
end end
@@ -42,26 +42,18 @@ def send_empty_config(player)
player.send(ConfigMessage.new(CHANGE_ALTAR_OBJECT_CONFIG, 0)) player.send(ConfigMessage.new(CHANGE_ALTAR_OBJECT_CONFIG, 0))
end end
# Appends a tiara to the list.
def append_tiara(hash)
raise 'Hash must contain a tiara id, altar id, talisman id, a bitshift number, and experience.' unless hash.has_keys?(:altar, :bitshift, :experience, :talisman, :tiara_id)
tiara_id = hash[:tiara_id]; altar = hash[:altar]; talisman = hash[:talisman]; bitshift = hash[:bitshift]; experience = hash[:experience]
TIARAS_BY_TALISMAN[talisman] = TIARAS_BY_ID[tiara_id] = TIARAS_BY_ALTAR[altar] = Tiara.new(tiara_id, altar, talisman, bitshift, experience)
end
# Sets the correct config upon login, if the player is wearing a tiara. # Sets the correct config upon login, if the player is wearing a tiara.
on :login do |event, player| on :login do |_event, player|
player = event.player
hat = player.equipment.get(EquipmentConstants::HAT) hat = player.equipment.get(EquipmentConstants::HAT)
unless hat.nil? unless hat.nil?
tiara = TIARAS_BY_ID[hat] tiara = TIARAS_BY_ID[hat]
if tiara.nil? then send_empty_config(player) else tiara.send_config end tiara.nil? ? send_empty_config(player) : tiara.send_config
end end
end end
# Intercepts the SecondObjectAction message to support left-click access to the altar when wielding the correct tiara. # Intercepts the SecondObjectAction message to support left-click access to the altar when wielding
# the correct tiara.
on :message, :second_object_action do |player, message| on :message, :second_object_action do |player, message|
object_id = message.id object_id = message.id
tiara = TIARAS_BY_ALTAR[object_id] tiara = TIARAS_BY_ALTAR[object_id]
@@ -69,11 +61,13 @@ on :message, :second_object_action do |player, message|
hat = player.equipment.get(EquipmentConstants::HAT) hat = player.equipment.get(EquipmentConstants::HAT)
if (!hat.nil? && hat.id == tiara.tiara_id) if !hat.nil? && hat.id == tiara.tiara_id
altar = ENTRANCE_ALTARS[tiara.altar] altar = ENTRANCE_ALTARS[tiara.altar]
player.start_action(TeleportAction.new(player, message.position, 2, altar.entrance_position)) unless altar.nil?
message.terminate message.terminate
unless altar.nil?
player.start_action(TeleportAction.new(player, message.position, 2, altar.entrance_position))
end
end end
end end
@@ -99,14 +93,15 @@ end
# Intercepts the ItemOnObject message to create the tiara. # Intercepts the ItemOnObject message to create the tiara.
on :message, :item_on_object do |player, message| on :message, :item_on_object do |player, message|
tiara= TIARAS_BY_TALISMAN[message.id]; altar = CRAFTING_ALTARS[message.object_id] tiara, altar = TIARAS_BY_TALISMAN[message.id], CRAFTING_ALTARS[message.object_id]
return if (tiara.nil? || altar.nil?) return if tiara.nil? || altar.nil?
player.start_action(CreateTiaraAction.new(player, message.position, tiara, altar)) player.start_action(CreateTiaraAction.new(player, message.position, tiara, altar))
message.terminate message.terminate
end end
# An action lets the player create a tiara when it comes within the specified distance of a specified position. # An action lets the player create a tiara when it comes within the specified distance of a
# specified position.
# noinspection JRubyImplementInterfaceInspection # noinspection JRubyImplementInterfaceInspection
class CreateTiaraAction < DistancedAction class CreateTiaraAction < DistancedAction
@@ -122,7 +117,7 @@ class CreateTiaraAction < DistancedAction
inventory = @player.inventory inventory = @player.inventory
if inventory.contains_all(TIARA_ITEM_ID, @tiara.talisman) if inventory.contains_all(TIARA_ITEM_ID, @tiara.talisman)
if (@tiara.altar == @altar.entrance_altar) if @tiara.altar == @altar.entrance_altar
inventory.remove(@tiara.talisman, TIARA_ITEM_ID) inventory.remove(@tiara.talisman, TIARA_ITEM_ID)
inventory.add(@tiara.tiara_id) inventory.add(@tiara.tiara_id)
@@ -130,30 +125,43 @@ class CreateTiaraAction < DistancedAction
@player.play_animation(RUNECRAFTING_ANIMATION) @player.play_animation(RUNECRAFTING_ANIMATION)
@player.play_graphic(RUNECRAFTING_GRAPHIC) @player.play_graphic(RUNECRAFTING_GRAPHIC)
else else
@player.send_message("You can't use that talisman on this altar.") @player.send_message('You can\'t use that talisman on this altar.')
end end
else else
@player.send_message("You need to have a talisman and blank tiara to enchant a tiara.") @player.send_message('You need to have a talisman and blank tiara to enchant a tiara.')
end end
stop stop
end end
def equals(other) def equals(other)
return (get_class == other.get_class && @player == other.player && @tiara == other.tiara) get_class == other.get_class && @player == other.player && @tiara == other.tiara
end end
end end
append_tiara :name => :air_tiara, :tiara_id => 5527, :altar => 2452, :talisman => 1438, :bitshift => 0, :experience => 25 # Appends a tiara to the list.
append_tiara :name => :mind_tiara, :tiara_id => 5529, :altar => 2453, :talisman => 1448, :bitshift => 1, :experience => 27.5 def tiara(_name, hash)
append_tiara :name => :water_tiara, :tiara_id => 5531, :altar => 2454, :talisman => 1444, :bitshift => 2, :experience => 30 unless hash.has_keys?(:altar, :bitshift, :experience, :talisman, :tiara_id)
append_tiara :name => :body_tiara, :tiara_id => 5533, :altar => 2457, :talisman => 1446, :bitshift => 5, :experience => 37.5 fail 'Hash must contain a tiara id, altar id, talisman id, a bitshift number, and experience.'
append_tiara :name => :earth_tiara, :tiara_id => 5535, :altar => 2455, :talisman => 1440, :bitshift => 3, :experience => 32.5 end
append_tiara :name => :fire_tiara, :tiara_id => 5537, :altar => 2456, :talisman => 1442, :bitshift => 4, :experience => 35
append_tiara :name => :cosmic_tiara, :tiara_id => 5539, :altar => 2458, :talisman => 1454, :bitshift => 6, :experience => 40 tiara_id, altar, talisman = hash[:tiara_id], hash[:altar], hash[:talisman]
append_tiara :name => :nature_tiara, :tiara_id => 5541, :altar => 2460, :talisman => 1462, :bitshift => 8, :experience => 45 bitshift, experience = hash[:bitshift], hash[:experience]
append_tiara :name => :chaos_tiara, :tiara_id => 5543, :altar => 2461, :talisman => 1452, :bitshift => 9, :experience => 42.5
append_tiara :name => :law_tiara, :tiara_id => 5545, :altar => 2459, :talisman => 1458, :bitshift => 7, :experience => 47.5 tiara = Tiara.new(tiara_id, altar, talisman, bitshift, experience)
append_tiara :name => :death_tiara, :tiara_id => 5548, :altar => 2462, :talisman => 1456, :bitshift => 10, :experience => 50 TIARAS_BY_TALISMAN[talisman] = TIARAS_BY_ID[tiara_id] = TIARAS_BY_ALTAR[altar] = tiara
# TODO there are 2 other altars, which probably just aren't spawned on the map end
tiara :air_tiara, tiara_id: 5527, altar: 2452, talisman: 1438, bitshift: 0, experience: 25
tiara :mind_tiara, tiara_id: 5529, altar: 2453, talisman: 1448, bitshift: 1, experience: 27.5
tiara :water_tiara, tiara_id: 5531, altar: 2454, talisman: 1444, bitshift: 2, experience: 30
tiara :body_tiara, tiara_id: 5533, altar: 2457, talisman: 1446, bitshift: 5, experience: 37.5
tiara :earth_tiara, tiara_id: 5535, altar: 2455, talisman: 1440, bitshift: 3, experience: 32.5
tiara :fire_tiara, tiara_id: 5537, altar: 2456, talisman: 1442, bitshift: 4, experience: 35
tiara :cosmic_tiara, tiara_id: 5539, altar: 2458, talisman: 1454, bitshift: 6, experience: 40
tiara :nature_tiara, tiara_id: 5541, altar: 2460, talisman: 1462, bitshift: 8, experience: 45
tiara :chaos_tiara, tiara_id: 5543, altar: 2461, talisman: 1452, bitshift: 9, experience: 42.5
tiara :law_tiara, tiara_id: 5545, altar: 2459, talisman: 1458, bitshift: 7, experience: 47.5
tiara :death_tiara, tiara_id: 5548, altar: 2462, talisman: 1456, bitshift: 10, experience: 50
# TODO: there are 2 other altars, which probably just aren't spawned on the map
+16 -15
View File
@@ -4,40 +4,41 @@ java_import 'org.apollo.cache.def.ItemDefinition'
java_import 'org.apollo.cache.def.NpcDefinition' java_import 'org.apollo.cache.def.NpcDefinition'
java_import 'org.apollo.cache.def.ObjectDefinition' java_import 'org.apollo.cache.def.ObjectDefinition'
# Checks whether the amount of arguments provided is correct, sending the player the specified
# Checks whether the amount of arguments provided is correct, sending the player the specified message if not. # message if not.
def valid_arg_length(args, length, player, message) def valid_arg_length(args, length, player, message)
valid = length.kind_of?(Range) ? length.include?(args.length) : length == args.length valid = length.is_a?(Range) ? length.include?(args.length) : length == args.length
player.send_message(message) if !valid player.send_message(message) unless valid
return valid valid
end end
# Returns the name of the Object, Npc, or Item with the specified id. # Returns the name of the Object, Npc, or Item with the specified id.
def name_of(type, id) def name_of(type, id)
types = [ :object, :item, :npc ] types = [:object, :item, :npc]
unless types.include?(type) unless types.include?(type)
raise "Invalid type of #{type} specified, must be one of #{types}" fail "Invalid type of #{type} specified, must be one of #{types}"
end end
return Kernel.const_get("#{type.capitalize}Definition").lookup(id).name.to_s Kernel.const_get("#{type.capitalize}Definition").lookup(id).name.to_s
end end
# Add a has_keys? method to hash # Monkey-patches Hash to add a has_keys? method.
class Hash class Hash
def has_keys?(*keys) def has_keys?(*keys)
keys.each { |key| return false unless has_key?(key) } keys.all? { |key| self.key?(key) }
return true
end end
end end
# Monkey-patches Player to add a hash_level? method.
class Player class Player
# Returns whether or not the player's current level is greater than or equal to the specified level. # Returns whether or not the player's current level is greater than or equal to the specified
def has_level(skill, level) # level.
return skill_set.get_skill(skill).current_level >= level def level?(skill, level)
skill_set.get_skill(skill).current_level >= level
end end
end end
-27
View File
@@ -1,27 +0,0 @@
# Essentially a wrapper for specific message types to make them easier to use. Only supports the interception of a message type once (for good reason - this is supposed to
# be a utility, not a chain of interceptors inside the existing chain).
#
# Plugins that wish to expand the list of available message types (you probably don't) should use the add_interception method - see the item-on-item script for example usage.
#
# If you only wish to intercept a message, use the intercept method, e.g.
#
# intercept :item_on_item, used_id, target_id, :irreversible do |player, message|
# # code here
# end
# Calls the registered interception(s), if applicable.
def intercept(message, *args, &block)
raise 'Error - interceptions must provide a block.' unless block_given?
interception = INTERCEPTIONS[message]
if interception == nil then raise "No interception for message #{message}" else interception.call(*args, block) end
end
# Adds an interception.
def add_interception(message, &block)
INTERCEPTIONS[message] = block
end
private
INTERCEPTIONS = {}
@@ -1,46 +0,0 @@
# Adds an interception for the ItemOnItem message
add_interception :item_on_item do |used, target, reversible, block|
interception = ItemOnItemPair.new(used, target)
ITEM_PAIRS[interception] = block
ITEM_PAIRS[interception.reverse] = block if reversible == :reversible
end
private
# A hash of ItemOnItemPairs to blocks.
ITEM_PAIRS = {}
# A pair of items that will cause a block to be executed if one (the 'used' item) is used on the other (the 'target' item).
class ItemOnItemPair
attr_reader :used, :target
def initialize(used, target)
@used = used
@target = target
end
# Returns a new ItemOnItemPair that is the reverse of this.
def reverse
return ItemOnItemPair.new(@target, @used)
end
def eql?(other)
return (other.kind_of?(ItemOnItemPair) && @used == other.used && @target == other.target)
end
def hash
return @used << 16 | @target
end
end
# Adds a message listener to the item on item message.
on :message, :item_on_item do |player, message|
used, target = message.id, message.target_id
pair = ItemOnItemPair.new(used, target)
block = ITEM_PAIRS[pair]
block.call(player, message) unless block == nil
end
@@ -2,17 +2,17 @@ require 'java'
# Looks up the id of the npc with the specified name. # Looks up the id of the npc with the specified name.
def lookup_npc(name) def lookup_npc(name)
return lookup_entity(:npc, name) lookup_entity(:npc, name)
end end
# Looks up the id of the item with the specified name. # Looks up the id of the item with the specified name.
def lookup_item(name) def lookup_item(name)
return lookup_entity(:item, name) lookup_entity(:item, name)
end end
# Looks up the id of the object with the specified name. # Looks up the id of the object with the specified name.
def lookup_object(name) def lookup_object(name)
return lookup_entity(:object, name) lookup_entity(:object, name)
end end
# Looks up the id of an entity of the specified type (either :npc, :item, or :object) # Looks up the id of an entity of the specified type (either :npc, :item, or :object)
@@ -24,26 +24,27 @@ def lookup_entity(type, name)
return cached unless cached.nil? return cached unless cached.nil?
id = name[name.rindex(' ') + 1, name.length - 1].to_i if name.include?(' ') id = name[name.rindex(' ') + 1, name.length - 1].to_i if name.include?(' ')
id = find_entities(type, name, 1).first if (id.nil? || id.zero?) id = find_entities(type, name, 1).first if id.nil? || id.zero?
raise "The #{type} called #{name} could not be identified." if id.nil? fail "The #{type} called #{name} could not be identified." if id.nil?
NAME_CACHE[type + name] = id NAME_CACHE[type + name] = id
return id id
end end
# Finds entities with the specified type (e.g. npc) and name, returning possible ids as an array. # Finds entities with the specified type (e.g. npc) and name, returning possible ids as an array.
def find_entities(type, name, limit=5) def find_entities(type, name, limit = 5)
ids = [] ids = []
name.downcase! name.downcase!
Kernel.const_get("#{type.capitalize}Definition").definitions.each do |definition| Kernel.const_get("#{type.capitalize}Definition").definitions.each do |definition|
break if (ids.length == limit) break if (ids.length == limit)
ids << definition.id.to_i if (definition.name.to_s.downcase == name) ids << definition.id.to_i if definition.name.to_s.downcase == name
end end
return ids ids
end end
private private
NAME_CACHE = {} # Primitive, caching all may not be desirable. NAME_CACHE = {} # Primitive, caching all may not be desirable.
+1 -3
View File
@@ -9,9 +9,7 @@
</authors> </authors>
<scripts> <scripts>
<script>command.rb</script> <script>command.rb</script>
<script>intercept.rb</script> <script>name_lookup.rb</script>
<script>item-on-item-intercept.rb</script>
<script>name-lookup.rb</script>
</scripts> </scripts>
<dependencies /> <!-- This plugin should _NOT_ depend on anything. --> <dependencies /> <!-- This plugin should _NOT_ depend on anything. -->
</plugin> </plugin>
@@ -213,8 +213,9 @@ public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState>
private void writeResponseCode(ChannelHandlerContext ctx, int response) { private void writeResponseCode(ChannelHandlerContext ctx, int response) {
ByteBuf buffer = ctx.alloc().buffer(Byte.BYTES); ByteBuf buffer = ctx.alloc().buffer(Byte.BYTES);
buffer.writeByte(response); buffer.writeByte(response);
System.out.println("Sending response: " + response);
ctx.write(buffer).addListener(ChannelFutureListener.CLOSE); ctx.writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE);
} }
} }