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
@@ -0,0 +1,80 @@
|
|
1
|
+
module Wowr
|
2
|
+
module Classes
|
3
|
+
class ArenaTeam
|
4
|
+
attr_reader :name, :size, :battle_group, :faction, :faction_id, :realm, :realm_url,
|
5
|
+
:games_played, :games_won, :ranking, :rating,
|
6
|
+
:season_games_played, :season_games_won, :last_season_ranking,
|
7
|
+
:relevance, :url, :url_escape,
|
8
|
+
:characters, # can be blank on search results
|
9
|
+
:emblem
|
10
|
+
alias_method :to_s, :name
|
11
|
+
|
12
|
+
def initialize(elem)
|
13
|
+
@name = elem[:name]
|
14
|
+
@size = elem[:size].to_i
|
15
|
+
@battle_group = elem[:battleGroup]
|
16
|
+
@faction = elem[:faction]
|
17
|
+
@faction_id = elem[:factionId].to_i
|
18
|
+
@realm = elem[:realm]
|
19
|
+
@realm_url = elem[:realmUrl]
|
20
|
+
|
21
|
+
@games_played = elem[:gamesPlayed].to_i
|
22
|
+
@games_won = elem[:gamesWon].to_i
|
23
|
+
# @ranking = elem[:ranking].to_i # Ranking in the seach results is always 0
|
24
|
+
@rating = elem[:rating].to_i
|
25
|
+
|
26
|
+
@season_games_played = elem[:seasonGamesPlayed].to_i
|
27
|
+
@season_games_won = elem[:seasonGamesWon].to_i
|
28
|
+
@last_season_ranking = elem[:lastSeasonRanking].to_i
|
29
|
+
|
30
|
+
@relevance = elem[:relevance].to_i
|
31
|
+
@url = elem[:url]
|
32
|
+
|
33
|
+
@emblem = ArenaTeamEmblem.new(elem%'emblem')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
class SearchArenaTeam < ArenaTeam
|
39
|
+
def initialize(elem)
|
40
|
+
super(elem)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# <teamInfo>
|
45
|
+
# <arenaTeam battleGroup="Vindication" faction="Alliance" factionId="0" gamesPlayed="6" gamesWon="1" lastSeasonRanking="4118" name="Monkey" ranking="6522" rating="1535" realm="Burning Blade" realmUrl="b=Vindication&r=Burning+Blade&ts=2&t=Monkey&ff=realm&fv=Burning+Blade&select=Monkey" relevance="0" seasonGamesPlayed="66" seasonGamesWon="34" size="2" url="r=Burning+Blade&ts=2&t=Monkey&select=Monkey" urlEscape="r=Burning+Blade&ts=2&t=Monkey&select=Monkey">
|
46
|
+
# <emblem background="ff70de56" borderColor="ffcc73eb" borderStyle="6" iconColor="ffe3b320" iconStyle="44"/>
|
47
|
+
# <members>
|
48
|
+
# <character battleGroup="Vindication" charUrl="r=Burning+Blade&n=Fandiar" class="Priest" classId="5" contribution="1380" gamesPlayed="0" gamesWon="0" gender="Male" genderId="0" guild="Legends" guildId="916" guildUrl="r=Burning+Blade&n=Legends&p=1" name="Fandiar" race="Night Elf" raceId="4" realm="Burning Blade" seasonGamesPlayed="18" seasonGamesWon="1" teamRank="0"/>
|
49
|
+
# <character battleGroup="Vindication" charUrl="r=Burning+Blade&n=Stayfrosty" class="Mage" classId="8" contribution="1460" gamesPlayed="6" gamesWon="1" gender="Male" genderId="0" guild="Legends" guildId="916" guildUrl="r=Burning+Blade&n=Legends&p=1" name="Stayfrosty" race="Human" raceId="1" realm="Burning Blade" seasonGamesPlayed="6" seasonGamesWon="1" teamRank="1"/>
|
50
|
+
# <character battleGroup="Vindication" charUrl="r=Burning+Blade&n=Step" class="Rogue" classId="4" contribution="1688" gamesPlayed="2" gamesWon="1" gender="Female" genderId="1" guild="Legends" guildId="916" guildUrl="r=Burning+Blade&n=Legends&p=1" name="Step" race="Human" raceId="1" realm="Burning Blade" seasonGamesPlayed="44" seasonGamesWon="33" teamRank="1"/>
|
51
|
+
# </members>
|
52
|
+
# </arenaTeam>
|
53
|
+
# </teamInfo>
|
54
|
+
class FullArenaTeam < ArenaTeam
|
55
|
+
|
56
|
+
def initialize(elem)
|
57
|
+
super(elem)
|
58
|
+
# @ranking = elem[:ranking].to_i
|
59
|
+
|
60
|
+
@members = {}
|
61
|
+
(elem%'members'/:character).each do |character|
|
62
|
+
@members[character[:name]] = SearchCharacter.new(character)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# An arena team's logo
|
68
|
+
class ArenaTeamEmblem
|
69
|
+
attr_reader :background, :border_color, :border_style, :icon_colour, :icon_style
|
70
|
+
|
71
|
+
def initialize(elem)
|
72
|
+
@background = elem[:background]
|
73
|
+
@border_color = elem[:borderColor]
|
74
|
+
@border_style = elem[:borderStyle].to_i
|
75
|
+
@icon_color = elem[:iconColor]
|
76
|
+
@icon_style = elem[:iconStyle].to_i
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,821 @@
|
|
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 'wowr/item.rb'
|
5
|
+
|
6
|
+
module Wowr
|
7
|
+
module Classes
|
8
|
+
|
9
|
+
# Short character info, used in guild lists etc.
|
10
|
+
# Note that the way that searches and character listings within guilds works,
|
11
|
+
# there can be a variable amount of information filled in within the class.
|
12
|
+
# Guild listings and search results contain a smaller amount of information than
|
13
|
+
# single queries
|
14
|
+
# Attributes
|
15
|
+
# * name (String) - Full character name
|
16
|
+
# * level (Fixnum) - Level
|
17
|
+
# See Also: Guild
|
18
|
+
class Character
|
19
|
+
attr_reader :name, :level, :url, :rank,
|
20
|
+
:klass, :klass_id,
|
21
|
+
:gender, :gender_id,
|
22
|
+
:race, :race_id,
|
23
|
+
:guild, :guild_id, :guild_url,
|
24
|
+
:realm,
|
25
|
+
:battle_group, :last_login,
|
26
|
+
:relevance, :search_rank,
|
27
|
+
|
28
|
+
:season_games_played, :season_games_won, :team_rank, :contribution # From ArenaTeam info
|
29
|
+
|
30
|
+
alias_method :to_s, :name
|
31
|
+
alias_method :to_i, :level
|
32
|
+
|
33
|
+
@@race_icon_url_base = 'images/icons/race/'
|
34
|
+
@@class_icon_url_base = 'images/icons/class/'
|
35
|
+
@@portrait_url_base = 'images/portraits/'
|
36
|
+
@@icon_types = {:default => 'wow-default', 70 => 'wow-70', :other => 'wow'}
|
37
|
+
|
38
|
+
def initialize(elem, api = nil)
|
39
|
+
@api = api
|
40
|
+
|
41
|
+
@name = elem[:name]
|
42
|
+
@level = elem[:level].to_i
|
43
|
+
@url = elem[:url] || elem[:charUrl]
|
44
|
+
@rank = elem[:rank].to_i
|
45
|
+
|
46
|
+
@klass = elem[:class]
|
47
|
+
@klass_id = elem[:classId].to_i
|
48
|
+
|
49
|
+
@gender = elem[:gender]
|
50
|
+
@gender_id = elem[:genderId].to_i
|
51
|
+
|
52
|
+
@race = elem[:race]
|
53
|
+
@race_id = elem[:raceId].to_i
|
54
|
+
|
55
|
+
@guild = elem[:guild] == "" ? nil : elem[:guild]
|
56
|
+
@guild_id = elem[:guildId].to_i == 0 ? nil : elem[:guildId].to_i
|
57
|
+
@guild_url = elem[:guildUrl] == "" ? nil : elem[:guildUrl]
|
58
|
+
|
59
|
+
@realm = elem[:realm] == "" ? nil : elem[:realm]
|
60
|
+
|
61
|
+
@battle_group = elem[:battleGroup] == "" ? nil : elem[:battleGroup]
|
62
|
+
@battle_group_id = elem[:battleGroupId].to_i
|
63
|
+
|
64
|
+
@relevance = elem[:relevance].to_i
|
65
|
+
@search_rank = elem[:searchRank].to_i
|
66
|
+
|
67
|
+
# Incoming string is 2007-02-24 20:33:04.0, parse to datetime
|
68
|
+
#@last_login = elem[:lastLoginDate] == "" ? nil : DateTime.parse(elem[:lastLoginDate])
|
69
|
+
@last_login = elem[:lastLoginDate] == "" ? nil : elem[:lastLoginDate]
|
70
|
+
|
71
|
+
# From ArenaTeam info, can be blank on normal requests
|
72
|
+
#<character battleGroup="" charUrl="r=Draenor&n=Lothaar" class="Paladin" classId="2"
|
73
|
+
# contribution="1602" gamesPlayed="10" gamesWon="7" gender="Male" genderId="0"
|
74
|
+
# guild="Passion" guildId="36659" guildUrl="r=Draenor&n=Passion&p=1" name="Lothaar"
|
75
|
+
# race="Human" raceId="1" seasonGamesPlayed="20" seasonGamesWon="13" teamRank="1"/>
|
76
|
+
@season_games_played = elem[:seasonGamesPlayed] == "" ? nil : elem[:seasonGamesPlayed].to_i
|
77
|
+
@season_games_won = elem[:seasonGamesWon] == "" ? nil : elem[:seasonGamesWon].to_i
|
78
|
+
@team_rank = elem[:teamRank] == "" ? nil : elem[:teamRank].to_i
|
79
|
+
@contribution = elem[:contribution] == "" ? nil : elem[:contribution].to_i
|
80
|
+
#@char_url = elem[:charUrl] # TODO: Merge with URL?
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def icon(type = nil)
|
85
|
+
if !type.nil? && !@@icon_types.include?(type)
|
86
|
+
raise Wowr::Exceptions::InvalidIconType.new(@@icon_types)
|
87
|
+
end
|
88
|
+
|
89
|
+
if (type.nil?) && (@level == 70)
|
90
|
+
dir = @@icon_types[70]
|
91
|
+
elsif (type.nil?)
|
92
|
+
dir = @@icon_types[:other]
|
93
|
+
else
|
94
|
+
dir = @@icon_types[type]
|
95
|
+
end
|
96
|
+
|
97
|
+
# http://armory.worldofwarcraft.com/images/portraits/wow-70/1-7-8.gif
|
98
|
+
return base + @@portrait_url_base + dir + "/#{@gender_id}-#{@race_id}-#{@klass_id}.gif"
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
def race_icon
|
103
|
+
# http://armory.worldofwarcraft.com/images/icons/race/11-1.gif
|
104
|
+
return base + @@race_icon_url_base + "#{@race_id}-#{@gender_id.to_s}.gif"
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
def class_icon
|
109
|
+
# http://armory.worldofwarcraft.com/images/icons/class/8.gif
|
110
|
+
return base + @@class_icon_url_base + "#{@klass_id.to_s}.gif"
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
protected
|
115
|
+
def base
|
116
|
+
if @api
|
117
|
+
return @api.base_url
|
118
|
+
else
|
119
|
+
return 'http://www.wowarmory.com/'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class SearchCharacter < Character
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# Full character details
|
129
|
+
# uses characterInfo element
|
130
|
+
# Made up of two parts, character and charactertab
|
131
|
+
class FullCharacter < Character
|
132
|
+
|
133
|
+
# character_info
|
134
|
+
attr_reader :char_url, :title,
|
135
|
+
:faction, :faction_id,
|
136
|
+
:arena_teams,
|
137
|
+
:last_modified
|
138
|
+
|
139
|
+
# character_tab
|
140
|
+
attr_reader :health, :second_bar,
|
141
|
+
:strength, :agility, :stamina, :intellect, :spirit
|
142
|
+
alias_method :str, :strength
|
143
|
+
alias_method :agi, :agility
|
144
|
+
alias_method :sta, :stamina
|
145
|
+
alias_method :int, :intellect
|
146
|
+
alias_method :spi, :spirit
|
147
|
+
|
148
|
+
attr_reader :melee, :ranged, :spell,
|
149
|
+
:defenses, :resistances,
|
150
|
+
:talent_spec, :pvp,
|
151
|
+
:professions,
|
152
|
+
:items,
|
153
|
+
:buffs, :debuffs,
|
154
|
+
:skill_categories,
|
155
|
+
:reputation_categories
|
156
|
+
|
157
|
+
alias_method :skills, :skill_categories
|
158
|
+
alias_method :rep, :reputation_categories
|
159
|
+
alias_method :reputation, :reputation_categories
|
160
|
+
|
161
|
+
# It's made up of two parts
|
162
|
+
# Don't care about battlegroups yet
|
163
|
+
# I don't think I can call stuff from the constructor?
|
164
|
+
def initialize(sheet, skills, reputation, api = nil)
|
165
|
+
@api = api
|
166
|
+
|
167
|
+
character_info(sheet%'character')
|
168
|
+
character_tab(sheet%'characterTab')
|
169
|
+
character_skills(skills)
|
170
|
+
character_reputation(reputation)
|
171
|
+
end
|
172
|
+
|
173
|
+
# <character
|
174
|
+
# battleGroup="Conviction"
|
175
|
+
# charUrl="r=Genjuros&n=Jonlok"
|
176
|
+
# class="Warlock"
|
177
|
+
# classId="9"
|
178
|
+
# faction="Horde"
|
179
|
+
# factionId="1"
|
180
|
+
# gender="Male"
|
181
|
+
# genderId="0"
|
182
|
+
# guildName=""
|
183
|
+
# lastModified="12 February 2008"
|
184
|
+
# level="41"
|
185
|
+
# name="Jonlok"
|
186
|
+
# prefix=""
|
187
|
+
# race="Orc"
|
188
|
+
# raceId="2"
|
189
|
+
# realm="Genjuros"
|
190
|
+
# suffix=""/>
|
191
|
+
|
192
|
+
def character_info(elem)
|
193
|
+
# basic info
|
194
|
+
@name = elem[:name]
|
195
|
+
@level = elem[:level].to_i
|
196
|
+
@char_url = elem[:charUrl]
|
197
|
+
|
198
|
+
@klass = elem[:class]
|
199
|
+
@klass_id = elem[:classId].to_i
|
200
|
+
|
201
|
+
@gender = elem[:gender]
|
202
|
+
@gender_id = elem[:genderId].to_i
|
203
|
+
|
204
|
+
@race = elem[:race]
|
205
|
+
@race_id = elem[:raceId].to_i
|
206
|
+
|
207
|
+
@faction = elem[:faction]
|
208
|
+
@faction_id = elem[:factionId].to_i
|
209
|
+
|
210
|
+
@guild = elem[:guildName] == "" ? nil : elem[:guildName]
|
211
|
+
@guild_url = elem[:guildUrl] == "" ? nil : elem[:guildUrl]
|
212
|
+
|
213
|
+
@prefix = elem[:prefix] == "" ? nil : elem[:prefix]
|
214
|
+
@suffix = elem[:suffix] == "" ? nil : elem[:suffix]
|
215
|
+
|
216
|
+
@realm = elem[:realm]
|
217
|
+
|
218
|
+
@battle_group = elem[:battleGroup]
|
219
|
+
|
220
|
+
# format is February 11, 2008
|
221
|
+
# except when it's korean, and then it's 2008년 5월 11일 (일)
|
222
|
+
# tw is 2008年5月11日 (2008年5月11日)
|
223
|
+
# TODO: Datetime doesn't parse other languages nicely
|
224
|
+
# Until then, just save it as a string
|
225
|
+
begin
|
226
|
+
@last_modified = elem[:lastModified] == "" ? nil : DateTime.parse(elem[:lastModified])
|
227
|
+
rescue
|
228
|
+
@last_modified = elem[:lastModified] == "" ? nil : elem[:lastModified]
|
229
|
+
end
|
230
|
+
#@last_modified = elem[:lastModified]#.to_time
|
231
|
+
|
232
|
+
@arena_teams = []
|
233
|
+
(elem/:arenaTeam).each do |arena_team|
|
234
|
+
@arena_teams << ArenaTeam.new(arena_team)
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
def character_tab(elem)
|
240
|
+
|
241
|
+
# <title value=""/>
|
242
|
+
@title = (elem%'title')[:value] == "" ? nil : (elem%'title')[:value]
|
243
|
+
#@known_titles = <knownTitles/>
|
244
|
+
|
245
|
+
@health = (elem%'characterBars'%'health')[:effective].to_i
|
246
|
+
@second_bar = SecondBar.new(elem%'characterBars'%'secondBar')
|
247
|
+
|
248
|
+
# base stats
|
249
|
+
@strength = Strength.new(elem%'baseStats'%'strength')
|
250
|
+
@agility = Agility.new(elem%'baseStats'%'agility')
|
251
|
+
@stamina = Stamina.new(elem%'baseStats'%'stamina')
|
252
|
+
@intellect = Intellect.new(elem%'baseStats'%'intellect')
|
253
|
+
@spirit = Spirit.new(elem%'baseStats'%'spirit')
|
254
|
+
|
255
|
+
# damage stuff
|
256
|
+
@melee = Melee.new(elem%'melee')
|
257
|
+
@ranged = Ranged.new(elem%'ranged')
|
258
|
+
@spell = Spell.new(elem.at(' > spell')) # TODO: hacky?
|
259
|
+
@defenses = Defenses.new(elem%'defenses')
|
260
|
+
|
261
|
+
# TODO: Massive problem, doesn't fill in resistances for some reason
|
262
|
+
resist_types = ['arcane', 'fire', 'frost', 'holy', 'nature', 'shadow']
|
263
|
+
@resistances = {}
|
264
|
+
resist_types.each do |res|
|
265
|
+
@resistances[res] = Resistance.new(elem%'resistances'%res)
|
266
|
+
end
|
267
|
+
|
268
|
+
@talent_spec = TalentSpec.new(elem%'talentSpec')
|
269
|
+
|
270
|
+
@pvp = Pvp.new(elem%'pvp')
|
271
|
+
|
272
|
+
# Also accessible from
|
273
|
+
# character.skills['professions']
|
274
|
+
@professions = []
|
275
|
+
(elem%'professions'/:skill).each do |skill|
|
276
|
+
@professions << Skill.new(skill)
|
277
|
+
end
|
278
|
+
|
279
|
+
@items = []
|
280
|
+
(elem%'items'/:item).each do |item|
|
281
|
+
@items << EquippedItem.new(item, @api)
|
282
|
+
end
|
283
|
+
|
284
|
+
@buffs = []
|
285
|
+
(elem%'buffs'/:spell).each do |buff|
|
286
|
+
@buffs << Buff.new(buff, @api)
|
287
|
+
end
|
288
|
+
|
289
|
+
@debuffs = []
|
290
|
+
(elem%'debuffs'/:spell).each do |debuff|
|
291
|
+
@debuffs << Buff.new(debuff, @api)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# character-skills.xml
|
296
|
+
def character_skills(elem)
|
297
|
+
@skill_categories = {}
|
298
|
+
(elem/:skillCategory).each do |category|
|
299
|
+
@skill_categories[category[:key]] = SkillCategory.new(category)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
# character-reputation.xml
|
304
|
+
def character_reputation(elem)
|
305
|
+
@reputation_categories = {}
|
306
|
+
(elem/:factionCategory).each do |category|
|
307
|
+
@reputation_categories[category[:key]] = RepFactionCategory.new(category)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
|
313
|
+
# Second stat bar, depends on character class
|
314
|
+
class SecondBar
|
315
|
+
attr_reader :effective, :casting, :not_casting, :type
|
316
|
+
|
317
|
+
def initialize(elem)
|
318
|
+
@effective = elem[:effective].to_i
|
319
|
+
@casting = elem[:casting].to_i == -1 ? nil : elem[:casting].to_i
|
320
|
+
@not_casting = elem[:notCasting].to_i == -1 ? nil : elem[:notCasting].to_i
|
321
|
+
@type = elem[:type]
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
|
326
|
+
class BaseStat # abstract?
|
327
|
+
attr_reader :base, :effective
|
328
|
+
end
|
329
|
+
|
330
|
+
class Strength < BaseStat
|
331
|
+
attr_reader :attack, :block
|
332
|
+
def initialize(elem)
|
333
|
+
@base = elem['base'].to_i
|
334
|
+
@effective = elem['effective'].to_i
|
335
|
+
@attack = elem['attack'].to_i
|
336
|
+
@block = elem['block'].to_i == -1 ? nil : elem['block'].to_i
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
class Agility < BaseStat
|
341
|
+
attr_reader :armor, :attack, :crit_hit_percent
|
342
|
+
def initialize(elem)
|
343
|
+
@base = elem[:base].to_i
|
344
|
+
@effective = elem[:effective].to_i
|
345
|
+
@armor = elem[:armor].to_i
|
346
|
+
@attack = elem[:attack].to_i == -1 ? nil : elem[:attack].to_i
|
347
|
+
@crit_hit_percent = elem[:critHitPercent].to_f
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
class Stamina < BaseStat
|
352
|
+
attr_reader :health, :pet_bonus
|
353
|
+
def initialize(elem)
|
354
|
+
@base = elem[:base].to_i
|
355
|
+
@effective = elem[:effective].to_i
|
356
|
+
@health = elem[:health].to_i
|
357
|
+
@pet_bonus = elem[:petBonus].to_i == -1 ? nil : elem[:petBonus].to_i
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
class Intellect < BaseStat
|
362
|
+
attr_reader :mana, :crit_hit_percent, :pet_bonus
|
363
|
+
def initialize(elem)
|
364
|
+
@base = elem[:base].to_i
|
365
|
+
@effective = elem[:effective].to_i
|
366
|
+
@mana = elem[:mana].to_i
|
367
|
+
@crit_hit_percent = elem[:critHitPercent].to_f
|
368
|
+
@pet_bonus = elem[:petBonus].to_i == -1 ? nil : elem[:petBonus].to_i
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
class Spirit < BaseStat
|
373
|
+
attr_reader :health_regen, :mana_regen
|
374
|
+
def initialize(elem)
|
375
|
+
@base = elem[:base].to_i
|
376
|
+
@effective = elem[:effective].to_i
|
377
|
+
@health_regen = elem[:healthRegen].to_i
|
378
|
+
@mana_regen = elem[:manaRegen].to_i
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
class Armor < BaseStat
|
383
|
+
attr_reader :percent, :pet_bonus
|
384
|
+
def initialize(elem)
|
385
|
+
@base = elem[:base].to_i
|
386
|
+
@effective = elem[:effective].to_i
|
387
|
+
@percent = elem[:percent].to_f
|
388
|
+
@pet_bonus = elem[:petBonus].to_i == -1 ? nil : elem[:petBonus].to_i
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
|
393
|
+
|
394
|
+
# <melee>
|
395
|
+
# <mainHandDamage dps="65.6" max="149" min="60" percent="0" speed="1.60"/>
|
396
|
+
# <offHandDamage dps="0.0" max="0" min="0" percent="0" speed="2.00"/>
|
397
|
+
# <mainHandSpeed hastePercent="0.00" hasteRating="0" value="1.60"/>
|
398
|
+
# <offHandSpeed hastePercent="0.00" hasteRating="0" value="2.00"/>
|
399
|
+
# <power base="338" effective="338" increasedDps="24.0"/>
|
400
|
+
# <hitRating increasedHitPercent="0.00" value="0"/>
|
401
|
+
# <critChance percent="4.16" plusPercent="0.00" rating="0"/>
|
402
|
+
# <expertise additional="0" percent="0.00" rating="0" value="0"/>
|
403
|
+
# </melee>
|
404
|
+
class Melee
|
405
|
+
attr_reader :main_hand_skill, :off_hand_skill,
|
406
|
+
:main_hand_damage, :off_hand_damage,
|
407
|
+
:main_hand_speed, :off_hand_speed,
|
408
|
+
:speed, :hit_rating, :crit_chance
|
409
|
+
:expertise
|
410
|
+
|
411
|
+
def initialize(elem)
|
412
|
+
# TODO: Do these not exist anymore?
|
413
|
+
@main_hand_skill = WeaponSkill.new(elem%'mainHandWeaponSkill') if (elem%'mainHandWeaponSkill')
|
414
|
+
@off_hand_skill = WeaponSkill.new(elem%'offHandWeaponSkill') if (elem%'offHandWeaponSkill')
|
415
|
+
|
416
|
+
@main_hand_damage = WeaponDamage.new(elem%'mainHandDamage')
|
417
|
+
@off_hand_damage = WeaponDamage.new(elem%'offHandDamage')
|
418
|
+
|
419
|
+
@main_hand_speed = WeaponSpeed.new(elem%'mainHandSpeed')
|
420
|
+
@off_hand_speed = WeaponSpeed.new(elem%'offHandSpeed')
|
421
|
+
|
422
|
+
@power = WeaponPower.new(elem%'power')
|
423
|
+
@hit_rating = WeaponHitRating.new(elem%'hitRating')
|
424
|
+
@crit_chance = WeaponCritChance.new(elem%'critChance')
|
425
|
+
|
426
|
+
@expertise = WeaponExpertise.new(elem%'expertise')
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
# <ranged>
|
431
|
+
# <weaponSkill rating="0" value="-1"/>
|
432
|
+
# <damage dps="0.0" max="0" min="0" percent="0" speed="0.00"/>
|
433
|
+
# <speed hastePercent="0.00" hasteRating="0" value="0.00"/>
|
434
|
+
# <power base="57" effective="57" increasedDps="4.0" petAttack="-1.00" petSpell="-1.00"/>
|
435
|
+
# <hitRating increasedHitPercent="0.00" value="0"/>
|
436
|
+
# <critChance percent="0.92" plusPercent="0.00" rating="0"/>
|
437
|
+
# </ranged>
|
438
|
+
class Ranged
|
439
|
+
attr_reader :weapon_skill, :damage, :speed, :power,
|
440
|
+
:hit_rating, :crit_chance
|
441
|
+
|
442
|
+
def initialize(elem)
|
443
|
+
@weapon_skill = WeaponSkill.new(elem%'weaponSkill')
|
444
|
+
@damage = WeaponDamage.new(elem%'damage')
|
445
|
+
@speed = WeaponSpeed.new(elem%'speed')
|
446
|
+
@power = WeaponPower.new(elem%'power')
|
447
|
+
@hit_rating = WeaponHitRating.new(elem%'hitRating')
|
448
|
+
@crit_chance = WeaponCritChance.new(elem%'critChance')
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
class WeaponSkill
|
453
|
+
attr_reader :rating, :value
|
454
|
+
|
455
|
+
def initialize(elem)
|
456
|
+
@value = elem[:value].to_i == -1 ? nil : elem[:value].to_i
|
457
|
+
@rating = elem[:rating].to_i
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
class WeaponDamage
|
462
|
+
attr_reader :dps, :max, :min, :percent, :speed
|
463
|
+
|
464
|
+
def initialize(elem)
|
465
|
+
@dps = elem[:dps].to_f
|
466
|
+
@max = elem[:max].to_i
|
467
|
+
@min = elem[:min].to_i
|
468
|
+
@percent = elem[:percent].to_f
|
469
|
+
@speed = elem[:speed].to_f
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
class WeaponSpeed
|
474
|
+
attr_reader :haste_percent, :haste_rating, :value
|
475
|
+
|
476
|
+
def initialize(elem)
|
477
|
+
@haste_percent = elem[:hastePercent].to_f
|
478
|
+
@haste_rating = elem[:hasteRating].to_f
|
479
|
+
@value = elem[:value].to_f
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
class WeaponPower
|
484
|
+
attr_reader :base, :effective, :increased_dps, :pet_attack, :pet_spell
|
485
|
+
|
486
|
+
def initialize(elem)
|
487
|
+
@base = elem[:base].to_i
|
488
|
+
@haste_rating = elem[:effective].to_i
|
489
|
+
@increased_dps = elem[:increasedDps].to_f
|
490
|
+
@pet_attack = (elem[:petAttack].to_f == -1 ? nil : elem[:petAttack].to_f)
|
491
|
+
@pet_spell = (elem[:petSpell].to_f == -1 ? nil : elem[:petSpell].to_f)
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
class WeaponHitRating
|
496
|
+
attr_reader :increased_hit_percent, :value
|
497
|
+
|
498
|
+
def initialize(elem)
|
499
|
+
@increased_hit_percent = elem[:increasedHitPercent].to_f
|
500
|
+
@value = elem[:value].to_f
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
class WeaponCritChance
|
505
|
+
attr_reader :percent, :plus_percent, :rating
|
506
|
+
|
507
|
+
def initialize(elem)
|
508
|
+
@percent = elem[:percent].to_f
|
509
|
+
@plus_percent = elem[:plusPercent].to_f
|
510
|
+
@rating = elem[:rating].to_i
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
# <expertise additional="0" percent="0.00" rating="0" value="0"/>
|
515
|
+
class WeaponExpertise
|
516
|
+
attr_reader :additional, :percent, :rating, :value
|
517
|
+
|
518
|
+
def initialize(elem)
|
519
|
+
@additional = elem[:additional].to_i
|
520
|
+
@percent = elem[:percent].to_f
|
521
|
+
@rating = elem[:rating].to_i
|
522
|
+
@value = elem[:value].to_i
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
|
527
|
+
# Decided to do funky stuff to the XML to make it more useful.
|
528
|
+
# instead of having two seperate lists of bonusDamage and critChance
|
529
|
+
# merged it into one set of objects for each thing
|
530
|
+
class Spell
|
531
|
+
attr_reader :arcane, :fire, :frost, :holy, :nature, :shadow,
|
532
|
+
:hit_rating, :bonus_healing, :penetration, :mana_regen
|
533
|
+
|
534
|
+
def initialize(elem)
|
535
|
+
@arcane = SpellDamage.new(elem%'bonusDamage'%'arcane', elem%'critChance'%'arcane')
|
536
|
+
@fire = SpellDamage.new(elem%'bonusDamage'%'fire', elem%'critChance'%'fire')
|
537
|
+
@frost = SpellDamage.new(elem%'bonusDamage'%'frost', elem%'critChance'%'frost')
|
538
|
+
@holy = SpellDamage.new(elem%'bonusDamage'%'holy', elem%'critChance'%'holy')
|
539
|
+
@nature = SpellDamage.new(elem%'bonusDamage'%'nature', elem%'critChance'%'nature')
|
540
|
+
@shadow = SpellDamage.new(elem%'bonusDamage'%'shadow', elem%'critChance'%'shadow')
|
541
|
+
|
542
|
+
@bonus_healing = (elem%'bonusHealing')[:value].to_i # is this right??
|
543
|
+
@penetration = (elem%'penetration')[:value].to_i
|
544
|
+
@hit_rating = WeaponHitRating.new(elem%'hitRating')
|
545
|
+
@mana_regen = ManaRegen.new(elem%'manaRegen')
|
546
|
+
|
547
|
+
# elements = %w[arcane fire frost holy nature shadow]
|
548
|
+
# elements.each do |element|
|
549
|
+
# # TODO: is this a good idea?
|
550
|
+
# #instance_variable_set("@#{element}", foo) #??
|
551
|
+
# #eval("@#{element} = SpellDamage.new(elem[:bonusDamage][element][:value], elem[:critChance][element][:percent]).to_f)")
|
552
|
+
# # eval("@#{element} = SpellDamage.new((elem%'bonusDamage'%element)[:value].to_i,
|
553
|
+
# # (elem%'critChance'%element)[:percent].to_f)")
|
554
|
+
# end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
class SpellDamage
|
559
|
+
attr_reader :value, :crit_chance_percent
|
560
|
+
alias_method :percent, :crit_chance_percent
|
561
|
+
|
562
|
+
def initialize(bonusDamage_elem, critChance_elem)
|
563
|
+
@value = bonusDamage_elem[:value].to_i
|
564
|
+
@crit_chance_percent = critChance_elem[:percent].to_f
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
class ManaRegen
|
569
|
+
attr_reader :casting, :not_casting
|
570
|
+
|
571
|
+
def initialize(elem)
|
572
|
+
@casting = elem[:casting].to_f
|
573
|
+
@not_casting = elem[:notCasting].to_f
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
class PetBonus
|
578
|
+
attr_reader :attack, :damage, :from_Type
|
579
|
+
|
580
|
+
def initialize(elem)
|
581
|
+
@attack = elem[:attack].to_i == -1 ? nil : elem[:attack].to_i
|
582
|
+
@damage = elem[:damage].to_i == -1 ? nil : elem[:damage].to_i
|
583
|
+
@from_type = elem[:fromType] if elem[:fromType]
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
|
588
|
+
|
589
|
+
class Defenses
|
590
|
+
attr_reader :armor, :defense, :dodge, :parry, :block, :resilience
|
591
|
+
|
592
|
+
def initialize(elem)
|
593
|
+
@armor = Armor.new(elem%'armor')
|
594
|
+
@defense = Defense.new(elem%'defense')
|
595
|
+
@dodge = DodgeParryBlock.new(elem%'dodge')
|
596
|
+
@parry = DodgeParryBlock.new(elem%'parry')
|
597
|
+
@block = DodgeParryBlock.new(elem%'block')
|
598
|
+
@resilience = Resilience.new(elem%'resilience')
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
class Armor
|
603
|
+
attr_reader :base, :effective, :percent, :pet_bonus
|
604
|
+
|
605
|
+
def initialize(elem)
|
606
|
+
@base = elem[:base].to_i
|
607
|
+
@effective = elem[:effective].to_i
|
608
|
+
@percent = elem[:percent].to_f
|
609
|
+
@pet_bonus = elem[:petBonus].to_i == -1 ? nil : elem[:petBonus].to_i
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
class Defense
|
614
|
+
attr_reader :value, :increase_percent, :decrease_percent, :plus_defense, :rating
|
615
|
+
|
616
|
+
def initialize(elem)
|
617
|
+
@value = elem[:value].to_i
|
618
|
+
@increase_percent = elem[:increasePercent].to_f
|
619
|
+
@decrease_percent = elem[:decreasePercent].to_f
|
620
|
+
@plus_defense = elem[:plusDefense].to_i
|
621
|
+
@rating = elem[:rating].to_i
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
class DodgeParryBlock
|
626
|
+
attr_reader :percent, :increase_percent, :rating
|
627
|
+
|
628
|
+
def initialize(elem)
|
629
|
+
@percent = elem[:percent].to_f
|
630
|
+
@increase_percent = elem[:increasePercent].to_f
|
631
|
+
@rating = elem[:rating].to_i
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
class Resilience
|
636
|
+
attr_reader :damage_percent, :hit_percent, :value
|
637
|
+
|
638
|
+
def initialize(elem)
|
639
|
+
@damage_percent = elem[:damagePercent].to_f
|
640
|
+
@hit_percent = elem[:hitPercent].to_f
|
641
|
+
@value = elem[:value].to_f
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
|
646
|
+
class Resistance
|
647
|
+
attr_reader :value, :pet_bonus
|
648
|
+
|
649
|
+
def initialize(elem)
|
650
|
+
@value = elem[:value].to_i
|
651
|
+
@pet_bonus = elem[:petBonus].to_i == -1 ? nil : elem[:petBonus].to_i
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
|
656
|
+
# Note the list of talent trees starts at 1. This is quirky, but that's what's used in the XML
|
657
|
+
class TalentSpec
|
658
|
+
attr_reader :trees
|
659
|
+
|
660
|
+
def initialize(elem)
|
661
|
+
@trees = []
|
662
|
+
@trees[1] = elem[:treeOne].to_i
|
663
|
+
@trees[2] = elem[:treeTwo].to_i
|
664
|
+
@trees[3] = elem[:treeThree].to_i
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
|
669
|
+
# Player-versus-player data
|
670
|
+
class Pvp
|
671
|
+
attr_reader :lifetime_honorable_kills, :arena_currency
|
672
|
+
|
673
|
+
def initialize(elem)
|
674
|
+
@lifetime_honorable_kills = (elem%'lifetimehonorablekills')[:value].to_i
|
675
|
+
@arena_currency = (elem%'arenacurrency')[:value].to_i
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
|
680
|
+
# A buff
|
681
|
+
# TODO: Code duplication, see basic Item class. Make extend Icon class?
|
682
|
+
class Buff
|
683
|
+
attr_reader :name, :effect, :icon_base
|
684
|
+
alias_method :to_s, :name
|
685
|
+
|
686
|
+
@@icon_url_base = 'images/icons/'
|
687
|
+
@@icon_sizes = {:large => ['64x64', 'jpg'], :medium => ['43x43', 'png'], :small => ['21x21', 'png']}
|
688
|
+
|
689
|
+
def initialize(elem, api = nil)
|
690
|
+
@api = api
|
691
|
+
|
692
|
+
@name = elem[:name]
|
693
|
+
@effect = elem[:effect]
|
694
|
+
@icon_base = elem[:icon]
|
695
|
+
end
|
696
|
+
|
697
|
+
# http://armory.worldofwarcraft.com/images/icons/21x21/spell_holy_arcaneintellect.png
|
698
|
+
def icon(size = :medium)
|
699
|
+
if !@@icon_sizes.include?(size)
|
700
|
+
raise Wowr::Exceptions::InvalidIconSize.new(@@icon_sizes)
|
701
|
+
end
|
702
|
+
|
703
|
+
if @api
|
704
|
+
base = @api.base_url
|
705
|
+
else
|
706
|
+
base = 'http://www.wowarmory.com/'
|
707
|
+
end
|
708
|
+
|
709
|
+
# http://www.wowarmory.com/images/icons/64x64/blahblah.jpg
|
710
|
+
return base + @@icon_url_base + @@icon_sizes[size][0] + '/' + @icon_base + '.' + @@icon_sizes[size][1]
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
|
715
|
+
# An item equipped to a player
|
716
|
+
class EquippedItem < Item
|
717
|
+
attr_reader :durability, :max_durability, #:id, :item_id, :icon,
|
718
|
+
:gems, :permanent_enchant,
|
719
|
+
:random_properties_id, :seed, :slot
|
720
|
+
|
721
|
+
def initialize(elem, api = nil)
|
722
|
+
super(elem, api)
|
723
|
+
@durability = elem[:durability].to_i
|
724
|
+
@max_durability = elem[:maxDurability].to_i
|
725
|
+
@gems = []
|
726
|
+
@gems[0] = elem[:gem0Id].to_i == 0 ? nil : elem[:gem0Id].to_i
|
727
|
+
@gems[1] = elem[:gem1Id].to_i == 0 ? nil : elem[:gem1Id].to_i
|
728
|
+
@gems[2] = elem[:gem2Id].to_i == 0 ? nil : elem[:gem2Id].to_i
|
729
|
+
@permanent_enchant = elem[:permanentEnchant].to_i
|
730
|
+
@random_properties_id = elem[:randomPropertiesId] == 0 ? nil : elem[:randomPropertiesId].to_i
|
731
|
+
@seed = elem[:seed].to_i # not sure if seed is so big it's overloading
|
732
|
+
@slot = elem[:slot].to_i
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
|
737
|
+
|
738
|
+
|
739
|
+
# <skillCategory key="weaponskills" name="Weapon Skills">
|
740
|
+
# <skill key="defense" max="350" name="Defense" value="348"/>
|
741
|
+
# <skill key="maces" max="350" name="Maces" value="291"/>
|
742
|
+
# <skill key="staves" max="350" name="Staves" value="234"/>
|
743
|
+
# <skill key="two-handedmaces" max="350" name="Two-Handed Maces" value="189"/>
|
744
|
+
# <skill key="unarmed" max="350" name="Unarmed" value="13"/>
|
745
|
+
# </skillCategory>
|
746
|
+
|
747
|
+
# General skill category
|
748
|
+
# eg Weapon Skills, Languages
|
749
|
+
class SkillCategory
|
750
|
+
attr_reader :key, :name, :skills
|
751
|
+
alias_method :to_s, :name
|
752
|
+
|
753
|
+
def initialize(elem)
|
754
|
+
@key = elem[:key]
|
755
|
+
@name = elem[:name]
|
756
|
+
|
757
|
+
@skills = {}
|
758
|
+
(elem/:skill).each do |skill|
|
759
|
+
@skills[skill[:key]] = Skill.new(skill)
|
760
|
+
end
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
# eg Daggers, Riding, Fishing, language
|
765
|
+
class Skill
|
766
|
+
attr_reader :key, :name, :value, :max
|
767
|
+
alias_method :to_s, :name
|
768
|
+
alias_method :to_i, :value
|
769
|
+
|
770
|
+
def initialize(elem)
|
771
|
+
@key = elem[:key]
|
772
|
+
@name = elem[:name]
|
773
|
+
@value = elem[:value].to_i
|
774
|
+
@max = elem[:max].to_i
|
775
|
+
end
|
776
|
+
end
|
777
|
+
|
778
|
+
|
779
|
+
# Larger group of factions
|
780
|
+
# Used for faction information
|
781
|
+
# eg Alliance, Shattrath City, Steamwheedle Cartel
|
782
|
+
class RepFactionCategory
|
783
|
+
attr_reader :key, :name, :factions
|
784
|
+
alias_method :to_s, :name
|
785
|
+
|
786
|
+
def initialize(elem)
|
787
|
+
@key = elem[:key]
|
788
|
+
@name = elem[:name]
|
789
|
+
|
790
|
+
@factions = {}
|
791
|
+
(elem/:faction).each do |faction|
|
792
|
+
@factions[faction[:key]] = RepFaction.new(faction)
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
def total
|
797
|
+
total = 0
|
798
|
+
factions.each_value { |faction| total += faction.reputation }
|
799
|
+
return total
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
803
|
+
|
804
|
+
# Smaller NPC faction that is part of a FactionCategory
|
805
|
+
# eg Darnassus, Argent Dawn
|
806
|
+
class RepFaction
|
807
|
+
attr_reader :key, :name, :reputation
|
808
|
+
alias_method :to_s, :name
|
809
|
+
alias_method :to_i, :reputation
|
810
|
+
|
811
|
+
alias_method :rep, :reputation
|
812
|
+
|
813
|
+
def initialize(elem)
|
814
|
+
@key = elem[:key]
|
815
|
+
@name = elem[:name]
|
816
|
+
@reputation = elem[:reputation].to_i
|
817
|
+
end
|
818
|
+
end
|
819
|
+
|
820
|
+
end
|
821
|
+
end
|