renchap-wowr 0.5.0

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