diff --git a/src/Classes/Item.lua b/src/Classes/Item.lua index 2d70a61a47..fa65282d47 100644 --- a/src/Classes/Item.lua +++ b/src/Classes/Item.lua @@ -435,13 +435,13 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) end end elseif specName == "Radius" and self.type == "Jewel" then - self.jewelRadiusLabel = specVal:match("^%a+") + self.jewelRadiusLabel = specVal:match("^%[a ]+") if specVal:match("^%a+") == "Variable" then -- Jewel radius is variable and must be read from it's mods instead after they are parsed deferJewelRadiusIndexAssignment = true else for index, data in pairs(data.jewelRadius) do - if specVal:match("^%a+") == data.label then + if specVal:match("^%[a ]+") == data.label then self.jewelRadiusIndex = index break end diff --git a/src/Data/ModItemExclusive.lua b/src/Data/ModItemExclusive.lua new file mode 100644 index 0000000000..d8afc10941 --- /dev/null +++ b/src/Data/ModItemExclusive.lua @@ -0,0 +1,29 @@ +-- This file is automatically generated, do not edit! +-- Item data (c) Grinding Gear Games + +return { + ["SummonArbalistNumberOfArbalistsAllowed"] = { affix = "", "+1 to number of Summoned Arbalists", statOrder = { 9046 }, level = 1, group = "SummonArbalistNumberOfArbalistsAllowed", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistNumberOfAdditionalProjectiles_"] = { affix = "", "Summoned Arbalists fire (2-4) additional Projectiles", statOrder = { 9760 }, level = 1, group = "SummonArbalistNumberOfAdditionalProjectiles", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistAttackSpeed_"] = { affix = "", "Summoned Arbalists have (30-40)% increased Attack Speed", statOrder = { 9750 }, level = 1, group = "SummonArbalistAttackSpeed", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistTargetsToPierce"] = { affix = "", "Summoned Arbalists' Projectiles Pierce (2-4) additional Targets", statOrder = { 9769 }, level = 1, group = "SummonArbalistTargetsToPierce", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistProjectilesFork"] = { affix = "", "Summoned Arbalists' Projectiles Fork", statOrder = { 9768 }, level = 1, group = "SummonArbalistProjectilesFork", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChains_"] = { affix = "", "Summoned Arbalists' Projectiles Chain +2 times", statOrder = { 9751 }, level = 1, group = "SummonArbalistChains", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistNumberOfSplits__"] = { affix = "", "Summoned Arbalists' Projectiles Split into 3", statOrder = { 9761 }, level = 1, group = "SummonArbalistNumberOfSplits", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToDealDoubleDamage___"] = { affix = "", "Summoned Arbalists have (25-35)% chance to deal Double Damage", statOrder = { 9754 }, level = 1, group = "SummonArbalistChanceToDealDoubleDamage", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToMaimfor4secondsOnHit_"] = { affix = "", "Summoned Arbalists have (20-30)% chance to Maim for 4 seconds on Hit", statOrder = { 9757 }, level = 1, group = "SummonArbalistChanceToMaimfor4secondsOnHit", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToIntimidateFor4SecondsOnHit"] = { affix = "", "Summoned Arbalists have (20-30)% chance to Intimidate for 4 seconds on Hit", statOrder = { 9756 }, level = 1, group = "SummonArbalistChanceToIntimidateFor4SecondsOnHit", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToUnnerveFor4SecondsOnHit_"] = { affix = "", "Summoned Arbalists have (20-30)% chance to Unnerve for 4 seconds on Hit", statOrder = { 9759 }, level = 1, group = "SummonArbalistChanceToUnnerveFor4SecondsOnHit", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToInflictFireExposureOnHit_"] = { affix = "", "Summoned Arbalists have (10-20)% chance to inflict Fire Exposure on Hit", statOrder = { 9774 }, level = 1, group = "SummonArbalistChanceToInflictFireExposureOnHit", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToInflictColdExposureonHit"] = { affix = "", "Summoned Arbalists have (10-20)% chance to inflict Cold Exposure on Hit", statOrder = { 9773 }, level = 1, group = "SummonArbalistChanceToInflictColdExposureonHit", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToInflictLightningExposureOnHit_"] = { affix = "", "Summoned Arbalists have (10-20)% chance to inflict Lightning Exposure on Hit", statOrder = { 9775 }, level = 1, group = "SummonArbalistChanceToInflictLightningExposureOnHit", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToCrushOnHit"] = { affix = "", "Summoned Arbalists have (10-20)% chance to Crush on Hit", statOrder = { 9753 }, level = 1, group = "SummonArbalistChanceToCrushOnHit", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistPhysicalDamagePercentToConvertToFire"] = { affix = "", "Summoned Arbalists Convert 100% of Physical Damage to Fire Damage", "Summoned Arbalists have (10-20)% chance to Ignite", statOrder = { 9766, 9771 }, level = 1, group = "SummonArbalistPhysicalDamageToConvertToFire", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistPhysicalDamagePercentToConvertToCold_"] = { affix = "", "Summoned Arbalists Convert 100% of Physical Damage to Cold Damage", "Summoned Arbalists have (10-20)% chance to Freeze", statOrder = { 9765, 9770 }, level = 1, group = "SummonArbalistPhysicalDamageToConvertToCold", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistPhysicalDamagePercentToConvertToLightning"] = { affix = "", "Summoned Arbalists Convert 100% of Physical Damage to Lightning Damage", "Summoned Arbalists have (10-20)% chance to Shock", statOrder = { 9767, 9772 }, level = 1, group = "SummonArbalistPhysicalDamageToConvertToLightning", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistPhysicalDamagePercentToAddAsFire"] = { affix = "", "Summoned Arbalists gain (30-40)% of Physical Damage as Extra Fire Damage", "Summoned Arbalists have 20% chance to inflict Fire Exposure on Hit", statOrder = { 9763, 9774 }, level = 1, group = "SummonArbalistPhysicalDamageToAddAsFire", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistPhysicalDamagePercentToAddAsCold_"] = { affix = "", "Summoned Arbalists gain (30-40)% of Physical Damage as Extra Cold Damage", "Summoned Arbalists have 20% chance to inflict Cold Exposure on Hit", statOrder = { 9762, 9773 }, level = 1, group = "SummonArbalistPhysicalDamageToAddAsCold", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistPhysicalDamagePercentToAddAsLightning"] = { affix = "", "Summoned Arbalists gain (30-40)% of Physical Damage as Extra Lightning Damage", "Summoned Arbalists have 20% chance to inflict Lightning Exposure on Hit", statOrder = { 9764, 9775 }, level = 1, group = "SummonArbalistPhysicalDamageToAddAsLightning", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToBleedPercent_"] = { affix = "", "Summoned Arbalists' Attacks have (40-60)% chance to inflict Bleeding", statOrder = { 9752 }, level = 1, group = "SummonArbalistChanceToBleed", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToPoisonPercent"] = { affix = "", "Summoned Arbalists have (40-60)% chance to Poison", statOrder = { 9758 }, level = 1, group = "SummonArbalistChanceToPoison", weightKey = { }, weightVal = { }, modTags = { }, }, + ["SummonArbalistChanceToIgniteFreezeShockPercent"] = { affix = "", "Summoned Arbalists have (15-25)% chance to Freeze, Shock, and Ignite", statOrder = { 9755 }, level = 1, group = "SummonArbalistChanceToIgniteFreezeShock", weightKey = { }, weightVal = { }, modTags = { }, }, +} \ No newline at end of file diff --git a/src/Export/Scripts/mods.lua b/src/Export/Scripts/mods.lua index 498fe71a0e..d594e9e300 100644 --- a/src/Export/Scripts/mods.lua +++ b/src/Export/Scripts/mods.lua @@ -166,6 +166,11 @@ end) writeMods("../Data/ModNecropolis.lua", function(mod) return mod.Domain == 1 and mod.Id:match("^NecropolisCrafting") end) +writeMods("../Data/ModItemExclusive.lua", function(mod) -- contains primarily uniques and items implicits but also other mods only available on a single base or unique. + return (mod.Domain == 1 or mod.Domain == 2 or mod.Domain == 11 or mod.Domain == 22) and mod.GenerationType == 3 + and (mod.Family[1] and mod.Family[1].Id ~= "AuraBonus" or not mod.Family[1]) + 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") +end) print("Mods exported.") diff --git a/src/Export/Scripts/uModsToText.lua b/src/Export/Scripts/uModsToText.lua new file mode 100644 index 0000000000..5a2ff9c7a1 --- /dev/null +++ b/src/Export/Scripts/uModsToText.lua @@ -0,0 +1,151 @@ +if not table.containsId then + dofile("Scripts/mods.lua") +end +local catalystTags = { + ["attack"] = true, + ["speed"] = true, + ["life"] = true, + ["mana"] = true, + ["caster"] = true, + ["attribute"] = true, + ["physical"] = true, + ["fire"] = true, + ["cold"] = true, + ["lightning"] = true, + ["chaos"] = true, + ["defences"] = true, +} +local itemTypes = { + -- "axe", + -- "bow", + -- "claw", + -- "dagger", + -- "fishing", + -- "mace", + -- "sceptre", + -- "spear", + -- "staff", + -- "sword", + -- "wand", + -- "helmet", + -- "body", + -- "focus", + -- "gloves", + -- "boots", + -- "shield", + -- "quiver", + -- "amulet", + -- "ring", + -- "belt", + -- "jewel", + -- "flask", + -- "tincture", +} +local function writeMods(out, statOrder) + local orders = { } + for order, _ in pairs(statOrder) do + table.insert(orders, order) + end + table.sort(orders) + for _, order in pairs(orders) do + for _, line in ipairs(statOrder[order]) do + out:write(line, "\n") + end + end +end + +local uniqueMods = LoadModule("../Data/ModItemExclusive.lua") +for _, name in ipairs(itemTypes) do + local out = io.open("../Data/Uniques/"..name..".lua", "w") + local statOrder = {} + local postModLines = {} + local modLines = 0 + local implicits + for line in io.lines("Uniques/"..name..".lua") do + if implicits then -- remove 1 downs to 0 + implicits = implicits - 1 + end + local specName, specVal = line:match("^([%a ]+): (.+)$") + if line:match("]],") then -- start new unique + writeMods(out, statOrder) + for _, line in ipairs(postModLines) do + out:write(line, "\n") + end + out:write(line, "\n") + statOrder = { } + postModLines = { } + modLines = 0 + elseif not specName then + local prefix = "" + local variantString = line:match("({variant:[%d,]+})") + local fractured = line:match("({fractured})") or "" + local modName, legacy = line:gsub("{.+}", ""):match("^([%a%d_]+)([%[%]-,%d]*)") + local mod = uniqueMods[modName] + if mod then + modLines = modLines + 1 + if variantString then + prefix = prefix ..variantString + end + local tags = {} + if isValueInArray({"amulet", "ring"}, name) then + for _, tag in ipairs(mod.modTags) do + if catalystTags[tag] then + table.insert(tags, tag) + end + end + end + if tags[1] then + prefix = prefix.."{tags:"..table.concat(tags, ",").."}" + end + prefix = prefix..fractured + local legacyMod + if legacy ~= "" then + local values = { } + for range in legacy:gmatch("%b[]") do + local min, max = range:match("%[([%d%-]+),([%d%-]+)%]") + table.insert(values, { min = tonumber(min), max = tonumber(max) }) + end + local mod = dat("Mods"):GetRow("Id", modName) + local stats = { } + for i = 1, 6 do + if mod["Stat"..i] then + stats[mod["Stat"..i].Id] = values[i] + end + end + if mod.Type then + stats.Type = mod.Type + end + legacyMod = describeStats(stats) + end + for i, line in ipairs(legacyMod or mod) do + local order = mod.statOrder[i] + if statOrder[order] then + table.insert(statOrder[order], prefix..line) + else + statOrder[order] = { prefix..line } + end + end + else + if modLines > 0 then -- treat as post line e.g. mirrored + table.insert(postModLines, line) + else + out:write(line, "\n") + end + end + else + if specName == "Implicits" then + implicits = tonumber(specVal) + end + out:write(line, "\n") + end + if implicits and implicits == 0 then + writeMods(out, statOrder) + implicits = nil + statOrder = { } + modLines = 0 + end + end + out:close() +end + +print("Unique text updated.") diff --git a/src/Export/statdesc.lua b/src/Export/statdesc.lua index d7550efa9a..cbb4dd6990 100644 --- a/src/Export/statdesc.lua +++ b/src/Export/statdesc.lua @@ -44,7 +44,7 @@ function loadStatFile(fileName) curLang = { } --curDescriptor.lang[langName] = curLang else - local statLimits, text, special = line:match('([%d%-#| ]+) "(.-)"%s*(.*)') + local statLimits, text, special = line:match('([%d%-#| !]+) "(.-)"%s*(.*)') if statLimits then local desc = { text = text, limit = { } } for statLimit in statLimits:gmatch("[!%d%-#|]+") do @@ -96,7 +96,12 @@ local function matchLimit(lang, val) for _, desc in ipairs(lang) do local match = true for i, limit in ipairs(desc.limit) do - if (limit[2] ~= "#" and val[i].min > limit[2]) or (limit[1] ~= "#" and val[i].min < limit[1]) then + if limit[1] == "!" then + if val[i].min == limit[2] then + match = false + break + end + elseif (limit[2] ~= "#" and val[i].min > limit[2]) or (limit[1] ~= "#" and val[i].min < limit[1]) then match = false break end @@ -145,6 +150,24 @@ function describeStats(stats) val[i].fmt = "d" end local desc = matchLimit(descriptor[1], val) + -- Hack to handle ranges starting or ending at 0 where no descriptor is defined for 0 + -- Attempt to adapt existing ranges + if not desc then + for _, s in ipairs(val) do + if s.min == 0 and s.max > 0 then + s.min = 1 + s.minz = true + elseif s.min < 0 and s.max == 0 then + s.max = -1 + s.maxz = true + end + end + desc = matchLimit(descriptor[1], val) + for _, s in ipairs(val) do + if s.minz then s.min = 0 end + if s.maxz then s.max = 0 end + end + end if desc then for _, spec in ipairs(desc) do if spec.k == "negate" then