wowr 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +6 -34
- data/changelog.txt +31 -0
- data/lib/wowr.rb +338 -308
- data/lib/wowr/arena_team.rb +80 -0
- data/lib/wowr/character.rb +821 -0
- data/lib/wowr/exceptions.rb +75 -10
- data/lib/wowr/extensions.rb +63 -1
- data/lib/wowr/guild.rb +85 -0
- data/lib/wowr/item.rb +616 -0
- metadata +8 -3
- data/lib/wowr/classes.rb +0 -1345
data/lib/wowr/exceptions.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Wowr
|
2
2
|
module Exceptions
|
3
|
-
def self.raise_me(code)
|
4
|
-
#msg = "(#{code.to_s}) #{msg}"
|
3
|
+
def self.raise_me(code, options = {})
|
5
4
|
case code
|
6
5
|
when "noCharacter"
|
7
|
-
raise CharacterNotFound.new("Character
|
6
|
+
raise CharacterNotFound.new("Character '#{options[:character_name]}' not found.")
|
7
|
+
else
|
8
|
+
raise StandardError.new("The XML returned an error: #{code.to_s}")
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
@@ -15,28 +16,92 @@ module Wowr
|
|
15
16
|
end
|
16
17
|
|
17
18
|
class ServerDoesNotExist < StandardError
|
19
|
+
def initialize(string)
|
20
|
+
super "Server at '#{string}' did not respond."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class CharacterNameNotSet < StandardError
|
25
|
+
def initialize
|
26
|
+
super "Character name not set in options or API constructor."
|
27
|
+
end
|
18
28
|
end
|
19
29
|
|
20
|
-
|
21
|
-
|
30
|
+
class GuildNameNotSet < StandardError
|
31
|
+
def initialize
|
32
|
+
super "Guild name not set in options or API constructor."
|
33
|
+
end
|
22
34
|
end
|
23
35
|
|
24
|
-
class
|
36
|
+
class ArenaTeamNameNotSet < StandardError
|
37
|
+
def initialize
|
38
|
+
super "Arena team name not set."
|
39
|
+
end
|
25
40
|
end
|
26
41
|
|
27
|
-
class
|
42
|
+
class InvalidArenaTeamSize < StandardError
|
28
43
|
end
|
29
44
|
|
45
|
+
class RealmNotSet < StandardError
|
46
|
+
def initialize
|
47
|
+
super "Realm not set in options or API constructor."
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Search (fold)
|
30
52
|
class SearchError < StandardError
|
31
53
|
end
|
32
54
|
|
33
|
-
class InvalidSearchType <
|
55
|
+
class InvalidSearchType < SearchError
|
56
|
+
def initialize(string)
|
57
|
+
super "'#{string}' is not a valid search type."
|
58
|
+
end
|
34
59
|
end
|
35
60
|
|
36
|
-
class NoSearchString <
|
61
|
+
class NoSearchString < SearchError
|
62
|
+
def initialize
|
63
|
+
super "No search string specified or string was empty."
|
64
|
+
end
|
37
65
|
end
|
38
66
|
|
39
|
-
class
|
67
|
+
class ElementNotFoundError < StandardError
|
68
|
+
end
|
69
|
+
|
70
|
+
class CharacterNotFound < ElementNotFoundError
|
71
|
+
def initialize(string)
|
72
|
+
super "Character not found with name '#{string}'."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class ItemNotFound < ElementNotFoundError
|
77
|
+
def initialize(string)
|
78
|
+
super "Item not found with name '#{string}'."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class GuildNotFound < ElementNotFoundError
|
83
|
+
def initialize(string)
|
84
|
+
super "Guild not found with name '#{string}'."
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class ArenaTeamNotFound < ElementNotFoundError
|
89
|
+
def initialize(string)
|
90
|
+
super "Arena team not found with name '#{string}'."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
# (end)
|
94
|
+
|
95
|
+
class InvalidIconSize < StandardError
|
96
|
+
def initialize(array)
|
97
|
+
super "Icon size must be: #{array.keys.inspect}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class InvalidIconType < StandardError
|
102
|
+
def initialize(array)
|
103
|
+
super "Icon type must be: #{array.keys.inspect}"
|
104
|
+
end
|
40
105
|
end
|
41
106
|
end
|
42
107
|
end
|
data/lib/wowr/extensions.rb
CHANGED
@@ -1,5 +1,67 @@
|
|
1
1
|
module Wowr
|
2
2
|
module Extensions
|
3
3
|
|
4
|
+
# Rails's cattr_ things. activesupport/lib/active_support/core_ext/class
|
5
|
+
# Really quite handy.
|
6
|
+
# Thanks Reve's Lisa Seelye
|
7
|
+
module Class #:nodoc:
|
8
|
+
def cattr_reader(*syms) #:nodoc:
|
9
|
+
syms.flatten.each do |sym|
|
10
|
+
next if sym.is_a?(Hash)
|
11
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
12
|
+
unless defined? @@#{sym}
|
13
|
+
@@#{sym} = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.#{sym}
|
17
|
+
@@#{sym}
|
18
|
+
end
|
19
|
+
|
20
|
+
def #{sym}
|
21
|
+
@@#{sym}
|
22
|
+
end
|
23
|
+
EOS
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def cattr_writer(*syms) #:nodoc:
|
28
|
+
options = syms.last.is_a?(Hash) ? syms.pop : {}
|
29
|
+
syms.flatten.each do |sym|
|
30
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
31
|
+
unless defined? @@#{sym}
|
32
|
+
@@#{sym} = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.#{sym}=(obj)
|
36
|
+
@@#{sym} = obj
|
37
|
+
end
|
38
|
+
#{"
|
39
|
+
def #{sym}=(obj)
|
40
|
+
@@#{sym} = obj
|
41
|
+
end
|
42
|
+
" unless options[:instance_writer] == false }
|
43
|
+
EOS
|
44
|
+
end
|
45
|
+
end
|
46
|
+
def cattr_accessor(*syms) #:nodoc:
|
47
|
+
cattr_reader(*syms)
|
48
|
+
cattr_writer(*syms)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def stringy(sym) #:nodoc:
|
53
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
54
|
+
def to_s
|
55
|
+
@#{sym}
|
56
|
+
end
|
57
|
+
EOS
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
4
61
|
end
|
5
|
-
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
class Class #:nodoc:
|
66
|
+
include Wowr::Extensions::Class
|
67
|
+
end
|
data/lib/wowr/guild.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'character.rb'
|
5
|
+
|
6
|
+
module Wowr #:nodoc:
|
7
|
+
module Classes #:nodoc:
|
8
|
+
|
9
|
+
# A player guild containing members
|
10
|
+
# Abstract
|
11
|
+
class Guild
|
12
|
+
attr_reader :name, :url, :realm
|
13
|
+
# :roster_url, :stats_url, :stats_url_escape,
|
14
|
+
alias_method :to_s, :name
|
15
|
+
|
16
|
+
def initialize(elem)
|
17
|
+
if (elem%'guildKey')
|
18
|
+
guild = (elem%'guildKey')
|
19
|
+
else
|
20
|
+
guild = elem
|
21
|
+
end
|
22
|
+
|
23
|
+
@name = guild[:name]
|
24
|
+
@url = guild[:url]
|
25
|
+
@realm = guild[:realm]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Basic search information returned by the search.xml
|
30
|
+
# <guilds>
|
31
|
+
# <guild
|
32
|
+
# battleGroup="Ruin"
|
33
|
+
# faction="Alliance"
|
34
|
+
# factionId="0"
|
35
|
+
# name="HAND"
|
36
|
+
# realm="Stormrage"
|
37
|
+
# relevance="100"
|
38
|
+
# url="r=Stormrage&n=HAND&p=1"/>
|
39
|
+
# </guilds>
|
40
|
+
class SearchGuild < Guild
|
41
|
+
attr_reader :faction, :faction_id, :battle_group
|
42
|
+
|
43
|
+
def initialize(elem)
|
44
|
+
super(elem)
|
45
|
+
|
46
|
+
@battle_group = elem[:battleGroup]
|
47
|
+
@faction = elem[:faction]
|
48
|
+
@faction_id = elem[:factionId].to_i
|
49
|
+
|
50
|
+
@relevance = elem[:relevance].to_i
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Full guild data
|
55
|
+
# <guildKey factionId="0" name="HAND" nameUrl="HAND" realm="Stormrage" realmUrl="Stormrage" url="r=Stormrage&n=HAND"/>
|
56
|
+
# <guildInfo>
|
57
|
+
# <guild>
|
58
|
+
# <members filterField="" filterValue="" maxPage="1" memberCount="1" page="1" sortDir="a" sortField="">
|
59
|
+
# <character class="Paladin" classId="2" gender="Male" genderId="0" level="14" name="Sturky" race="Dwarf" raceId="3" rank="0" url="r=Stormrage&n=Sturky"/>
|
60
|
+
# </members>
|
61
|
+
# </guild>
|
62
|
+
# </guildInfo>
|
63
|
+
class FullGuild < Guild
|
64
|
+
attr_reader :members, :name_url, :realm_url #, :member_count
|
65
|
+
|
66
|
+
def initialize(elem)
|
67
|
+
super(elem)
|
68
|
+
|
69
|
+
@name_url = elem[:nameUrl]
|
70
|
+
@realm_url = elem[:realmUrl]
|
71
|
+
|
72
|
+
# Guild/guild_id/guild_url not set for characters
|
73
|
+
if (elem%'guildInfo')
|
74
|
+
# @member_count = (elem%'guildInfo'%'guild'%'members')[:memberCount].to_i || nil
|
75
|
+
@members = {}
|
76
|
+
(elem%'guildInfo'%'guild'%'members'/:character).each do |char|
|
77
|
+
# TODO: Change to search character?
|
78
|
+
members[char[:name]] = Character.new(char)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/wowr/item.rb
ADDED
@@ -0,0 +1,616 @@
|
|
1
|
+
# TODO: Item sources - Vendors
|
2
|
+
# sourceType.vendor
|
3
|
+
# sourceType.questReward
|
4
|
+
# sourceType.createdBySpell
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
7
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
8
|
+
|
9
|
+
module Wowr
|
10
|
+
module Classes
|
11
|
+
|
12
|
+
# Most basic
|
13
|
+
# Composed of an ItemInfo and
|
14
|
+
# Needs to be consolidated with ItemInfo and other stuff
|
15
|
+
# to be a parent class that they extend?
|
16
|
+
# TODO: At the moment needs a reference to the API in order to get the base URL for icons
|
17
|
+
# TODO: Make extend Icon class
|
18
|
+
class Item
|
19
|
+
attr_reader :id, :name, :icon_base
|
20
|
+
alias_method :item_id, :id
|
21
|
+
alias_method :to_s, :name
|
22
|
+
alias_method :to_i, :id
|
23
|
+
|
24
|
+
@@icon_url_base = 'images/icons/'
|
25
|
+
@@icon_sizes = {:large => ['64x64', 'jpg'], :medium => ['43x43', 'png'], :small => ['21x21', 'png']}
|
26
|
+
|
27
|
+
def initialize(elem, api = nil)
|
28
|
+
@api = api
|
29
|
+
|
30
|
+
@id = elem[:id].to_i
|
31
|
+
@name = elem[:name]
|
32
|
+
@icon_base = elem[:icon]
|
33
|
+
end
|
34
|
+
|
35
|
+
def icon(size = :medium)
|
36
|
+
if !@@icon_sizes.include?(size)
|
37
|
+
raise Wowr::Exceptions::InvalidIconSize.new(@@icon_sizes)
|
38
|
+
end
|
39
|
+
|
40
|
+
if @api
|
41
|
+
base = @api.base_url
|
42
|
+
else
|
43
|
+
base = 'http://www.wowarmory.com/'
|
44
|
+
end
|
45
|
+
|
46
|
+
# http://www.wowarmory.com/images/icons/64x64/blahblah.jpg
|
47
|
+
return base + @@icon_url_base + @@icon_sizes[size][0] + '/' + @icon_base + '.' + @@icon_sizes[size][1]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Full data from item-info and item-tooltip
|
52
|
+
class FullItem < Item
|
53
|
+
|
54
|
+
def initialize(info, tooltip, api = nil)
|
55
|
+
super(info, api)
|
56
|
+
@info = ItemInfo.new(info, api)
|
57
|
+
@tooltip = ItemTooltip.new(tooltip, api)
|
58
|
+
end
|
59
|
+
|
60
|
+
def method_missing(m, *args)
|
61
|
+
begin
|
62
|
+
return @info.send(m, *args)
|
63
|
+
rescue NoMethodError => e
|
64
|
+
begin
|
65
|
+
return @tooltip.send(m, *args)
|
66
|
+
rescue
|
67
|
+
raise NoMethodError.new("undefined method '#{m}' for #{self.class}")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
# uses item-info.xml
|
77
|
+
class ItemInfo < Item
|
78
|
+
attr_reader :level, :quality, :type,
|
79
|
+
:cost, :disenchant_items, :disenchant_skill_rank, :vendors,
|
80
|
+
:objective_of_quests,
|
81
|
+
:reward_from_quests,
|
82
|
+
:drop_creatures,
|
83
|
+
:plans_for, :created_by
|
84
|
+
|
85
|
+
alias_method :disenchants, :disenchant_items
|
86
|
+
|
87
|
+
def initialize(elem, api = nil)
|
88
|
+
super(elem, api)
|
89
|
+
|
90
|
+
@level = elem[:level].to_i
|
91
|
+
@quality = elem[:quality].to_i
|
92
|
+
@type = elem[:type]
|
93
|
+
|
94
|
+
# Cost can be in gold, or tokens
|
95
|
+
@cost = ItemCost.new(elem%'cost') if (elem%'cost')
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
# is costs really an array?
|
100
|
+
#@costs = []
|
101
|
+
#(elem/:cost).each do |cost|
|
102
|
+
# @costs << ItemCost.new(cost)
|
103
|
+
#end
|
104
|
+
|
105
|
+
etc = [
|
106
|
+
['disenchantLoot', '@disenchant_items', 'item', DisenchantItem, true],
|
107
|
+
['objectiveOfQuests', '@objective_of_quests', 'quest', ItemQuest, false],
|
108
|
+
['rewardFromQuests', '@reward_from_quests', 'quest', ItemQuest, false],
|
109
|
+
['vendors', '@vendors', 'creature', ItemVendor, false],
|
110
|
+
['dropCreatures', '@drop_creatures', 'creature', ItemDropCreature, false],
|
111
|
+
['plansFor', '@plans_for', 'spell', ItemPlansFor, true],
|
112
|
+
['createdBy', '@created_by', 'spell', ItemCreatedBy, true],
|
113
|
+
]
|
114
|
+
|
115
|
+
etc.each do |b|
|
116
|
+
ele = b[0]
|
117
|
+
var = b[1]
|
118
|
+
list = b[2]
|
119
|
+
my_class = b[3]
|
120
|
+
requires_api = b[4]
|
121
|
+
|
122
|
+
if elem%ele
|
123
|
+
tmp_arr = []
|
124
|
+
(elem%ele/list).each do |x|
|
125
|
+
if requires_api
|
126
|
+
tmp_arr << my_class.new(x, api)
|
127
|
+
else
|
128
|
+
tmp_arr << my_class.new(x)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
self.instance_variable_set(var, tmp_arr)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
if (elem%'disenchantLoot')
|
136
|
+
@disenchant_skill_rank = (elem%'disenchantLoot')[:requiredSkillRank].to_i
|
137
|
+
|
138
|
+
# @disenchant_items = []
|
139
|
+
# (elem%'disenchantLoot'/:item).each do |item|
|
140
|
+
# @disenchant_items << DisenchantItem.new(item)
|
141
|
+
# end
|
142
|
+
end
|
143
|
+
|
144
|
+
# if (elem%'objectiveOfQuests')
|
145
|
+
# @objective_of_quests = []
|
146
|
+
# (elem%'objectiveOfQuests'/:quest).each do |quest|
|
147
|
+
# @objective_of_quests << ItemQuest.new(quest)
|
148
|
+
# end
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# if (elem%'rewardFromQuests')
|
152
|
+
# @reward_from_quests = []
|
153
|
+
# (elem%'rewardFromQuests'/:quest).each do |quest|
|
154
|
+
# @reward_from_quests << ItemQuest.new(quest)
|
155
|
+
# end
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# if (elem%'vendors')
|
159
|
+
# @vendors = []
|
160
|
+
# (elem%'vendors'/:creature).each do |vendor|
|
161
|
+
# @vendors << ItemVendor.new(vendor)
|
162
|
+
# end
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# if (elem%'dropCreatures')
|
166
|
+
# @drop_creatures = []
|
167
|
+
# (elem%'dropCreatures'/:creature).each do |creature|
|
168
|
+
# @drop_creatures << ItemDropCreature.new(creature)
|
169
|
+
# end
|
170
|
+
# end
|
171
|
+
#
|
172
|
+
# if (elem%'plansFor')
|
173
|
+
# @plans_for = []
|
174
|
+
# (elem%'plansFor'/:spell).each do |plan|
|
175
|
+
# @plans_for << ItemPlansFor.new(plan)
|
176
|
+
# end
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# if (elem%'createdBy')
|
180
|
+
# @created_by = []
|
181
|
+
# (elem%'createdBy'/:spell).each do |c|
|
182
|
+
# @created_by << ItemCreatedBy.new(c)
|
183
|
+
# end
|
184
|
+
# end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
# Provides detailed item information
|
191
|
+
# Note that the item-tooltip.xml just returns an empty document when the item
|
192
|
+
# can't be found.
|
193
|
+
class ItemTooltip < Item
|
194
|
+
attr_reader :desc, :overall_quality_id, :bonding, :max_count, #:id, :name, :icon,
|
195
|
+
:class_id, :bonuses, :item_source,
|
196
|
+
:bonuses, :resistances,
|
197
|
+
:required_level,
|
198
|
+
:allowable_classes,
|
199
|
+
:armor, :durability,
|
200
|
+
:sockets, :socket_match_enchant,
|
201
|
+
:gem_properties
|
202
|
+
alias_method :description, :desc
|
203
|
+
|
204
|
+
def initialize(elem, api = nil)
|
205
|
+
super(elem, api)
|
206
|
+
@id = (elem%'id').html.to_i
|
207
|
+
@name = (elem%'name').html
|
208
|
+
@icon_base = (elem%'icon').html
|
209
|
+
@desc = (elem%'desc').html if (elem%'desc')
|
210
|
+
@overall_quality_id = (elem%'overallQualityId').html.to_i
|
211
|
+
@bonding = (elem%'bonding').html.to_i
|
212
|
+
@stackable = (elem%'stackable').html.to_i if (elem%'stackable')
|
213
|
+
@max_count = (elem%'maxCount').html.to_i if (elem%'maxCount')
|
214
|
+
@class_id = (elem%'classId').html.to_i
|
215
|
+
@required_level = (elem%'requiredLevel').html.to_i if (elem%'requiredLevel')
|
216
|
+
|
217
|
+
@equipData = ItemEquipData.new(elem%'equipData')
|
218
|
+
|
219
|
+
# TODO: This appears to be a plain string at the moment
|
220
|
+
#<gemProperties>+26 Healing +9 Spell Damage and 2% Reduced Threat</gemProperties>
|
221
|
+
@gem_properties = (elem%'gemProperties').html if (elem%'gemProperties')
|
222
|
+
|
223
|
+
# not all items have damage data
|
224
|
+
@damage = ItemDamageData.new(elem%'damageData') if !(elem%'damageData').html.empty?
|
225
|
+
|
226
|
+
|
227
|
+
# TODO: Test socket data with a variety of items
|
228
|
+
# TODO: replace with socket Class?
|
229
|
+
if (elem%'socketData')
|
230
|
+
@sockets = []
|
231
|
+
(elem%'socketData'/:socket).each do |socket|
|
232
|
+
@sockets << socket[:color]
|
233
|
+
end
|
234
|
+
|
235
|
+
@socket_match_enchant = (elem%'socketData'%'socketMatchEnchant')
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
# When there is no data, stats are not present in @bonuses
|
240
|
+
# TODO: When there is no stats at all, @bonuses shouldn't be set
|
241
|
+
@bonuses = {}
|
242
|
+
|
243
|
+
bonus_stats = {
|
244
|
+
:strength => :bonusStrength,
|
245
|
+
:agility => :bonusAgility,
|
246
|
+
:stamina => :bonusStamina,
|
247
|
+
:intellect => :bonusIntellect,
|
248
|
+
:spirit => :bonusSpirit
|
249
|
+
}
|
250
|
+
bonus_stats.each do |stat, xml_elem|
|
251
|
+
@bonuses[stat] = test_stat(elem/xml_elem) if test_stat(elem/xml_elem)
|
252
|
+
end
|
253
|
+
|
254
|
+
# Resistances
|
255
|
+
@resistances = {}
|
256
|
+
|
257
|
+
resist_stats = {
|
258
|
+
:arcane => :arcaneResist,
|
259
|
+
:fire => :fireResist,
|
260
|
+
:frost => :frostResist,
|
261
|
+
:holy => :holyResist,
|
262
|
+
:nature => :natureResist,
|
263
|
+
:shadow => :shadowResist
|
264
|
+
}
|
265
|
+
resist_stats.each do |stat, xml_elem|
|
266
|
+
@resistances[stat] = test_stat(elem/xml_elem) if test_stat(elem/xml_elem)
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
if (elem%'allowableClasses')
|
271
|
+
@allowable_classes = []
|
272
|
+
(elem%'allowableClasses'/:class).each do |klass|
|
273
|
+
@allowable_classes << klass.html
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# NOTE not representing armor bonus
|
278
|
+
@armor = (elem%'armor').html.to_i if (elem%'armor')
|
279
|
+
|
280
|
+
# NOTE not representing max
|
281
|
+
@durability = (elem%'durability')[:current].to_i if (elem%'durability')
|
282
|
+
|
283
|
+
if (elem%'spellData')
|
284
|
+
@spells = []
|
285
|
+
(elem%'spellData'/:spell).each do |spell|
|
286
|
+
@spells << ItemSpell.new(spell)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
@setData = ItemSetData.new(elem%'setData') if (elem%'setData')
|
291
|
+
|
292
|
+
# @item_sources = []
|
293
|
+
# (elem/:itemSource).each do |source|
|
294
|
+
# @item_sources << ItemSource.new(source)
|
295
|
+
# end
|
296
|
+
@item_source = ItemSource.new(elem%'itemSource') if (elem%'itemSource') # TODO: More than once source?
|
297
|
+
end
|
298
|
+
|
299
|
+
private
|
300
|
+
def test_stat(elem)
|
301
|
+
if elem
|
302
|
+
if !elem.html.empty?
|
303
|
+
return elem.html.to_i
|
304
|
+
end
|
305
|
+
end
|
306
|
+
return nil
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
class ItemEquipData
|
311
|
+
attr_reader :inventory_type, :subclass_name, :container_slots
|
312
|
+
|
313
|
+
def initialize(elem)
|
314
|
+
@inventory_type = (elem%'inventoryType').html.to_i
|
315
|
+
@subclass_name = (elem%'subclassName').html if (elem%'subclassName')
|
316
|
+
@container_slots = (elem%'containerSlots').html.to_i if (elem%'containerSlots') # for baggies
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
class ItemSetData
|
321
|
+
attr_reader :name, :items, :set_bonuses
|
322
|
+
alias_method :to_s, :name
|
323
|
+
|
324
|
+
def initialize(elem)
|
325
|
+
@name = elem[:name]
|
326
|
+
|
327
|
+
@items = []
|
328
|
+
(elem/:item).each do |item|
|
329
|
+
@items << item[:name]
|
330
|
+
end
|
331
|
+
|
332
|
+
@set_bonuses = []
|
333
|
+
(elem/:setBonus).each do |bonus|
|
334
|
+
@set_bonuses << ItemSetBonus.new(bonus)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
class ItemSetBonus
|
340
|
+
attr_reader :threshold, :description
|
341
|
+
alias_method :desc, :description
|
342
|
+
alias_method :to_s, :description
|
343
|
+
|
344
|
+
def initialize(elem)
|
345
|
+
@threshold = elem[:threshold].to_i
|
346
|
+
@description = elem[:desc]
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
class ItemSpell
|
351
|
+
attr_reader :trigger, :description
|
352
|
+
alias_method :desc, :description
|
353
|
+
alias_method :to_s, :description
|
354
|
+
|
355
|
+
def initialize(elem)
|
356
|
+
@trigger = (elem%'trigger').html.to_i
|
357
|
+
@description = (elem%'desc').html
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
class ItemDamageData
|
362
|
+
attr_reader :type, :min, :max, :speed, :dps
|
363
|
+
|
364
|
+
def initialize(elem)
|
365
|
+
@type = (elem%'damage'%'type').html.to_i
|
366
|
+
@min = (elem%'damage'%'min').html.to_i
|
367
|
+
@max = (elem%'damage'%'max').html.to_i
|
368
|
+
@speed = (elem%'speed').html.to_i
|
369
|
+
@dps = (elem%'dps').html.to_f
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
class ItemSource
|
374
|
+
attr_reader :value,
|
375
|
+
:area_id, :area_name,
|
376
|
+
:creature_id, :creature_name,
|
377
|
+
:difficulty, :drop_rate
|
378
|
+
|
379
|
+
def initialize(elem)
|
380
|
+
@value = elem[:value]
|
381
|
+
@area_id = elem[:areaId].to_i if elem[:areaId]
|
382
|
+
@area_name = elem[:areaName] if elem[:areaName]
|
383
|
+
@creature_id = elem[:creatureId].to_i if elem[:creatureId]
|
384
|
+
@creature_name = elem[:creatureName] if elem[:creatureName]
|
385
|
+
@difficulty = elem[:difficulty] if elem[:difficulty]
|
386
|
+
@drop_rate = elem[:dropRate].to_i if elem[:dropRate]
|
387
|
+
@required_level = elem[:reqLvl].to_i if elem[:reqLvl]
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
|
392
|
+
|
393
|
+
# A really basic item type returned by searches
|
394
|
+
class SearchItem < Item
|
395
|
+
attr_reader :url, :rarity,
|
396
|
+
:source, :item_level, :relevance
|
397
|
+
alias_method :level, :item_level
|
398
|
+
|
399
|
+
def initialize(elem, api = nil)
|
400
|
+
super(elem, api)
|
401
|
+
@rarity = elem[:rarity].to_i
|
402
|
+
@url = elem[:url]
|
403
|
+
|
404
|
+
@item_level = elem.at("filter[@name='itemLevel']")[:value].to_i
|
405
|
+
@source = elem.at("filter[@name='source']")[:value]
|
406
|
+
@relevance = elem.at("filter[@name='relevance']")[:value].to_i
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
|
411
|
+
|
412
|
+
|
413
|
+
# <rewardFromQuests>
|
414
|
+
# <quest name="Justice Dispensed" level="39" reqMinLevel="30" id="11206" area="Dustwallow Marsh" suggestedPartySize="0"></quest>
|
415
|
+
# <quest name="Peace at Last" level="39" reqMinLevel="30" id="11152" area="Dustwallow Marsh" suggestedPartySize="0"></quest>
|
416
|
+
# </rewardFromQuests>
|
417
|
+
# TODO: Rename
|
418
|
+
class ItemQuest
|
419
|
+
attr_reader :name, :id, :level, :min_level, :area, :suggested_party_size
|
420
|
+
|
421
|
+
def initialize(elem)
|
422
|
+
@name = elem[:name]
|
423
|
+
@id = elem[:id].to_i
|
424
|
+
@level = elem[:level].to_i
|
425
|
+
@min_level = elem[:min_level].to_i
|
426
|
+
@area = elem[:area]
|
427
|
+
@suggested_party_size = elem[:suggested_party_size].to_i
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
|
432
|
+
|
433
|
+
# Creatures that drop the item
|
434
|
+
# <creature name="Giant Marsh Frog" minLevel="1" type="Critter" maxLevel="1" dropRate="6" id="23979" classification="0" area="Dustwallow Marsh"></creature>
|
435
|
+
# <creature name="Nalorakk" minLevel="73" title="Bear Avatar" url="fl[source]=dungeon&fl[difficulty]=normal&fl[boss]=23576" type="Humanoid" maxLevel="73" dropRate="2" id="23576" classification="3" areaUrl="fl[source]=dungeon&fl[boss]=all&fl[difficulty]=normal&fl[dungeon]=3805" area="Zul'Aman"></creature>
|
436
|
+
class ItemDropCreature
|
437
|
+
attr_reader :name, :id, :type, :min_level, :max_level, :drop_rate, :classification, :area
|
438
|
+
|
439
|
+
def initialize(elem)
|
440
|
+
@name = elem[:name]
|
441
|
+
@id = elem[:id].to_i
|
442
|
+
@min_level = elem[:minLevel].to_i
|
443
|
+
@max_level = elem[:maxLevel].to_i
|
444
|
+
@drop_rate = elem[:dropRate].to_i
|
445
|
+
@classification = elem[:classification].to_i
|
446
|
+
@area = elem[:area]
|
447
|
+
|
448
|
+
# optional boss stuff
|
449
|
+
@title = elem[:title] if elem[:title] # TODO: not nil when no property?
|
450
|
+
@url = elem[:url] if elem[:url]
|
451
|
+
@type = elem[:type] if elem[:type] # Humanoid etc.
|
452
|
+
@area_url = elem[:areaUrl] if elem[:areaUrl]
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
# Cost can be gold or a set of required tokens
|
457
|
+
# See ItemCostToken
|
458
|
+
# <cost sellPrice="280" buyPrice="5600"></cost>
|
459
|
+
# <cost>
|
460
|
+
# <token icon="spell_holy_championsbond" id="29434" count="60"></token>
|
461
|
+
# </cost>
|
462
|
+
class ItemCost
|
463
|
+
attr_reader :buy_price, :sell_price, :tokens
|
464
|
+
|
465
|
+
def initialize(elem)
|
466
|
+
@buy_price = elem[:buyPrice].to_i if elem[:buyPrice]
|
467
|
+
@sell_price = elem[:sellPrice].to_i if elem[:sellPrice]
|
468
|
+
|
469
|
+
if (elem%'token')
|
470
|
+
@tokens = []
|
471
|
+
(elem/:token).each do |token|
|
472
|
+
@tokens << ItemCostToken.new(token)
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
# <token icon="spell_holy_championsbond" id="29434" count="60"></token>
|
479
|
+
class ItemCostToken < Item
|
480
|
+
attr_reader :count
|
481
|
+
|
482
|
+
def initialize(elem, api = nil)
|
483
|
+
super(elem)
|
484
|
+
# @id = elem[:id].to_i
|
485
|
+
# @icon_bse = elem[:icon]
|
486
|
+
@count = elem[:count].to_i
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
# <item name="Void Crystal" minCount="1" maxCount="2" icon="inv_enchant_voidcrystal" type="Enchanting" level="70" dropRate="6" id="22450" quality="4"></item>
|
491
|
+
class DisenchantItem < Item
|
492
|
+
attr_reader :level, :type, :drop_rate, :min_count, :max_count, :quality
|
493
|
+
# :name, :id, :icon,
|
494
|
+
|
495
|
+
def initialize(elem, api = nil)
|
496
|
+
super(elem, api)
|
497
|
+
# @name = elem[:name]
|
498
|
+
# @id = elem[:id].to_i
|
499
|
+
# @icon = elem[:icon]
|
500
|
+
@level = elem[:level].to_i
|
501
|
+
@type = elem[:type]
|
502
|
+
@drop_rate = elem[:dropRate].to_i
|
503
|
+
@min_count = elem[:minCount].to_i
|
504
|
+
@max_count = elem[:maxCount].to_i
|
505
|
+
@quality = elem[:quality].to_i
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
|
510
|
+
class ItemVendor
|
511
|
+
attr_reader :id, :name, :title, :type,
|
512
|
+
:area, :classification, :max_level, :min_level
|
513
|
+
alias_method :to_s, :name
|
514
|
+
alias_method :to_i, :id
|
515
|
+
|
516
|
+
def initialize(elem)
|
517
|
+
@id = elem[:id].to_i
|
518
|
+
@name = elem[:name]
|
519
|
+
@title = elem[:title]
|
520
|
+
@type = elem[:type]
|
521
|
+
@area = elem[:area]
|
522
|
+
@classification = elem[:classification].to_i
|
523
|
+
@max_level = elem[:maxLevel].to_i
|
524
|
+
@min_level = elem[:minLevel].to_i
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
|
529
|
+
|
530
|
+
# TODO rename
|
531
|
+
# There is some sort of opposite relationship between PlansFor and CreatedBy
|
532
|
+
class ItemCreation < Item
|
533
|
+
attr_reader :item, :reagents
|
534
|
+
|
535
|
+
def initialize(elem, api = nil)
|
536
|
+
super(elem, api)
|
537
|
+
|
538
|
+
if (elem%'reagent')
|
539
|
+
@reagents = []
|
540
|
+
(elem/:reagent).each do |reagent|
|
541
|
+
@reagents << Reagent.new(reagent, api)
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
# (fold)
|
548
|
+
# <plansFor>
|
549
|
+
# <spell name="Shadowprowler's Chestguard" icon="trade_leatherworking" id="42731">
|
550
|
+
# <item name="Shadowprowler's Chestguard" icon="inv_chest_plate11" type="Leather" level="105" id="33204" quality="4"></item>
|
551
|
+
# <reagent name="Heavy Knothide Leather" icon="inv_misc_leatherscrap_11" id="23793" count="10"></reagent>
|
552
|
+
# </spell>
|
553
|
+
# </plansFor>
|
554
|
+
# (end)
|
555
|
+
class ItemPlansFor < ItemCreation
|
556
|
+
def initialize(elem, api = nil)
|
557
|
+
super(elem, api)
|
558
|
+
# TODO: Multiple items?
|
559
|
+
@item = CreatedItem.new(elem%'item') if (elem%'item')
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
# <createdBy>
|
564
|
+
# <spell name="Bracing Earthstorm Diamond" icon="temp" id="32867">
|
565
|
+
# <item requiredSkill="Jewelcrafting" name="Design: Bracing Earthstorm Diamond" icon="inv_scroll_03" type="Jewelcrafting" level="73" id="25903" requiredSkillRank="365" quality="1"></item>
|
566
|
+
# <reagent name="Earthstorm Diamond" icon="inv_misc_gem_diamond_04" id="25867" count="1"></reagent>
|
567
|
+
# </spell>
|
568
|
+
# </createdBy>
|
569
|
+
class ItemCreatedBy < ItemCreation
|
570
|
+
def initialize(elem, api = nil)
|
571
|
+
super(elem, api)
|
572
|
+
# TODO: Multiple items?
|
573
|
+
@item = PlanItem.new(elem%'item') if (elem%'item')
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
|
578
|
+
# <item name="Shadowprowler's Chestguard" icon="inv_chest_plate11" type="Leather" level="105" id="33204" quality="4"></item>
|
579
|
+
class CreatedItem < Item
|
580
|
+
attr_reader :type, :level, :quality
|
581
|
+
|
582
|
+
def initialize(elem, api = nil)
|
583
|
+
super(elem, api)
|
584
|
+
@type = elem[:type]
|
585
|
+
@level = elem[:level].to_i
|
586
|
+
@quality = elem[:quality].to_i
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
# <item requiredSkill="Jewelcrafting" name="Design: Bracing Earthstorm Diamond" icon="inv_scroll_03" type="Jewelcrafting" level="73" id="25903" requiredSkillRank="365" quality="1"></item>
|
591
|
+
class PlanItem < Item
|
592
|
+
attr_reader :required_skill, :type, :required_skill_rank, :level, :quality
|
593
|
+
|
594
|
+
def initialize(elem, api = nil)
|
595
|
+
super(elem, api)
|
596
|
+
@type = elem[:type]
|
597
|
+
@level = elem[:level].to_i
|
598
|
+
@quality = elem[:quality].to_i
|
599
|
+
@required_skill = elem[:requiredSkill]
|
600
|
+
@required_skill_rank = elem[:requiredSkillRank].to_i
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
class Reagent < Item
|
605
|
+
attr_reader :count
|
606
|
+
|
607
|
+
def initialize(elem, api = nil)
|
608
|
+
super(elem, api)
|
609
|
+
# @id = elem[:id].to_i
|
610
|
+
# @name = elem[:name]
|
611
|
+
# @icon = elem[:icon]
|
612
|
+
@count = elem[:count].to_i
|
613
|
+
end
|
614
|
+
end
|
615
|
+
end
|
616
|
+
end
|