481 lines
19 KiB
Lua
481 lines
19 KiB
Lua
-- Path of Building
|
|
--
|
|
-- Module: Data
|
|
-- Contains static data used by other modules.
|
|
--
|
|
|
|
LoadModule("Data/Global")
|
|
|
|
local skillTypes = {
|
|
"act_str",
|
|
"act_dex",
|
|
"act_int",
|
|
"other",
|
|
"glove",
|
|
"minion",
|
|
"spectre",
|
|
"sup_str",
|
|
"sup_dex",
|
|
"sup_int",
|
|
}
|
|
local itemTypes = {
|
|
"axe",
|
|
"bow",
|
|
"claw",
|
|
"dagger",
|
|
"mace",
|
|
"staff",
|
|
"sword",
|
|
"wand",
|
|
"helmet",
|
|
"body",
|
|
"gloves",
|
|
"boots",
|
|
"shield",
|
|
"quiver",
|
|
"amulet",
|
|
"ring",
|
|
"belt",
|
|
"jewel",
|
|
"flask",
|
|
}
|
|
|
|
local function makeSkillMod(modName, modType, modVal, flags, keywordFlags, ...)
|
|
return {
|
|
name = modName,
|
|
type = modType,
|
|
value = modVal,
|
|
flags = flags or 0,
|
|
keywordFlags = keywordFlags or 0,
|
|
...
|
|
}
|
|
end
|
|
local function makeFlagMod(modName, ...)
|
|
return makeSkillMod(modName, "FLAG", true, 0, 0, ...)
|
|
end
|
|
local function makeSkillDataMod(dataKey, dataValue, ...)
|
|
return makeSkillMod("SkillData", "LIST", { key = dataKey, value = dataValue }, 0, 0, ...)
|
|
end
|
|
local function processMod(grantedEffect, mod)
|
|
mod.source = grantedEffect.modSource
|
|
if type(mod.value) == "table" and mod.value.mod then
|
|
mod.value.mod.source = "Skill:"..grantedEffect.id
|
|
end
|
|
for _, tag in ipairs(mod) do
|
|
if tag.type == "GlobalEffect" then
|
|
grantedEffect.hasGlobalEffect = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
-----------------
|
|
-- Common Data --
|
|
-----------------
|
|
|
|
data = { }
|
|
|
|
data.powerStatList = {
|
|
{ stat=nil, label="Offence/Defence", combinedOffDef=true, ignoreForItems=true },
|
|
{ stat=nil, label="Name", itemField="Name", ignoreForNodes=true, reverseSort=true, transform=function(value) return value:gsub("^The ","") end},
|
|
{ stat="CombinedDPS", label="Combined DPS" },
|
|
{ stat="TotalDPS", label="Total DPS" },
|
|
{ stat="WithImpaleDPS", label="Impale + Total DPS" },
|
|
{ stat="AverageDamage", label="Average Hit" },
|
|
{ stat="Speed", label="Attack/Cast Speed" },
|
|
{ stat="TotalDot", label="DoT DPS" },
|
|
{ stat="BleedDPS", label="Bleed DPS" },
|
|
{ stat="IgniteDPS", label="Ignite DPS" },
|
|
{ stat="PoisonDPS", label="Poison DPS" },
|
|
{ stat="Life", label="Life" },
|
|
{ stat="LifeRegen", label="Life regen" },
|
|
{ stat="LifeLeechRate", label="Life leech" },
|
|
{ stat="EnergyShield", label="Energy Shield" },
|
|
{ stat="EnergyShieldRegen", label="Energy Shield regen" },
|
|
{ stat="EnergyShieldLeechRate", label="Energy Shield leech" },
|
|
{ stat="Mana", label="Mana" },
|
|
{ stat="ManaRegen", label="Mana regen" },
|
|
{ stat="ManaLeechRate", label="Mana leech" },
|
|
{ stat="Str", label="Strength" },
|
|
{ stat="Dex", label="Dexterity" },
|
|
{ stat="Int", label="Intelligence" },
|
|
{ stat="TotalAttr", label="Total Attributes" },
|
|
{ stat="MeleeAvoidChance", label="Melee avoid chance" },
|
|
{ stat="SpellAvoidChance", label="Spell avoid chance" },
|
|
{ stat="ProjectileAvoidChance", label="Projectile avoid chance" },
|
|
{ stat="PhysicalTotalEHP", label="eHP vs Physical hits" },
|
|
{ stat="LightningTotalEHP", label="eHP vs Lightning hits" },
|
|
{ stat="ColdTotalEHP", label="eHP vs Cold hits" },
|
|
{ stat="FireTotalEHP", label="eHP vs Fire hits" },
|
|
{ stat="ChaosTotalEHP", label="eHP vs Chaos hits" },
|
|
{ stat="PhysicalTakenHitMult", label="Taken Phys dmg", transform=function(value) return 1-value end },
|
|
{ stat="LightningTakenDotMult", label="Taken Lightning dmg", transform=function(value) return 1-value end },
|
|
{ stat="ColdTakenDotMult", label="Taken Cold dmg", transform=function(value) return 1-value end },
|
|
{ stat="FireTakenDotMult", label="Taken Fire dmg", transform=function(value) return 1-value end },
|
|
{ stat="ChaosTakenHitMult", label="Taken Chaos dmg", transform=function(value) return 1-value end },
|
|
{ stat="CritChance", label="Crit Chance" },
|
|
{ stat="CritMultiplier", label="Crit Multiplier" },
|
|
{ stat="BleedChance", label="Bleed Chance" },
|
|
{ stat="FreezeChance", label="Freeze Chance" },
|
|
{ stat="IgniteChance", label="Ignite Chance" },
|
|
{ stat="ShockChance", label="Shock Chance" },
|
|
{ stat="EffectiveMovementSpeedMod", label="Move speed" },
|
|
}
|
|
|
|
data.skillColorMap = { colorCodes.STRENGTH, colorCodes.DEXTERITY, colorCodes.INTELLIGENCE, colorCodes.NORMAL }
|
|
|
|
data.jewelRadius = {
|
|
{ inner = 0, outer = 800, col = "^xBB6600", label = "Small" },
|
|
{ inner = 0, outer = 1200, col = "^x66FFCC", label = "Medium" },
|
|
{ inner = 0, outer = 1500, col = "^x2222CC", label = "Large" },
|
|
|
|
{ inner = 850, outer = 1100, col = "^xD35400", label = "Variable" },
|
|
{ inner = 1150, outer = 1400, col = "^x66FFCC", label = "Variable" },
|
|
{ inner = 1450, outer = 1700, col = "^x2222CC", label = "Variable" },
|
|
{ inner = 1750, outer = 2000, col = "^xC100FF", label = "Variable" },
|
|
}
|
|
|
|
data.labyrinths = {
|
|
{ name = "ENDGAME", label = "Eternal" },
|
|
{ name = "MERCILESS", label = "Merciless" },
|
|
{ name = "CRUEL", label = "Cruel" },
|
|
{ name = "NORMAL", label = "Normal" },
|
|
}
|
|
|
|
local maxPenaltyFreeAreaLevel = 70
|
|
local maxAreaLevel = 87 -- T16 map + side area + three watchstones that grant +1 level
|
|
local penaltyMultiplier = 0.06
|
|
|
|
---@param areaLevel number
|
|
---@return number
|
|
local function effectiveMonsterLevel(areaLevel)
|
|
--- Areas with area level above a certain penalty-free level are considered to have
|
|
--- a scaling lower effective monster level for experience penalty calculations.
|
|
if areaLevel <= maxPenaltyFreeAreaLevel then
|
|
return areaLevel
|
|
end
|
|
return areaLevel - triangular(areaLevel - maxPenaltyFreeAreaLevel) * penaltyMultiplier
|
|
end
|
|
|
|
---@type table<number, number>
|
|
data.monsterExperienceLevelMap = {}
|
|
for i = 1, maxAreaLevel do
|
|
data.monsterExperienceLevelMap[i] = effectiveMonsterLevel(i)
|
|
end
|
|
|
|
data.weaponTypeInfo = {
|
|
["None"] = { oneHand = true, melee = true, flag = "Unarmed" },
|
|
["Bow"] = { oneHand = false, melee = false, flag = "Bow" },
|
|
["Claw"] = { oneHand = true, melee = true, flag = "Claw" },
|
|
["Dagger"] = { oneHand = true, melee = true, flag = "Dagger" },
|
|
["Staff"] = { oneHand = false, melee = true, flag = "Staff" },
|
|
["Wand"] = { oneHand = true, melee = false, flag = "Wand" },
|
|
["One Handed Axe"] = { oneHand = true, melee = true, flag = "Axe" },
|
|
["One Handed Mace"] = { oneHand = true, melee = true, flag = "Mace" },
|
|
["One Handed Sword"] = { oneHand = true, melee = true, flag = "Sword" },
|
|
["Sceptre"] = { oneHand = true, melee = true, flag = "Mace", label = "One Handed Mace" },
|
|
["Thrusting One Handed Sword"] = { oneHand = true, melee = true, flag = "Sword", label = "One Handed Sword" },
|
|
["Two Handed Axe"] = { oneHand = false, melee = true, flag = "Axe" },
|
|
["Two Handed Mace"] = { oneHand = false, melee = true, flag = "Mace" },
|
|
["Two Handed Sword"] = { oneHand = false, melee = true, flag = "Sword" },
|
|
}
|
|
data.unarmedWeaponData = {
|
|
[0] = { type = "None", AttackRate = 1.2, CritChance = 0, PhysicalMin = 2, PhysicalMax = 6 }, -- Scion
|
|
[1] = { type = "None", AttackRate = 1.2, CritChance = 0, PhysicalMin = 2, PhysicalMax = 8 }, -- Marauder
|
|
[2] = { type = "None", AttackRate = 1.2, CritChance = 0, PhysicalMin = 2, PhysicalMax = 5 }, -- Ranger
|
|
[3] = { type = "None", AttackRate = 1.2, CritChance = 0, PhysicalMin = 2, PhysicalMax = 5 }, -- Witch
|
|
[4] = { type = "None", AttackRate = 1.2, CritChance = 0, PhysicalMin = 2, PhysicalMax = 6 }, -- Duelist
|
|
[5] = { type = "None", AttackRate = 1.2, CritChance = 0, PhysicalMin = 2, PhysicalMax = 6 }, -- Templar
|
|
[6] = { type = "None", AttackRate = 1.2, CritChance = 0, PhysicalMin = 2, PhysicalMax = 5 }, -- Shadow
|
|
}
|
|
|
|
data.specialBaseTags = {
|
|
["Amulet"] = { shaper = "amulet_shaper", elder = "amulet_elder", adjudicator = "amulet_adjudicator", basilisk = "amulet_basilisk", crusader = "amulet_crusader", eyrie = "amulet_eyrie", },
|
|
["Ring"] = { shaper = "ring_shaper", elder = "ring_elder", adjudicator = "ring_adjudicator", basilisk = "ring_basilisk", crusader = "ring_crusader", eyrie = "ring_eyrie", },
|
|
["Claw"] = { shaper = "claw_shaper", elder = "claw_elder", adjudicator = "claw_adjudicator", basilisk = "claw_basilisk", crusader = "claw_crusader", eyrie = "claw_eyrie", },
|
|
["Dagger"] = { shaper = "dagger_shaper", elder = "dagger_elder", adjudicator = "dagger_adjudicator", basilisk = "dagger_basilisk", crusader = "dagger_crusader", eyrie = "dagger_eyrie", },
|
|
["Wand"] = { shaper = "wand_shaper", elder = "wand_elder", adjudicator = "wand_adjudicator", basilisk = "wand_basilisk", crusader = "wand_crusader", eyrie = "wand_eyrie", },
|
|
["One Handed Sword"] = { shaper = "sword_shaper", elder = "sword_elder", adjudicator = "sword_adjudicator", basilisk = "sword_basilisk", crusader = "sword_crusader", eyrie = "sword_eyrie", },
|
|
["Thrusting One Handed Sword"] = { shaper = "sword_shaper", elder = "sword_elder", adjudicator = "sword_adjudicator", basilisk = "sword_basilisk", crusader = "sword_crusader", eyrie = "sword_eyrie", },
|
|
["One Handed Axe"] = { shaper = "axe_shaper", elder = "axe_elder", adjudicator = "axe_adjudicator", basilisk = "axe_basilisk", crusader = "axe_crusader", eyrie = "axe_eyrie", },
|
|
["One Handed Mace"] = { shaper = "mace_shaper", elder = "mace_elder", adjudicator = "mace_adjudicator", basilisk = "mace_basilisk", crusader = "mace_crusader", eyrie = "mace_eyrie", },
|
|
["Bow"] = { shaper = "bow_shaper", elder = "bow_elder", adjudicator = "bow_adjudicator", basilisk = "bow_basilisk", crusader = "bow_crusader", eyrie = "bow_eyrie", },
|
|
["Staff"] = { shaper = "staff_shaper", elder = "staff_elder", adjudicator = "staff_adjudicator", basilisk = "staff_basilisk", crusader = "staff_crusader", eyrie = "staff_eyrie", },
|
|
["Two Handed Sword"] = { shaper = "2h_sword_shaper", elder = "2h_sword_elder", adjudicator = "2h_sword_adjudicator", basilisk = "2h_sword_basilisk", crusader = "2h_sword_crusader", eyrie = "2h_sword_eyrie", },
|
|
["Two Handed Axe"] = { shaper = "2h_axe_shaper", elder = "2h_axe_elder", adjudicator = "2h_axe_adjudicator", basilisk = "2h_axe_basilisk", crusader = "2h_axe_crusader", eyrie = "2h_axe_eyrie", },
|
|
["Two Handed Mace"] = { shaper = "2h_mace_shaper", elder = "2h_mace_elder", adjudicator = "2h_mace_adjudicator", basilisk = "2h_mace_basilisk", crusader = "2h_mace_crusader", eyrie = "2h_mace_eyrie", },
|
|
["Quiver"] = { shaper = "quiver_shaper", elder = "quiver_elder", adjudicator = "quiver_adjudicator", basilisk = "quiver_basilisk", crusader = "quiver_crusader", eyrie = "quiver_eyrie", },
|
|
["Belt"] = { shaper = "belt_shaper", elder = "belt_elder", adjudicator = "belt_adjudicator", basilisk = "belt_basilisk", crusader = "belt_crusader", eyrie = "belt_eyrie", },
|
|
["Gloves"] = { shaper = "gloves_shaper", elder = "gloves_elder", adjudicator = "gloves_adjudicator", basilisk = "gloves_basilisk", crusader = "gloves_crusader", eyrie = "gloves_eyrie", },
|
|
["Boots"] = { shaper = "boots_shaper", elder = "boots_elder", adjudicator = "boots_adjudicator", basilisk = "boots_basilisk", crusader = "boots_crusader", eyrie = "boots_eyrie", },
|
|
["Body Armour"] = { shaper = "body_armour_shaper", elder = "body_armour_elder", adjudicator = "body_armour_adjudicator", basilisk = "body_armour_basilisk", crusader = "body_armour_crusader", eyrie = "body_armour_eyrie", },
|
|
["Helmet"] = { shaper = "helmet_shaper", elder = "helmet_elder", adjudicator = "helmet_adjudicator", basilisk = "helmet_basilisk", crusader = "helmet_crusader", eyrie = "helmet_eyrie", },
|
|
["Shield"] = { shaper = "shield_shaper", elder = "shield_elder", adjudicator = "shield_adjudicator", basilisk = "shield_basilisk", crusader = "shield_crusader", eyrie = "shield_eyrie", },
|
|
["Sceptre"] = { shaper = "sceptre_shaper", elder = "sceptre_elder", adjudicator = "sceptre_adjudicator", basilisk = "sceptre_basilisk", crusader = "sceptre_crusader", eyrie = "sceptre_eyrie", },
|
|
}
|
|
|
|
---@type string[] @List of keystones that can be found on unique items.
|
|
data.keystones = {
|
|
"Acrobatics",
|
|
"Ancestral Bond",
|
|
"Arrow Dancing",
|
|
"Avatar of Fire",
|
|
"Blood Magic",
|
|
"Call to Arms",
|
|
"Conduit",
|
|
"Corrupted Soul",
|
|
"Crimson Dance",
|
|
"Eldritch Battery",
|
|
"Elemental Equilibrium",
|
|
"Elemental Overload",
|
|
"Eternal Youth",
|
|
"Ghost Reaver",
|
|
"Glancing Blows",
|
|
"Hollow Palm Technique",
|
|
"Imbalanced Guard",
|
|
"Immortal Ambition",
|
|
"Iron Grip",
|
|
"Iron Reflexes",
|
|
"Mind Over Matter",
|
|
"Minion Instability",
|
|
"Mortal Conviction",
|
|
"Pain Attunement",
|
|
"Perfect Agony",
|
|
"Phase Acrobatics",
|
|
"Point Blank",
|
|
"Resolute Technique",
|
|
"Runebinder",
|
|
"Supreme Ego",
|
|
"The Agnostic",
|
|
"The Impaler",
|
|
"Unwavering Stance",
|
|
"Vaal Pact",
|
|
"Wicked Ward",
|
|
"Wind Dancer",
|
|
"Zealot's Oath",
|
|
}
|
|
|
|
data.misc = { -- magic numbers
|
|
ServerTickRate = 30,
|
|
TemporalChainsEffectCap = 75,
|
|
DamageReductionCap = 90,
|
|
MaxResistCap = 90,
|
|
EvadeChanceCap = 95,
|
|
DodgeChanceCap = 75,
|
|
AvoidChanceCap = 75,
|
|
EnergyShieldRechargeBase = 0.2,
|
|
Transfiguration = 0.3,
|
|
EnemyMaxResist = 75,
|
|
LeechRateBase = 0.02,
|
|
BleedPercentBase = 70,
|
|
BleedDurationBase = 5,
|
|
PoisonPercentBase = 0.20,
|
|
PoisonDurationBase = 2,
|
|
IgnitePercentBase = 0.50,
|
|
IgniteDurationBase = 4,
|
|
ImpaleStoredDamageBase = 0.1,
|
|
BuffExpirationSlowCap = 0.25,
|
|
TrapTriggerRadiusBase = 10,
|
|
MineDetonationRadiusBase = 60,
|
|
MineAuraRadiusBase = 35,
|
|
PurposefulHarbingerMaxBuffPercent = 40,
|
|
}
|
|
|
|
-- Misc data tables
|
|
LoadModule("Data/Misc", data)
|
|
|
|
-- Stat descriptions
|
|
data.describeStats = LoadModule("Modules/StatDescriber")
|
|
|
|
-- Load item modifiers
|
|
data.itemMods = {
|
|
Item = LoadModule("Data/ModItem"),
|
|
Flask = LoadModule("Data/ModFlask"),
|
|
Jewel = LoadModule("Data/ModJewel"),
|
|
JewelAbyss = LoadModule("Data/ModJewelAbyss"),
|
|
JewelCluster = LoadModule("Data/ModJewelCluster"),
|
|
}
|
|
data.masterMods = LoadModule("Data/ModMaster")
|
|
data.enchantments = {
|
|
Helmet = LoadModule("Data/EnchantmentHelmet"),
|
|
Boots = LoadModule("Data/EnchantmentBoots"),
|
|
Gloves = LoadModule("Data/EnchantmentGloves"),
|
|
}
|
|
data.essences = LoadModule("Data/Essence")
|
|
data.pantheons = LoadModule("Data/Pantheons")
|
|
|
|
-- Cluster jewel data
|
|
data.clusterJewels = LoadModule("Data/ClusterJewels")
|
|
|
|
-- Create a quick lookup cache from cluster jewel skill to the notables which use that skill
|
|
---@type table<string, table<string>>
|
|
local clusterSkillToNotables = { }
|
|
for notableKey, notableInfo in pairs(data.itemMods.JewelCluster) do
|
|
-- Translate the notable key to its name
|
|
local notableName = notableInfo[1] and notableInfo[1]:match("1 Added Passive Skill is (.*)")
|
|
if notableName then
|
|
for weightIndex, clusterSkill in pairs(notableInfo.weightKey) do
|
|
if notableInfo.weightVal[weightIndex] > 0 then
|
|
if not clusterSkillToNotables[clusterSkill] then
|
|
clusterSkillToNotables[clusterSkill] = { }
|
|
end
|
|
table.insert(clusterSkillToNotables[clusterSkill], notableName)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Create easy lookup from cluster node name -> cluster jewel size and types
|
|
data.clusterJewelInfoForNotable = { }
|
|
for size, jewel in pairs(data.clusterJewels.jewels) do
|
|
for skill, skillInfo in pairs(jewel.skills) do
|
|
local notables = clusterSkillToNotables[skill]
|
|
if notables then
|
|
for _, notableKey in ipairs(notables) do
|
|
if not data.clusterJewelInfoForNotable[notableKey] then
|
|
data.clusterJewelInfoForNotable[notableKey] = { }
|
|
data.clusterJewelInfoForNotable[notableKey].jewelTypes = { }
|
|
data.clusterJewelInfoForNotable[notableKey].size = { }
|
|
end
|
|
local curJewelInfo = data.clusterJewelInfoForNotable[notableKey]
|
|
curJewelInfo.size[size] = true
|
|
table.insert(curJewelInfo.jewelTypes, skill)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Load skills
|
|
data.skills = { }
|
|
data.skillStatMap = LoadModule("Data/SkillStatMap", makeSkillMod, makeFlagMod, makeSkillDataMod)
|
|
data.skillStatMapMeta = {
|
|
__index = function(t, key)
|
|
local map = data.skillStatMap[key]
|
|
if map then
|
|
map = copyTable(map)
|
|
t[key] = map
|
|
for _, mod in ipairs(map) do
|
|
processMod(t._grantedEffect, mod)
|
|
end
|
|
return map
|
|
end
|
|
end
|
|
}
|
|
for _, type in pairs(skillTypes) do
|
|
LoadModule("Data/Skills/"..type, data.skills, makeSkillMod, makeFlagMod, makeSkillDataMod)
|
|
end
|
|
for skillId, grantedEffect in pairs(data.skills) do
|
|
grantedEffect.id = skillId
|
|
grantedEffect.modSource = "Skill:"..skillId
|
|
-- Add sources for skill mods, and check for global effects
|
|
for _, list in pairs({grantedEffect.baseMods, grantedEffect.qualityMods, grantedEffect.levelMods}) do
|
|
for _, mod in pairs(list) do
|
|
if mod.name then
|
|
processMod(grantedEffect, mod)
|
|
else
|
|
for _, mod in ipairs(mod) do
|
|
processMod(grantedEffect, mod)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- Install stat map metatable
|
|
grantedEffect.statMap = grantedEffect.statMap or { }
|
|
setmetatable(grantedEffect.statMap, data.skillStatMapMeta)
|
|
grantedEffect.statMap._grantedEffect = grantedEffect
|
|
for _, map in pairs(grantedEffect.statMap) do
|
|
for _, mod in ipairs(map) do
|
|
processMod(grantedEffect, mod)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Load gems
|
|
data.gems = LoadModule("Data/Gems")
|
|
data.gemForSkill = { }
|
|
data.gemForBaseName = { }
|
|
for gemId, gem in pairs(data.gems) do
|
|
gem.id = gemId
|
|
gem.grantedEffect = data.skills[gem.grantedEffectId]
|
|
data.gemForSkill[gem.grantedEffect] = gemId
|
|
data.gemForBaseName[gem.name .. (gem.grantedEffect.support and " Support" or "")] = gemId
|
|
gem.secondaryGrantedEffect = gem.secondaryGrantedEffectId and data.skills[gem.secondaryGrantedEffectId]
|
|
gem.grantedEffectList = {
|
|
gem.grantedEffect,
|
|
gem.secondaryGrantedEffect
|
|
}
|
|
gem.defaultLevel = gem.defaultLevel or (#gem.grantedEffect.levels > 20 and #gem.grantedEffect.levels - 20) or (gem.grantedEffect.levels[3][1] and 3) or 1
|
|
end
|
|
|
|
-- Load minions
|
|
data.minions = { }
|
|
LoadModule("Data/Minions", data.minions, makeSkillMod)
|
|
data.spectres = { }
|
|
LoadModule("Data/Spectres", data.spectres, makeSkillMod)
|
|
for name, spectre in pairs(data.spectres) do
|
|
spectre.limit = "ActiveSpectreLimit"
|
|
data.minions[name] = spectre
|
|
end
|
|
local missing = { }
|
|
for _, minion in pairs(data.minions) do
|
|
for _, skillId in ipairs(minion.skillList) do
|
|
if launch.devMode and not data.skills[skillId] and not missing[skillId] then
|
|
ConPrintf("'%s' missing skill '%s'", minion.name, skillId)
|
|
missing[skillId] = true
|
|
end
|
|
end
|
|
for _, mod in ipairs(minion.modList) do
|
|
mod.source = "Minion:"..minion.name
|
|
end
|
|
end
|
|
|
|
-- Item bases
|
|
data.itemBases = { }
|
|
for _, type in pairs(itemTypes) do
|
|
LoadModule("Data/Bases/"..type, data.itemBases)
|
|
end
|
|
|
|
-- Build lists of item bases, separated by type
|
|
data.itemBaseLists = { }
|
|
for name, base in pairs(data.itemBases) do
|
|
if not base.hidden then
|
|
local type = base.type
|
|
if base.subType then
|
|
type = type .. ": " .. base.subType
|
|
end
|
|
data.itemBaseLists[type] = data.itemBaseLists[type] or { }
|
|
table.insert(data.itemBaseLists[type], { label = name:gsub(" %(.+%)",""), name = name, base = base })
|
|
end
|
|
end
|
|
data.itemBaseTypeList = { }
|
|
for type, list in pairs(data.itemBaseLists) do
|
|
table.insert(data.itemBaseTypeList, type)
|
|
table.sort(list, function(a, b)
|
|
if a.base.req and b.base.req then
|
|
if a.base.req.level == b.base.req.level then
|
|
return a.name < b.name
|
|
else
|
|
return (a.base.req.level or 1) > (b.base.req.level or 1)
|
|
end
|
|
elseif a.base.req and not b.base.req then
|
|
return true
|
|
elseif b.base.req and not a.base.req then
|
|
return false
|
|
else
|
|
return a.name < b.name
|
|
end
|
|
end)
|
|
end
|
|
table.sort(data.itemBaseTypeList)
|
|
|
|
-- Rare templates
|
|
data.rares = LoadModule("Data/Rares")
|
|
|
|
-- Uniques (loaded after version-specific data because reasons)
|
|
data.uniques = { }
|
|
for _, type in pairs(itemTypes) do
|
|
data.uniques[type] = LoadModule("Data/Uniques/"..type)
|
|
end
|
|
LoadModule("Data/Generated")
|
|
LoadModule("Data/New")
|