6363-- Parse raw item data and extract item name, base type, quality, and modifiers
6464function ItemClass :ParseRaw (raw )
6565 self .raw = raw
66- local data = data
6766 self .name = " ?"
6867 self .rarity = " UNIQUE"
6968 self .quality = nil
@@ -97,82 +96,23 @@ function ItemClass:ParseRaw(raw)
9796 end
9897 if self .rawLines [l ] then
9998 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
136101 l = l + 1
137102 end
138103 end
139- self .base = data .itemBases [self .baseName ]
140104 self .sockets = { }
141105 self .buffModLines = { }
142106 self .enchantModLines = { }
143107 self .implicitModLines = { }
144108 self .explicitModLines = { }
145109 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
156110 self .variantList = nil
157111 self .prefixes = { }
158112 self .suffixes = { }
159113 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
167114 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
176116 local deferJewelRadiusIndexAssignment
177117 local gameModeStage = " FINDIMPLICIT"
178118 local foundExplicit , foundImplicit
@@ -189,7 +129,7 @@ function ItemClass:ParseRaw(raw)
189129
190130 while self .rawLines [l ] do
191131 local line = self .rawLines [l ]
192- if flaskBuffLines [line ] then
132+ if flaskBuffLines and flaskBuffLines [line ] then
193133 flaskBuffLines [line ] = nil
194134 elseif line == " --------" then
195135 if gameModeStage == " IMPLICIT" then
@@ -232,6 +172,9 @@ function ItemClass:ParseRaw(raw)
232172 self .itemLevel = tonumber (specVal )
233173 elseif specName == " Quality" then
234174 self .quality = tonumber (specVal )
175+ if line :match (" %(augmented%)" ) and self .quality ~= 30 then
176+ self .quality = 20
177+ end
235178 elseif specName == " Sockets" then
236179 local group = 0
237180 for c in specVal :gmatch (" ." ) do
@@ -367,6 +310,81 @@ function ItemClass:ParseRaw(raw)
367310 variantList [tonumber (varId )] = true
368311 end
369312 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
370388 local fractured = line :match (" {fractured}" ) or line :match (" %(fractured%)" )
371389 local rangeSpec = line :match (" {range:([%d.]+)}" )
372390 local enchant = line :match (" %(enchant%)" )
@@ -452,6 +470,9 @@ function ItemClass:ParseRaw(raw)
452470 end
453471 l = l + 1
454472 end
473+ if self .baseName and self .title then
474+ self .name = self .title .. " , " .. self .baseName :gsub (" %(.+%)" ," " )
475+ end
455476 if self .base and not self .requirements .level then
456477 if importedLevelReq and # self .sockets == 0 then
457478 -- Requirements on imported items can only be trusted for items with no sockets
@@ -618,6 +639,18 @@ function ItemClass:BuildRaw()
618639 end
619640 t_insert (rawLines , " Selected Variant: " .. self .variant )
620641
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
621654 if self .hasAltVariant then
622655 t_insert (rawLines , " Has Alt Variant: true" )
623656 t_insert (rawLines , " Selected Alt Variant: " .. self .variantAlt )
@@ -852,23 +885,25 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
852885 end
853886 end
854887 end
888+ local extraQuality = sumLocal (modList , " Quality" , " BASE" , 0 )
855889 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" )
857891 end
858892 if self .base .weapon then
859893 local weaponData = { }
860894 self .weaponData [slotNum ] = weaponData
861895 weaponData .type = self .base .type
862896 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 ))
864899 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 ))
866901 for _ , dmgType in pairs (dmgTypeList ) do
867902 local min = (self .base .weapon [dmgType .. " Min" ] or 0 ) + sumLocal (modList , dmgType .. " Min" , " BASE" , 0 )
868903 local max = (self .base .weapon [dmgType .. " Max" ] or 0 ) + sumLocal (modList , dmgType .. " Max" , " BASE" , 0 )
869904 if dmgType == " Physical" then
870905 local physInc = sumLocal (modList , " PhysicalDamage" , " INC" , 0 )
871- local qualityScalar = self .quality
906+ local qualityScalar = weaponData .quality
872907 if sumLocal (modList , " AlternateQualityWeapon" , " BASE" , 0 ) > 0 then
873908 qualityScalar = 0
874909 end
@@ -885,7 +920,7 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
885920 end
886921 end
887922 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 )
889924 for _ , value in ipairs (modList :List (nil , " WeaponData" )) do
890925 weaponData [value .key ] = value .value
891926 end
@@ -908,6 +943,7 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
908943 end
909944 elseif self .base .armour then
910945 local armourData = self .armourData
946+ armourData .quality = self .quality + extraQuality
911947 local armourBase = sumLocal (modList , " Armour" , " BASE" , 0 ) + (self .base .armour .ArmourBase or 0 )
912948 local armourEvasionBase = sumLocal (modList , " ArmourAndEvasion" , " BASE" , 0 )
913949 local evasionBase = sumLocal (modList , " Evasion" , " BASE" , 0 ) + (self .base .armour .EvasionBase or 0 )
@@ -921,7 +957,7 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
921957 local energyShieldInc = sumLocal (modList , " EnergyShield" , " INC" , 0 )
922958 local armourEnergyShieldInc = sumLocal (modList , " ArmourAndEnergyShield" , " INC" , 0 )
923959 local defencesInc = sumLocal (modList , " Defences" , " INC" , 0 )
924- local qualityScalar = self .quality
960+ local qualityScalar = armourData .quality
925961 if sumLocal (modList , " AlternateQualityArmour" , " BASE" , 0 ) > 0 then
926962 qualityScalar = 0
927963 end
@@ -940,27 +976,28 @@ function ItemClass:BuildModListForSlotNum(baseList, slotNum)
940976 elseif self .base .flask then
941977 local flaskData = self .flaskData
942978 local durationInc = sumLocal (modList , " Duration" , " INC" , 0 )
979+ flaskData .quality = self .quality + extraQuality
943980 if self .base .flask .life or self .base .flask .mana then
944981 -- Recovery flask
945982 flaskData .instantPerc = sumLocal (modList , " FlaskInstantRecovery" , " BASE" , 0 )
946983 local recoveryMod = 1 + sumLocal (modList , " FlaskRecovery" , " INC" , 0 ) / 100
947984 local rateMod = 1 + sumLocal (modList , " FlaskRecoveryRate" , " INC" , 0 ) / 100
948985 flaskData .duration = self .base .flask .duration * (1 + durationInc / 100 ) / rateMod
949986 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
951988 flaskData .lifeInstant = flaskData .lifeBase * flaskData .instantPerc / 100
952989 flaskData .lifeGradual = flaskData .lifeBase * (1 - flaskData .instantPerc / 100 ) * (1 + durationInc / 100 )
953990 flaskData .lifeTotal = flaskData .lifeInstant + flaskData .lifeGradual
954991 end
955992 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
957994 flaskData .manaInstant = flaskData .manaBase * flaskData .instantPerc / 100
958995 flaskData .manaGradual = flaskData .manaBase * (1 - flaskData .instantPerc / 100 ) * (1 + durationInc / 100 )
959996 flaskData .manaTotal = flaskData .manaInstant + flaskData .manaGradual
960997 end
961998 else
962999 -- 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 )
9641001 end
9651002 flaskData .chargesMax = self .base .flask .chargesMax + sumLocal (modList , " FlaskCharges" , " BASE" , 0 )
9661003 flaskData .chargesUsed = m_floor (self .base .flask .chargesUsed * (1 + sumLocal (modList , " FlaskChargesUsed" , " INC" , 0 ) / 100 ))
0 commit comments