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.
@@ -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&amp;r=Burning+Blade&amp;ts=2&amp;t=Monkey&amp;ff=realm&amp;fv=Burning+Blade&amp;select=Monkey" relevance="0" seasonGamesPlayed="66" seasonGamesWon="34" size="2" url="r=Burning+Blade&amp;ts=2&amp;t=Monkey&amp;select=Monkey" urlEscape="r=Burning+Blade&amp;ts=2&amp;t=Monkey&amp;select=Monkey">
46
+ # <emblem background="ff70de56" borderColor="ffcc73eb" borderStyle="6" iconColor="ffe3b320" iconStyle="44"/>
47
+ # <members>
48
+ # <character battleGroup="Vindication" charUrl="r=Burning+Blade&amp;n=Fandiar" class="Priest" classId="5" contribution="1380" gamesPlayed="0" gamesWon="0" gender="Male" genderId="0" guild="Legends" guildId="916" guildUrl="r=Burning+Blade&amp;n=Legends&amp;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&amp;n=Stayfrosty" class="Mage" classId="8" contribution="1460" gamesPlayed="6" gamesWon="1" gender="Male" genderId="0" guild="Legends" guildId="916" guildUrl="r=Burning+Blade&amp;n=Legends&amp;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&amp;n=Step" class="Rogue" classId="4" contribution="1688" gamesPlayed="2" gamesWon="1" gender="Female" genderId="1" guild="Legends" guildId="916" guildUrl="r=Burning+Blade&amp;n=Legends&amp;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&amp;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&amp;n=Passion&amp;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&amp;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&#24180;5&#26376;11&#26085; (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