63
63
-- Parse raw item data and extract item name, base type, quality, and modifiers
64
64
function ItemClass :ParseRaw (raw )
65
65
self .raw = raw
66
- local data = data
67
66
self .name = " ?"
68
67
self .rarity = " UNIQUE"
69
68
self .quality = nil
@@ -97,82 +96,23 @@ function ItemClass:ParseRaw(raw)
97
96
end
98
97
if self .rawLines [l ] then
99
98
self .name = self .rawLines [l ]
100
- l = l + 1
101
- end
102
- self .namePrefix = " "
103
- self .nameSuffix = " "
104
- if self .rarity == " NORMAL" or self .rarity == " MAGIC" then
105
- for baseName , baseData in pairs (data .itemBases ) do
106
- local s , e = self .name :find (baseName , 1 , true )
107
- if s then
108
- self .baseName = baseName
109
- self .namePrefix = self .name :sub (1 , s - 1 )
110
- self .nameSuffix = self .name :sub (e + 1 )
111
- self .type = baseData .type
112
- break
113
- end
114
- end
115
- if not self .baseName then
116
- local s , e = self .name :find (" Two-Toned Boots" , 1 , true )
117
- if s then
118
- -- Hack for Two-Toned Boots
119
- self .baseName = " Two-Toned Boots (Armour/Energy Shield)"
120
- self .namePrefix = self .name :sub (1 , s - 1 )
121
- self .nameSuffix = self .name :sub (e + 1 )
122
- self .type = " Boots"
123
- end
124
- end
125
- self .name = self .name :gsub (" %(.+%)" ," " )
126
- elseif self .rawLines [l ] and not self .rawLines [l ]:match (" ^%-" ) then
127
- if self .rawLines [l ] == " Two-Toned Boots" then
128
- self .rawLines [l ] = " Two-Toned Boots (Armour/Energy Shield)"
129
- end
130
- local baseName = self .rawLines [l ]:gsub (" Synthesised " ," " )
131
- if data .itemBases [baseName ] then
132
- self .baseName = baseName
133
- self .title = self .name
134
- self .name = self .title .. " , " .. baseName :gsub (" %(.+%)" ," " )
135
- self .type = data .itemBases [baseName ].type
99
+ -- Found the name for a rare or unique, but let's parse it if it's a magic or normal item to get the base
100
+ if not (self .rarity == " NORMAL" or self .rarity == " MAGIC" ) then
136
101
l = l + 1
137
102
end
138
103
end
139
- self .base = data .itemBases [self .baseName ]
140
104
self .sockets = { }
141
105
self .buffModLines = { }
142
106
self .enchantModLines = { }
143
107
self .implicitModLines = { }
144
108
self .explicitModLines = { }
145
109
local implicitLines = 0
146
- if self .base then
147
- self .affixes = (self .base .subType and data .itemMods [self .base .type .. self .base .subType ])
148
- or data .itemMods [self .base .type ]
149
- or data .itemMods .Item
150
- self .enchantments = data .enchantments [self .base .type ]
151
- self .corruptable = self .base .type ~= " Flask" and self .base .subType ~= " Cluster"
152
- self .influenceTags = data .specialBaseTags [self .type ]
153
- self .canBeInfluenced = self .influenceTags
154
- self .clusterJewel = data .clusterJewels and data .clusterJewels .jewels [self .baseName ]
155
- end
156
110
self .variantList = nil
157
111
self .prefixes = { }
158
112
self .suffixes = { }
159
113
self .requirements = { }
160
- if self .base then
161
- self .requirements .str = self .base .req .str or 0
162
- self .requirements .dex = self .base .req .dex or 0
163
- self .requirements .int = self .base .req .int or 0
164
- local maxReq = m_max (self .requirements .str , self .requirements .dex , self .requirements .int )
165
- self .defaultSocketColor = (maxReq == self .requirements .dex and " G" ) or (maxReq == self .requirements .int and " B" ) or " R"
166
- end
167
114
local importedLevelReq
168
- local flaskBuffLines = { }
169
- if self .base and self .base .flask and self .base .flask .buff then
170
- for _ , line in ipairs (self .base .flask .buff ) do
171
- flaskBuffLines [line ] = true
172
- local modList , extra = modLib .parseMod (line )
173
- t_insert (self .buffModLines , { line = line , extra = extra , modList = modList or { } })
174
- end
175
- end
115
+ local flaskBuffLines
176
116
local deferJewelRadiusIndexAssignment
177
117
local gameModeStage = " FINDIMPLICIT"
178
118
local foundExplicit , foundImplicit
@@ -189,7 +129,7 @@ function ItemClass:ParseRaw(raw)
189
129
190
130
while self .rawLines [l ] do
191
131
local line = self .rawLines [l ]
192
- if flaskBuffLines [line ] then
132
+ if flaskBuffLines and flaskBuffLines [line ] then
193
133
flaskBuffLines [line ] = nil
194
134
elseif line == " --------" then
195
135
if gameModeStage == " IMPLICIT" then
@@ -232,6 +172,9 @@ function ItemClass:ParseRaw(raw)
232
172
self .itemLevel = tonumber (specVal )
233
173
elseif specName == " Quality" then
234
174
self .quality = tonumber (specVal )
175
+ if line :match (" %(augmented%)" ) and self .quality ~= 30 then
176
+ self .quality = 20
177
+ end
235
178
elseif specName == " Sockets" then
236
179
local group = 0
237
180
for c in specVal :gmatch (" ." ) do
@@ -367,6 +310,81 @@ function ItemClass:ParseRaw(raw)
367
310
variantList [tonumber (varId )] = true
368
311
end
369
312
end
313
+ if line :gsub (" ({variant:[%d,]+})" , " " ) == " Two-Toned Boots" then
314
+ line = " Two-Toned Boots (Armour/Energy Shield)"
315
+ end
316
+ self .namePrefix = self .namePrefix or " "
317
+ self .nameSuffix = self .nameSuffix or " "
318
+ if self .rarity == " NORMAL" or self .rarity == " MAGIC" then
319
+ -- Exact match (affix-less magic and normal items)
320
+ if data .itemBases [self .name ] then
321
+ self .baseName = self .name
322
+ self .type = data .itemBases [self .name ].type
323
+ else
324
+ -- Partial match (magic items with affixes)
325
+ for baseName , baseData in pairs (data .itemBases ) do
326
+ local s , e = self .name :find (baseName , 1 , true )
327
+ if s then
328
+ -- Set the base name if it isn't there, or we found a better match, so replace it
329
+ if (self .baseName and string.len (self .namePrefix ) > string.len (self .name :sub (1 , s - 1 )))
330
+ or self .baseName == nil or self .baseName == " " then
331
+ self .namePrefix = self .name :sub (1 , s - 1 )
332
+ self .nameSuffix = self .name :sub (e + 1 )
333
+ self .baseName = baseName
334
+ self .type = baseData .type
335
+ end
336
+ end
337
+ end
338
+ end
339
+ if not self .baseName then
340
+ local s , e = self .name :find (" Two-Toned Boots" , 1 , true )
341
+ if s then
342
+ -- Hack for Two-Toned Boots
343
+ self .baseName = " Two-Toned Boots (Armour/Energy Shield)"
344
+ self .namePrefix = self .name :sub (1 , s - 1 )
345
+ self .nameSuffix = self .name :sub (e + 1 )
346
+ self .type = " Boots"
347
+ end
348
+ end
349
+ self .name = self .name :gsub (" %(.+%)" ," " )
350
+ end
351
+ local baseName = self .baseName or " "
352
+ if self .variant and varSpec then
353
+ if tonumber (varSpec ) == self .variant then
354
+ baseName = line :gsub (" Synthesised " ," " ):gsub (" {variant:([%d,]+)}" , " " )
355
+ end
356
+ elseif baseName == " " then
357
+ baseName = line :gsub (" Synthesised " ," " ):gsub (" {variant:([%d,]+)}" , " " )
358
+ end
359
+ if baseName and data .itemBases [baseName ] then
360
+ self .baseName = baseName
361
+ if not (self .rarity == " NORMAL" or self .rarity == " MAGIC" ) then
362
+ self .title = self .name
363
+ end
364
+ self .type = data .itemBases [baseName ].type
365
+ self .base = data .itemBases [self .baseName ]
366
+ self .affixes = (self .base .subType and data .itemMods [self .base .type .. self .base .subType ])
367
+ or data .itemMods [self .base .type ]
368
+ or data .itemMods .Item
369
+ self .enchantments = data .enchantments [self .base .type ]
370
+ self .corruptable = self .base .type ~= " Flask" and self .base .subType ~= " Cluster"
371
+ self .influenceTags = data .specialBaseTags [self .type ]
372
+ self .canBeInfluenced = self .influenceTags
373
+ self .clusterJewel = data .clusterJewels and data .clusterJewels .jewels [self .baseName ]
374
+ self .requirements .str = self .base .req .str or 0
375
+ self .requirements .dex = self .base .req .dex or 0
376
+ self .requirements .int = self .base .req .int or 0
377
+ local maxReq = m_max (self .requirements .str , self .requirements .dex , self .requirements .int )
378
+ self .defaultSocketColor = (maxReq == self .requirements .dex and " G" ) or (maxReq == self .requirements .int and " B" ) or " R"
379
+ if self .base .flask and self .base .flask .buff and not flaskBuffLines then
380
+ flaskBuffLines = { }
381
+ for _ , line in ipairs (self .base .flask .buff ) do
382
+ flaskBuffLines [line ] = true
383
+ local modList , extra = modLib .parseMod (line )
384
+ t_insert (self .buffModLines , { line = line , extra = extra , modList = modList or { } })
385
+ end
386
+ end
387
+ end
370
388
local fractured = line :match (" {fractured}" ) or line :match (" %(fractured%)" )
371
389
local rangeSpec = line :match (" {range:([%d.]+)}" )
372
390
local enchant = line :match (" %(enchant%)" )
@@ -452,6 +470,9 @@ function ItemClass:ParseRaw(raw)
452
470
end
453
471
l = l + 1
454
472
end
473
+ if self .baseName and self .title then
474
+ self .name = self .title .. " , " .. self .baseName :gsub (" %(.+%)" ," " )
475
+ end
455
476
if self .base and not self .requirements .level then
456
477
if importedLevelReq and # self .sockets == 0 then
457
478
-- Requirements on imported items can only be trusted for items with no sockets
@@ -618,6 +639,18 @@ function ItemClass:BuildRaw()
618
639
end
619
640
t_insert (rawLines , " Selected Variant: " .. self .variant )
620
641
642
+ local hasVariantBases = false
643
+ local i = 1
644
+ for _ , variantName in ipairs (self .variantList ) do
645
+ if data .itemBases [variantName ] then
646
+ t_insert (rawLines , " {variant:" .. i .. " }" .. variantName )
647
+ hasVariantBases = true
648
+ end
649
+ i = i + 1
650
+ end
651
+ if not hasVariantBases then
652
+ t_insert (rawLines , self .baseName )
653
+ end
621
654
if self .hasAltVariant then
622
655
t_insert (rawLines , " Has Alt Variant: true" )
623
656
t_insert (rawLines , " Selected Alt Variant: " .. self .variantAlt )
@@ -852,23 +885,25 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
852
885
end
853
886
end
854
887
end
888
+ local extraQuality = sumLocal (modList , " Quality" , " BASE" , 0 )
855
889
if self .quality then
856
- modList :NewMod (" Multiplier:QualityOn" .. slotName , " BASE" , self .quality , " Quality" )
890
+ modList :NewMod (" Multiplier:QualityOn" .. slotName , " BASE" , self .quality + extraQuality , " Quality" )
857
891
end
858
892
if self .base .weapon then
859
893
local weaponData = { }
860
894
self .weaponData [slotNum ] = weaponData
861
895
weaponData .type = self .base .type
862
896
weaponData .name = self .name
863
- weaponData .AttackSpeedInc = sumLocal (modList , " Speed" , " INC" , ModFlag .Attack ) + m_floor (self .quality / 8 * sumLocal (modList , " AlternateQualityLocalAttackSpeedPer8Quality" , " INC" , 0 ))
897
+ weaponData .quality = extraQuality + self .quality
898
+ weaponData .AttackSpeedInc = sumLocal (modList , " Speed" , " INC" , ModFlag .Attack ) + m_floor (weaponData .quality / 8 * sumLocal (modList , " AlternateQualityLocalAttackSpeedPer8Quality" , " INC" , 0 ))
864
899
weaponData .AttackRate = round (self .base .weapon .AttackRateBase * (1 + weaponData .AttackSpeedInc / 100 ), 2 )
865
- weaponData .range = self .base .weapon .Range + sumLocal (modList , " WeaponRange" , " BASE" , 0 ) + m_floor (self .quality / 10 * sumLocal (modList , " AlternateQualityLocalWeaponRangePer10Quality" , " BASE" , 0 ))
900
+ weaponData .range = self .base .weapon .Range + sumLocal (modList , " WeaponRange" , " BASE" , 0 ) + m_floor (weaponData .quality / 10 * sumLocal (modList , " AlternateQualityLocalWeaponRangePer10Quality" , " BASE" , 0 ))
866
901
for _ , dmgType in pairs (dmgTypeList ) do
867
902
local min = (self .base .weapon [dmgType .. " Min" ] or 0 ) + sumLocal (modList , dmgType .. " Min" , " BASE" , 0 )
868
903
local max = (self .base .weapon [dmgType .. " Max" ] or 0 ) + sumLocal (modList , dmgType .. " Max" , " BASE" , 0 )
869
904
if dmgType == " Physical" then
870
905
local physInc = sumLocal (modList , " PhysicalDamage" , " INC" , 0 )
871
- local qualityScalar = self .quality
906
+ local qualityScalar = weaponData .quality
872
907
if sumLocal (modList , " AlternateQualityWeapon" , " BASE" , 0 ) > 0 then
873
908
qualityScalar = 0
874
909
end
@@ -885,7 +920,7 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
885
920
end
886
921
end
887
922
end
888
- weaponData .CritChance = round (self .base .weapon .CritChanceBase * (1 + (sumLocal (modList , " CritChance" , " INC" , 0 ) + m_floor (self .quality / 4 * sumLocal (modList , " AlternateQualityLocalCritChancePer4Quality" , " INC" , 0 ))) / 100 ), 2 )
923
+ weaponData .CritChance = round (self .base .weapon .CritChanceBase * (1 + (sumLocal (modList , " CritChance" , " INC" , 0 ) + m_floor (weaponData .quality / 4 * sumLocal (modList , " AlternateQualityLocalCritChancePer4Quality" , " INC" , 0 ))) / 100 ), 2 )
889
924
for _ , value in ipairs (modList :List (nil , " WeaponData" )) do
890
925
weaponData [value .key ] = value .value
891
926
end
@@ -908,6 +943,7 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
908
943
end
909
944
elseif self .base .armour then
910
945
local armourData = self .armourData
946
+ armourData .quality = self .quality + extraQuality
911
947
local armourBase = sumLocal (modList , " Armour" , " BASE" , 0 ) + (self .base .armour .ArmourBase or 0 )
912
948
local armourEvasionBase = sumLocal (modList , " ArmourAndEvasion" , " BASE" , 0 )
913
949
local evasionBase = sumLocal (modList , " Evasion" , " BASE" , 0 ) + (self .base .armour .EvasionBase or 0 )
@@ -921,7 +957,7 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
921
957
local energyShieldInc = sumLocal (modList , " EnergyShield" , " INC" , 0 )
922
958
local armourEnergyShieldInc = sumLocal (modList , " ArmourAndEnergyShield" , " INC" , 0 )
923
959
local defencesInc = sumLocal (modList , " Defences" , " INC" , 0 )
924
- local qualityScalar = self .quality
960
+ local qualityScalar = armourData .quality
925
961
if sumLocal (modList , " AlternateQualityArmour" , " BASE" , 0 ) > 0 then
926
962
qualityScalar = 0
927
963
end
@@ -940,27 +976,28 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
940
976
elseif self .base .flask then
941
977
local flaskData = self .flaskData
942
978
local durationInc = sumLocal (modList , " Duration" , " INC" , 0 )
979
+ flaskData .quality = self .quality + extraQuality
943
980
if self .base .flask .life or self .base .flask .mana then
944
981
-- Recovery flask
945
982
flaskData .instantPerc = sumLocal (modList , " FlaskInstantRecovery" , " BASE" , 0 )
946
983
local recoveryMod = 1 + sumLocal (modList , " FlaskRecovery" , " INC" , 0 ) / 100
947
984
local rateMod = 1 + sumLocal (modList , " FlaskRecoveryRate" , " INC" , 0 ) / 100
948
985
flaskData .duration = self .base .flask .duration * (1 + durationInc / 100 ) / rateMod
949
986
if self .base .flask .life then
950
- flaskData .lifeBase = self .base .flask .life * (1 + self .quality / 100 ) * recoveryMod
987
+ flaskData .lifeBase = self .base .flask .life * (1 + flaskData .quality / 100 ) * recoveryMod
951
988
flaskData .lifeInstant = flaskData .lifeBase * flaskData .instantPerc / 100
952
989
flaskData .lifeGradual = flaskData .lifeBase * (1 - flaskData .instantPerc / 100 ) * (1 + durationInc / 100 )
953
990
flaskData .lifeTotal = flaskData .lifeInstant + flaskData .lifeGradual
954
991
end
955
992
if self .base .flask .mana then
956
- flaskData .manaBase = self .base .flask .mana * (1 + self .quality / 100 ) * recoveryMod
993
+ flaskData .manaBase = self .base .flask .mana * (1 + flaskData .quality / 100 ) * recoveryMod
957
994
flaskData .manaInstant = flaskData .manaBase * flaskData .instantPerc / 100
958
995
flaskData .manaGradual = flaskData .manaBase * (1 - flaskData .instantPerc / 100 ) * (1 + durationInc / 100 )
959
996
flaskData .manaTotal = flaskData .manaInstant + flaskData .manaGradual
960
997
end
961
998
else
962
999
-- Utility flask
963
- flaskData .duration = self .base .flask .duration * (1 + (durationInc + self .quality ) / 100 )
1000
+ flaskData .duration = self .base .flask .duration * (1 + (durationInc + flaskData .quality ) / 100 )
964
1001
end
965
1002
flaskData .chargesMax = self .base .flask .chargesMax + sumLocal (modList , " FlaskCharges" , " BASE" , 0 )
966
1003
flaskData .chargesUsed = m_floor (self .base .flask .chargesUsed * (1 + sumLocal (modList , " FlaskChargesUsed" , " INC" , 0 ) / 100 ))
0 commit comments