wowr 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|