pwood-wowr 0.5.1

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