-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathShared.lua
280 lines (243 loc) · 9.93 KB
/
Shared.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
local Env = select(2, ...)
Env.VERSION = GetAddOnMetadata(select(1, ...), "Version")
Env.IS_CLASSIC_ERA = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC
Env.IS_CLASSIC_ERA_SOD = Env.IS_CLASSIC_ERA and C_Engraving.IsEngravingEnabled()
Env.IS_CLASSIC_WRATH = WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC
Env.IS_CLASSIC_CATA = WOW_PROJECT_ID == WOW_PROJECT_CATACLYSM_CLASSIC
Env.IS_CLIENT_SUPPORTED = Env.IS_CLASSIC_ERA_SOD or Env.IS_CLASSIC_WRATH or Env.IS_CLASSIC_CATA
Env.supportedClientNames = {
"Classic: Cataclysm",
"Classic: WotLK",
"Classic: SoD (Export may work for Era, but sim is made for SoD only!)",
}
-- This is needed because classic has no way to get Ids for professions.
-- GetSkillLineInfo() only returns localized values. GetSpellInfo() also does.
-- These spells are NOT the skill line, but have the same name in english,
-- So they should probably end up with the same translation.
-- engName is what the sim uses.
Env.professionNames = {
[GetSpellInfo(2018)] = { skillLine = 164, engName = "Blacksmithing" },
[GetSpellInfo(3104)] = { skillLine = 165, engName = "Leatherworking" },
[GetSpellInfo(2259)] = { skillLine = 171, engName = "Alchemy" },
[GetSpellInfo(9134)] = { skillLine = 182, engName = "Herbalism" },
[GetSpellInfo(2575)] = { skillLine = 186, engName = "Mining" },
[GetSpellInfo(3908)] = { skillLine = 197, engName = "Tailoring" },
[GetSpellInfo(12656)] = { skillLine = 202, engName = "Engineering" },
[GetSpellInfo(7412)] = { skillLine = 333, engName = "Enchanting" },
[GetSpellInfo(8617)] = { skillLine = 393, engName = "Skinning" },
}
local statToStatId = {
str = 1,
strength = 1,
agi = 2,
agility = 2,
stam = 3,
stm = 3,
stamina = 3,
int = 4,
intellect = 4,
spi = 5,
spirit = 5,
}
---Determine if an item should be exported on bag item export.
-- TODO(Riotdog-GehennasEU): Is this sufficient? This seems to be what simc uses:
-- https://github.com/simulationcraft/simc-addon/blob/master/core.lua
-- Except we don't need the artifact check for wotlk classic.
---@param itemLink string See https://wowpedia.fandom.com/wiki/ItemLink
---@return boolean exportItem true if item should be exported
function Env.TreatItemAsPossibleUpgrade(itemLink)
if not IsEquippableItem(itemLink) then return false end
local itemInfo = { GetItemInfo(itemLink) }
local itemRarity = itemInfo[3]
local itemLevel = itemInfo[4]
local itemClassId = itemInfo[12]
if Env.IS_CLASSIC_ERA then
local minIlvl = UnitLevel("player") - 15
if itemLevel <= minIlvl
or itemRarity < Enum.ItemQuality.Good then
return false
end
elseif Env.IS_CLASSIC_WRATH or Env.IS_CLASSIC_CATA then
-- Ignore TBC items like Rocket Boots Xtreme (Lite). The ilvl limit is intentionally set low
-- to limit accidental filtering.
if itemLevel <= 112
or itemRarity < Enum.ItemQuality.Rare then
return false
end
end
-- Ignore ammunition.
if itemClassId == Enum.ItemClass.Projectile then
return false
end
return true
end
---Check if stat1 is bigger than stat2.
---Accepts short (agi) or full stat names (agility)
---@param stat1 string
---@param stat2 string
---@return boolean
function Env.StatBiggerThanStat(stat1, stat2)
local statId1 = statToStatId[stat1:lower()]
local statId2 = statToStatId[stat2:lower()]
assert(statId1 and statId2, "Invalid stat identifiers provided!")
return select(2, UnitStat("player", statId1)) > select(2, UnitStat("player", statId2))
end
-- Some runes learn multiple spells, i.e. the learnedAbilitySpellIDs array of the
-- rune data returned by C_Engraving.GetRuneForEquipmentSlot and C_Engraving.GetRuneForInventorySlot
-- has multiple entries. The sim uses one of those Ids to indentify runes.
-- Map the first spell Id to the expected spell Id for runes that do not have it at position 1.
local runeSpellRemap = {
[407993] = 407995, -- Mangle: The bear version is expected.
}
-- Ring Runes don't provide a Spell ID like other runes do. We have to convert the Enchant ID back to the Spell ID manually.
-- Ordered by spell name
local enchantmentIDToSpellID = {
[7514] = 442893, -- Arcane Specialization
[7508] = 442876, -- Axe Specialization
[7510] = 442887, -- Dagger Specialization
[7555] = 459312, -- Defense Specialization
[7520] = 453622, -- Feral Combat Specialization
[7515] = 442894, -- Fire Specialization
[7511] = 442890, -- Fist Weapon Specialization
[7516] = 442895, -- Frost Specialization
[7519] = 442898, -- Holy Specialization
[7509] = 442881, -- Mace Specialization
[7517] = 442896, -- Nature Specialization
[7513] = 442892, -- Pole Weapon Specialization
[7512] = 442891, -- Ranged Weapon Specialization
[7518] = 442897, -- Shadow Specialization
[7507] = 442813, -- Sword Specialization
}
---Get rune spell from an item in a slot, if item has a rune engraved.
---@param slotId integer
---@param bagId integer|nil If not nil check bag items instead of equipped items.
---@return integer|nil abilitySpellId The first spell id granted by the rune, or nil if no rune engraved.
function Env.GetEngravedRuneSpell(slotId, bagId)
-- After first login the whole engraving stuff may not be loaded yet!
-- GetNumRunesKnown will return 0 for maximum runes available in that case.
if select(2, C_Engraving.GetNumRunesKnown()) == 0 then
LoadAddOn("Blizzard_EngravingUI")
C_Engraving.RefreshRunesList()
end
-- The shoulder "runes" are special and don't use the C_Engraving API
-- Instead they override a special spell "Soul Engraving" (1219955)
if bagId == nil then
if slotId == INVSLOT_SHOULDER then
return FindSpellOverrideByID(1219955)
end
else
local itemLocation = ItemLocation:CreateFromBagAndSlot(bagId, slotId)
local inventoryType = C_Item.GetItemInventoryType(itemLocation)
if inventoryType == Enum.InventoryType.IndexShoulderType then
return Env.GetSoulEngravingSpellID(slotId, bagId)
end
end
local runeData
if bagId == nil then
runeData = C_Engraving.GetRuneForEquipmentSlot(slotId)
else
runeData = C_Engraving.GetRuneForInventorySlot(bagId, slotId)
end
if runeData then
local firstSpellId = runeData.learnedAbilitySpellIDs[1]
if firstSpellId == nil then
-- Fall back to re-mapping the enchant ID.
-- Should only apply to ring specializations for now.
return enchantmentIDToSpellID[runeData.itemEnchantmentID]
else
-- All non-ring runes should have a Spell ID
if runeSpellRemap[firstSpellId] then
return runeSpellRemap[firstSpellId]
end
return firstSpellId
end
end
end
---Counts spent talent points per tree.
---@param isInspect boolean If true use inspect target.
---@return table pointsPerTreeTable { tree1Count, tree2Count, tree3Count }
local function CountSpentTalentsPerTree(isInspect)
local trees = {}
for tab = 1, GetNumTalentTabs(isInspect) do
trees[tab] = 0
for i = 1, GetNumTalents(tab, isInspect) do
local _, _, _, _, currentRank = GetTalentInfo(tab, i, isInspect)
trees[tab] = trees[tab] + currentRank
end
end
return trees
end
local specializations = {}
---Try to find spec. Returns empty strings if spec could not be found.
---@param unit "player"|"target"
---@return string specName The name of the spec, e.g. "feral".
---@return string specUrl The URL part of the spec, e.g. "feral_druid"
function Env.GetSpec(unit)
local playerClass = select(2, UnitClass(unit))
if specializations[playerClass] then
local spentTalentPoints = CountSpentTalentsPerTree(unit == "target")
for _, specData in pairs(specializations[playerClass]) do
if specData.isCurrentSpec(spentTalentPoints) then
return specData.spec, specData.url
end
end
end
return "", ""
end
---Add spec to detection list.
---@param playerClass string
---@param spec string The name of the spec, e.g. "feral".
---@param url string The URL part of the spec, e.g. "feral_druid"
---@param checkFunc fun(spentTanlents:number[]):boolean
function Env.AddSpec(playerClass, spec, url, checkFunc)
playerClass = playerClass:upper()
specializations[playerClass] = specializations[playerClass] or {}
table.insert(specializations[playerClass], {
spec = spec,
url = url,
isCurrentSpec = checkFunc,
})
end
CreateFrame("GameTooltip", "WSEScanningTooltip", nil, "GameTooltipTemplate")
WSEScanningTooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
local baseItemLink = "item:9333:"
C_Item.RequestLoadItemDataByID(baseItemLink)
---@return table<integer, string>
local function GetBaseItemText()
WSEScanningTooltip:ClearLines()
WSEScanningTooltip:SetHyperlink(baseItemLink)
local regions = { WSEScanningTooltip:GetRegions() }
local itemText = {}
for i = 1, #regions do
local region = regions[i]
if region and region:GetObjectType() == "FontString" then
local text = region:GetText()
if text then
itemText[i] = text
end
end
end
return itemText
end
local baseItemText
---Get the localized text of a given enchantID as it will appear in an tooltip
---@param enchantID integer
---@return string
function Env.GetEnchantText(enchantID)
if not baseItemText then
baseItemText = GetBaseItemText()
end
WSEScanningTooltip:ClearLines()
WSEScanningTooltip:SetHyperlink(baseItemLink .. enchantID)
local regions = { WSEScanningTooltip:GetRegions() }
for i = 1, #regions do
local region = regions[i]
if region and region:GetObjectType() == "FontString" then
local text = region:GetText()
if text and baseItemText[i] ~= text then
return text
end
end
end
return ""
end