Repository navigation
Expand file tree
/
Copy pathmods.lua
More file actions
333 lines (323 loc) · 12.7 KB
/
Copy pathmods.lua
File metadata and controls
333 lines (323 loc) · 12.7 KB
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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
if not loadStatFile then
dofile("statdesc.lua")
end
loadStatFile("tincture_stat_descriptions.txt", "graft_stat_descriptions.txt")
-- https://www.poewiki.net/wiki/Modifier#Domain
local Domains = {
Item = 1,
Flask = 2,
Jewel = 10,
AbyssJewel = 13,
DelveFossil = 16,
Synthesis = 20,
ClusterJewel = 21,
Veiled = 26,
Unveiled = 28,
Tincture = 34,
Charm = 35,
Idol = 37,
Graft = 38,
}
-- https://www.poewiki.net/wiki/Modifier#Generation_type
local GenTypes = {
Prefix = 1,
Suffix = 2,
-- includes both implicit mods and unique explicit mods
Intrinsic = 3,
Corrupted = 5,
Enchantment = 10,
Essence = 11,
ScourgeBenefit = 24,
ScourgeDownside = 25,
SearingExarch = 28,
EaterOfWorlds = 29,
}
function table.containsId(table, element)
for _, value in pairs(table) do
if value.Id == element then
return true
end
end
return false
end
local function writeMods(outName, condFunc)
local out = io.open(outName, "w")
out:write('-- This file is automatically generated, do not edit!\n')
out:write('-- Item data (c) Grinding Gear Games\n\nreturn {\n')
for mod in dat("Mods"):Rows() do
if condFunc(mod) then
if mod.Domain == Domains.DelveFossil and string.match(outName, "Item") then
if mod.SpawnTags[1].Id == "abyss_jewel" and mod.SpawnTags[2].Id == "jewel" and #mod.SpawnTags == 3 then
print("[Item]: Skipping '" .. mod.Id .. "'")
goto continue
end
elseif mod.Domain == Domains.DelveFossil and string.match(outName, "JewelAbyss") then
if not table.containsId(mod.SpawnTags, "abyss_jewel") then
print("[Abyss Jewel]: Skipping '" .. mod.Id .. "'")
goto continue
end
elseif mod.Domain == Domains.DelveFossil and string.match(outName, "Jewel") then
if not table.containsId(mod.SpawnTags, "jewel") then
print("[Jewel]: Skipping '" .. mod.Id .. "'")
goto continue
end
end
-- game data has 0 and 0, which means no description is generated
if mod.Id == "JewelExpansionPassiveNodes" then
mod.Stat2Value[1] = 2
mod.Stat2Value[2] = 12
end
local stats, orders = describeMod(mod)
if #orders > 0 and not stats[1]:match("^DNT") then
out:write('\t["', mod.Id, '"] = { ')
if mod.GenerationType == GenTypes.Prefix then
out:write('type = "Prefix", ')
elseif mod.GenerationType == GenTypes.Suffix then
out:write('type = "Suffix", ')
elseif mod.GenerationType == GenTypes.Intrinsic then
if mod.Domain == Domains.Item then
if mod.Id:match("^Synthesis") then
out:write('type = "Synthesis", ')
elseif mod.Family[2] and mod.Family[2].Id:match("MatchedInfluencesTier") then
out:write('type = "' ..
mod.Family[2].Id:match("%d+") .. mod.Family[1].Id:match("(.-)Influence") .. '", ')
end
elseif mod.Domain == Domains.DelveFossil then
out:write('type = "DelveImplicit", ')
end
elseif mod.GenerationType == GenTypes.Corrupted then
out:write('type = "Corrupted", ')
elseif mod.GenerationType == GenTypes.ScourgeBenefit then
out:write('type = "ScourgeUpside", ')
elseif mod.GenerationType == GenTypes.ScourgeDownside then
out:write('type = "ScourgeDownside", ')
elseif mod.GenerationType == GenTypes.SearingExarch then
out:write('type = "Exarch", ')
elseif mod.GenerationType == GenTypes.EaterOfWorlds then
out:write('type = "Eater", ')
end
out:write('affix = "', mod.Name, '", ')
if string.find(mod.Id, "EldritchImplicitUniquePresence") and #stats > 0 and #orders > 0 then
for i, stat in ipairs(stats) do
stats[i] = "While a Unique Enemy is in your Presence, " .. stat
end
end
if string.find(mod.Id, "EldritchImplicitPinnaclePresence") and #stats > 0 and #orders > 0 then
for i, stat in ipairs(stats) do
stats[i] = "While a Pinnacle Atlas Boss is in your Presence, " .. stat
end
end
out:write('"', table.concat(stats, '", "'), '", ')
out:write('statOrder = { ', table.concat(orders, ', '), ' }, ')
out:write('level = ', mod.Level, ', group = "', mod.Type.Id, '", ')
out:write('weightKey = { ')
for _, tag in ipairs(mod.SpawnTags) do
out:write('"', tag.Id, '", ')
end
out:write('}, ')
out:write('weightVal = { ', table.concat(mod.SpawnWeights, ', '), ' }, ')
if mod.GenerationWeightTags[1] then
-- make large clusters only have 1 notable suffix
if mod.GenerationType == GenTypes.Suffix and mod.Tags[1] and outName == "../Data/ModJewelCluster.lua" and mod.Tags[1].Id == "has_affliction_notable" then
out:write('weightMultiplierKey = { "has_affliction_notable2", ')
for _, tag in ipairs(mod.GenerationWeightTags) do
out:write('"', tag.Id, '", ')
end
out:write('}, ')
out:write('weightMultiplierVal = { 0, ', table.concat(mod.GenerationWeightValues, ', '), ' }, ')
if mod.Tags[1] then
out:write('tags = { "has_affliction_notable2", ')
for _, tag in ipairs(mod.Tags) do
out:write('"', tag.Id, '", ')
end
out:write('}, ')
end
else
out:write('weightMultiplierKey = { ')
for _, tag in ipairs(mod.GenerationWeightTags) do
out:write('"', tag.Id, '", ')
end
out:write('}, ')
out:write('weightMultiplierVal = { ', table.concat(mod.GenerationWeightValues, ', '), ' }, ')
if mod.Tags[1] then
out:write('tags = { ')
for _, tag in ipairs(mod.Tags) do
out:write('"', tag.Id, '", ')
end
out:write('}, ')
end
end
end
out:write('modTags = { ', stats.modTags, ' }, ')
-- Timeless jewels have special trade ids, such as
-- "explicit.pseudo_timeless_jewel_doryani". See the below API
-- for more info:
-- https://www.pathofexile.com/api/trade/data/stats
local modIdx = 1
local tradeHashes = {}
while mod["Stat" .. modIdx] do
local currentStats = {}
local stat = mod["Stat" .. modIdx]
currentStats[stat.Id] = {
min = mod["Stat" .. modIdx .. "Value"][1], max = mod["Stat" .. modIdx .. "Value"][2]
}
if modIdx == 6 then
break
end
local bytes = intToBytes(stat.Hash)
-- # to # stats consist of two different stats as the min and max have different ranges
if stat.Id:match("minimum") then
local nextStat = mod["Stat" .. (modIdx + 1)]
if nextStat and nextStat.Id:match("maximum") then
modIdx = modIdx + 1
bytes = bytes .. intToBytes(nextStat.Hash)
currentStats[nextStat.Id] = {
min = mod["Stat" .. modIdx .. "Value"][1], max = mod["Stat" .. modIdx .. "Value"][2]
}
end
end
local description, _, _ = describeStats(currentStats)
tradeHashes[murmurHash2(bytes, 0x02312233)] = description
modIdx = modIdx + 1
end
out:write("tradeHashes = { ")
for hash, desc in pairs(tradeHashes) do
local descriptionLines = '"' .. table.concat(desc, '", "') .. '"'
out:write(string.format('[%d] = { %s }, ', hash, descriptionLines))
end
out:write('} ')
out:write('},\n')
else
print("Mod '" .. mod.Id .. "' has no stats")
end
end
::continue::
end
out:write('}')
out:close()
end
-- generic explicit mods
writeMods("../Data/ModExplicit.lua", function(mod)
return mod.Domain == Domains.Item
and (mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix)
-- excl. separately exported mods
and not mod.Id:match("Royale")
and not mod.Id:match("Necropolis")
and not mod.Id:match("^Synthesis")
and not (mod.GenerationType == GenTypes.SearingExarch or mod.GenerationType == GenTypes.EaterOfWorlds)
and #mod.AuraFlags == 0
end)
writeMods("../Data/ModCorrupted.lua", function(mod)
return mod.GenerationType == GenTypes.Corrupted and mod.Domain == Domains.Item
end)
writeMods("../Data/ModDelve.lua", function(mod)
-- contains both explicit mods and the "item sells for more" implicit
return mod.Domain == Domains.DelveFossil
end)
writeMods("../Data/ModSynthesis.lua", function(mod)
return mod.GenerationType == GenTypes.Intrinsic and mod.Domain == Domains.Item
and mod.Id:match("^Synthesis")
end)
writeMods("../Data/ModScourge.lua", function(mod)
return mod.Domain == Domains.Item and
(mod.GenerationType == GenTypes.ScourgeBenefit or mod.GenerationType == GenTypes.ScourgeDownside) and
not mod.Id:match("^Hellscape[UpDown]+sideMap") -- Exclude Scourge map mods
end)
writeMods("../Data/ModEldritch.lua", function(mod)
return mod.Domain == Domains.Item and
(mod.GenerationType == GenTypes.SearingExarch or mod.GenerationType == GenTypes.EaterOfWorlds)
end)
writeMods("../Data/ModFlask.lua", function(mod)
return mod.Domain == Domains.Flask and
(mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix)
end)
writeMods("../Data/ModTincture.lua", function(mod)
return (mod.Domain == Domains.Tincture) and
(mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix)
end)
writeMods("../Data/ModJewel.lua", function(mod)
return (mod.Domain == Domains.Jewel or mod.Domain == Domains.DelveFossil) and
(mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix or mod.GenerationType == GenTypes.Corrupted)
end)
writeMods("../Data/ModJewelAbyss.lua", function(mod)
return (mod.Domain == Domains.AbyssJewel or mod.Domain == Domains.DelveFossil) and
(mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix or mod.GenerationType == GenTypes.Corrupted)
end)
writeMods("../Data/ModJewelCluster.lua", function(mod)
return (mod.Domain == Domains.ClusterJewel and (mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix)) or
(mod.Domain == Domains.Jewel and mod.GenerationType == GenTypes.Corrupted)
end)
writeMods("../Data/ModJewelCharm.lua", function(mod)
return (mod.Domain == Domains.Charm) and
(mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix)
end)
writeMods("../Data/Uniques/Special/WatchersEye.lua", function(mod)
return mod.Family[1] and (mod.Family[1].Id == "AuraBonus" or mod.Family[1].Id == "ArbalestBonus") and
mod.GenerationType == GenTypes.Intrinsic and not mod.Id:match("^Synthesis")
end)
writeMods("../Data/Uniques/Special/BoundByDestiny.lua", function(mod)
return mod.Family[2] and mod.Family[2].Id:match("MatchedInfluencesTier")
end)
writeMods("../Data/ModVeiled.lua", function(mod)
return mod.Domain == Domains.Unveiled and
(mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix)
end)
writeMods("../Data/ModNecropolis.lua", function(mod)
return mod.Domain == Domains.Item and mod.Id:match("^NecropolisCrafting")
end)
writeMods("../Data/ModItemExclusive.lua",
-- contains primarily uniques and items implicits but also other mods only available on a single base or unique.
function(mod)
return (mod.Domain == Domains.Item or mod.Domain == Domains.Flask or mod.Domain == Domains.Jewel or mod.Domain == Domains.ClusterJewel or mod.Domain == Domains.Tincture) and
mod.GenerationType == GenTypes.Intrinsic
and (mod.Family[1] and mod.Family[1].Id ~= "AuraBonus")
and not mod.Id:match("^Synthesis") and not mod.Id:match("Royale")
and not mod.Id:match("Cowards") and not mod.Id:match("Map")
and not mod.Id:match("Ultimatum") and not mod.Id:match("^MutatedUnique")
and not mod.Id:match("UNUSED")
end)
writeMods("../Data/ModGraft.lua", function(mod)
return mod.Domain == Domains.Graft and
(mod.GenerationType == GenTypes.Prefix or mod.GenerationType == GenTypes.Suffix or mod.GenerationType == GenTypes.Corrupted)
end)
writeMods("../Data/BeastCraft.lua", function(mod)
return (mod.Id:match("Aspect") and mod.GenerationType == GenTypes.Suffix) -- Aspect Crafts
end)
writeMods("../Data/ModFoulborn.lua", function(mod)
return (mod.Domain == Domains.Item or mod.Domain == Domains.Jewel) and mod.GenerationType == GenTypes.Intrinsic and mod.Id:match("^MutatedUnique")
end)
-- Generate unique mod mappings from text to mod
local out = io.open("Uniques/ModTextMap.lua", "w")
local modTextMap = {}
out:write('-- This file is automatically generated, do not edit!\n')
out:write('-- Item data (c) Grinding Gear Games\n\nreturn {\n')
for modName, mod in pairsSortByKey(LoadModule("../Data/ModItemExclusive.lua")) do
if not mod[1]:match("^DNT") then
if modTextMap[mod[1]:lower()] then
table.insert(modTextMap[mod[1]:lower()], modName)
else
modTextMap[mod[1]:lower()] = { modName }
end
-- Add generic mod for matching legacy values
if mod[1]:match('%d+') then
local genericText = mod[1]:gsub('(%-*%d*%.*%d+%-*%-*%d*%.*%d*)', '#')
if genericText ~= mod[1] then
if modTextMap[genericText:lower()] then
table.insert(modTextMap[genericText:lower()], modName)
else
modTextMap[genericText:lower()] = { modName }
end
end
end
end
end
for key, value in pairsSortByKey(modTextMap) do
out:write('\t["' .. key .. '"] = { ')
for _, modName in ipairs(value) do
out:write('"' .. modName .. '", ')
end
out:write('},\n')
end
out:write('\n}')
out:close()
print("Mods exported.")