pwood-wowr 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +41 -0
- data/VERSION.yml +4 -0
- data/lib/wowr.rb +1253 -0
- data/lib/wowr/achievements.rb +143 -0
- data/lib/wowr/arena_team.rb +80 -0
- data/lib/wowr/calendar.rb +78 -0
- data/lib/wowr/character.rb +832 -0
- data/lib/wowr/dungeon.rb +85 -0
- data/lib/wowr/exceptions.rb +163 -0
- data/lib/wowr/extensions.rb +67 -0
- data/lib/wowr/general.rb +39 -0
- data/lib/wowr/guild.rb +85 -0
- data/lib/wowr/guild_bank.rb +188 -0
- data/lib/wowr/item.rb +577 -0
- data/test/wowr_arena_team_test.rb +41 -0
- data/test/wowr_character_test.rb +88 -0
- data/test/wowr_dungeon_test.rb +63 -0
- data/test/wowr_guild_test.rb +27 -0
- data/test/wowr_item_test.rb +8 -0
- data/test/wowr_test.rb +456 -0
- data/test/xml/arena_team_search.xml +60 -0
- data/test/xml/arena_team_single.xml +25 -0
- data/test/xml/armory-search.xml +207 -0
- data/test/xml/armory_search.xml +126 -0
- data/test/xml/benedictt.xml +152 -0
- data/test/xml/character-reputation.xml +82 -0
- data/test/xml/character-sheet.xml +145 -0
- data/test/xml/character-skills.xml +60 -0
- data/test/xml/character-talents.xml +29 -0
- data/test/xml/character_info.xml +141 -0
- data/test/xml/character_search.xml +102 -0
- data/test/xml/dungeonStrings.xml +550 -0
- data/test/xml/dungeons.xml +1658 -0
- data/test/xml/example.xml +127 -0
- data/test/xml/guild-info.xml +302 -0
- data/test/xml/item-info.xml +20 -0
- data/test/xml/item-tooltip.xml +167 -0
- data/test/xml/itemSearch.xml +46 -0
- data/test/xml/item_search.xml +63 -0
- metadata +96 -0
@@ -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&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,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&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&n=Passion&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&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年5月11日 (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
|