Release 1.2.41
- Show save prompt before updating - Add options for Enemy is Blinded, Dealt Non-Crit Recently, Ignited/Frozen an Enemy Recently - Reworked node stat difference to avoid issue with certain radius jewels
This commit is contained in:
@@ -31,7 +31,7 @@ function buildMode:Init(dbFileName, buildName)
|
||||
self.anchorTopBarLeft = common.New("Control", nil, 4, 4, 0, 20)
|
||||
self.controls.back = common.New("ButtonControl", {"LEFT",self.anchorTopBarLeft,"RIGHT"}, 0, 0, 60, 20, "<< Back", function()
|
||||
if self.unsaved then
|
||||
self:OpenSavePopup(false)
|
||||
self:OpenSavePopup("LIST")
|
||||
else
|
||||
main:SetMode("LIST", self.dbFileName and self.buildName)
|
||||
end
|
||||
@@ -352,11 +352,11 @@ function buildMode:Init(dbFileName, buildName)
|
||||
self.abortSave = false
|
||||
end
|
||||
|
||||
function buildMode:CanExit()
|
||||
function buildMode:CanExit(mode)
|
||||
if not self.unsaved then
|
||||
return true
|
||||
end
|
||||
self:OpenSavePopup(true)
|
||||
self:OpenSavePopup(mode)
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -408,7 +408,7 @@ function buildMode:OnFrame(inputEvents)
|
||||
inputEvents[id] = nil
|
||||
elseif event.key == "w" then
|
||||
if self.unsaved then
|
||||
self:OpenSavePopup(false)
|
||||
self:OpenSavePopup("LIST")
|
||||
else
|
||||
main:SetMode("LIST", self.dbFileName and self.buildName)
|
||||
end
|
||||
@@ -526,20 +526,27 @@ function buildMode:OnFrame(inputEvents)
|
||||
self:DrawControls(main.viewPort)
|
||||
end
|
||||
|
||||
function buildMode:OpenSavePopup(exit)
|
||||
main:OpenPopup(280, 100, "Save Changes", {
|
||||
common.New("LabelControl", nil, 0, 20, 0, 16, "^7This build has unsaved changes.\nDo you want to save them "..(exit and "before exiting?" or "now?")),
|
||||
function buildMode:OpenSavePopup(mode)
|
||||
local modeDesc = {
|
||||
["LIST"] = "now?",
|
||||
["EXIT"] = "before exiting?",
|
||||
["UPDATE"] = "before updating?",
|
||||
}
|
||||
main:OpenPopup(290, 100, "Save Changes", {
|
||||
common.New("LabelControl", nil, 0, 20, 0, 16, "^7This build has unsaved changes.\nDo you want to save them "..modeDesc[mode]),
|
||||
common.New("ButtonControl", nil, -90, 70, 80, 20, "Save", function()
|
||||
main:ClosePopup()
|
||||
self.actionOnSave = exit and "EXIT" or "LIST"
|
||||
self.actionOnSave = mode
|
||||
self:SaveDBFile()
|
||||
end),
|
||||
common.New("ButtonControl", nil, 0, 70, 80, 20, "Don't Save", function()
|
||||
main:ClosePopup()
|
||||
if exit then
|
||||
Exit()
|
||||
else
|
||||
if mode == "LIST" then
|
||||
main:SetMode("LIST", self.dbFileName and self.buildName)
|
||||
elseif mode == "EXIT" then
|
||||
Exit()
|
||||
elseif mode == "UPDATE" then
|
||||
launch:ApplyUpdate(launch.updateAvailable)
|
||||
end
|
||||
end),
|
||||
common.New("ButtonControl", nil, 90, 70, 80, 20, "Cancel", function()
|
||||
@@ -702,9 +709,11 @@ function buildMode:SaveDBFile()
|
||||
file:write(xmlText)
|
||||
file:close()
|
||||
if self.actionOnSave == "LIST" then
|
||||
main:SetMode("LIST", self.buildName)
|
||||
main:SetMode("LIST", self.dbFileName and self.buildName)
|
||||
elseif self.actionOnSave == "EXIT" then
|
||||
Exit()
|
||||
elseif self.actionOnSave == "UPDATE" then
|
||||
launch:ApplyUpdate(launch.updateAvailable)
|
||||
end
|
||||
self.actionOnSave = nil
|
||||
end
|
||||
|
||||
@@ -633,6 +633,7 @@ local function initEnv(build, mode)
|
||||
modDB:NewMod("BlockChance", "BASE", 15, "Base", { type = "Condition", var = "DualWielding" })
|
||||
modDB:NewMod("LifeRegenPercent", "BASE", 4, "Base", { type = "Condition", var = "OnConsecratedGround" })
|
||||
modDB:NewMod("Misc", "LIST", { type = "EnemyModifier", mod = modLib.createMod("DamageTaken", "INC", 50, "Shock") }, "Base", { type = "Condition", var = "EnemyShocked" })
|
||||
modDB:NewMod("Misc", "LIST", { type = "EnemyModifier", mod = modLib.createMod("HitChance", "MORE", -50, "Blind") }, "Base", { type = "Condition", var = "EnemyBlinded" })
|
||||
|
||||
-- Add bandit mods
|
||||
if build.banditNormal == "Alira" then
|
||||
@@ -678,32 +679,52 @@ local function initEnv(build, mode)
|
||||
end
|
||||
|
||||
-- This function:
|
||||
-- 1. Merges modifiers for all items, optionally replacing one item
|
||||
-- 1. Merges modifiers for all items
|
||||
-- 2. Builds a list of jewels with radius functions
|
||||
-- 3. Merges modifiers for all allocated passive nodes
|
||||
-- 4. Builds a list of active skills and their supports
|
||||
-- 5. Builds modifier lists for all active skills
|
||||
local function mergeMainMods(env, repSlotName, repItem)
|
||||
local function mergeMainMods(env, override)
|
||||
local build = env.build
|
||||
override = override or { }
|
||||
|
||||
-- Build list of passive nodes
|
||||
local nodes
|
||||
if override.addNodes or override.removeNodes then
|
||||
nodes = { }
|
||||
if override.addNodes then
|
||||
for node in pairs(override.addNodes) do
|
||||
nodes[node.id] = node
|
||||
end
|
||||
end
|
||||
for _, node in pairs(build.spec.allocNodes) do
|
||||
if not override.removeNodes or not override.removeNodes[node] then
|
||||
nodes[node.id] = node
|
||||
end
|
||||
end
|
||||
else
|
||||
nodes = build.spec.allocNodes
|
||||
end
|
||||
|
||||
-- Build and merge item modifiers, and create list of radius jewels
|
||||
env.radiusJewelList = wipeTable(env.radiusJewelList)
|
||||
env.itemList = { }
|
||||
env.flasks = { }
|
||||
env.modDB.conditions["UsingAllCorruptedItems"] = true
|
||||
for slotName, slot in pairs(build.itemsTab.slots) do
|
||||
local item
|
||||
if slotName == repSlotName then
|
||||
item = repItem
|
||||
if slotName == override.repSlotName then
|
||||
item = override.repItem
|
||||
else
|
||||
item = build.itemsTab.list[slot.selItemId]
|
||||
end
|
||||
if slot.nodeId then
|
||||
-- Slot is a jewel socket, check if socket is allocated
|
||||
if not build.spec.allocNodes[slot.nodeId] then
|
||||
if not nodes[slot.nodeId] then
|
||||
item = nil
|
||||
elseif item and item.jewelRadiusIndex then
|
||||
-- Jewel has a radius, add it to the list
|
||||
local funcList = item.jewelFunc or { function(nodeMods, out, data)
|
||||
local funcList = item.jewelFuncList or { function(nodeMods, out, data)
|
||||
-- Default function just tallies all stats in radius
|
||||
if nodeMods then
|
||||
for _, stat in pairs({"Str","Dex","Int"}) do
|
||||
@@ -727,12 +748,10 @@ local function mergeMainMods(env, repSlotName, repItem)
|
||||
end
|
||||
end
|
||||
if item and item.type == "Flask" then
|
||||
if env.configInput["enableFlask"..slot.slotNum] then
|
||||
-- FIXME dunno lol
|
||||
env.modDB.conditions["UsingFlask"] = true
|
||||
else
|
||||
item = nil
|
||||
if slot.active then
|
||||
env.flasks[item] = true
|
||||
end
|
||||
item = nil
|
||||
end
|
||||
env.itemList[slotName] = item
|
||||
if item then
|
||||
@@ -760,6 +779,14 @@ local function mergeMainMods(env, repSlotName, repItem)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if override.toggleFlask then
|
||||
if env.flasks[override.toggleFlask] then
|
||||
env.flasks[override.toggleFlask] = nil
|
||||
else
|
||||
env.flasks[override.toggleFlask] = true
|
||||
end
|
||||
end
|
||||
|
||||
if env.mode == "MAIN" then
|
||||
-- Process extra skills granted by items
|
||||
@@ -844,7 +871,7 @@ local function mergeMainMods(env, repSlotName, repItem)
|
||||
end
|
||||
|
||||
-- Build and merge modifiers for allocated passives
|
||||
env.modDB:AddList(buildNodeModList(env, build.spec.allocNodes, true))
|
||||
env.modDB:AddList(buildNodeModList(env, nodes, true))
|
||||
|
||||
-- Determine main skill group
|
||||
if env.mode == "CALCS" then
|
||||
@@ -1015,6 +1042,15 @@ local function performCalcs(env)
|
||||
end
|
||||
end
|
||||
|
||||
-- Merge flask modifiers
|
||||
if env.mode_combat then
|
||||
local effectInc = modDB:Sum("INC", nil, "FlaskEffect")
|
||||
for item in pairs(env.flasks) do
|
||||
modDB.conditions["UsingFlask"] = true
|
||||
modDB:ScaleAddList(item.modList, 1 + (effectInc + item.flaskData.effectInc) / 100)
|
||||
end
|
||||
end
|
||||
|
||||
-- Set conditions
|
||||
local condList = modDB.conditions
|
||||
if env.weaponData1.type == "Staff" then
|
||||
@@ -1538,7 +1574,7 @@ local function performCalcs(env)
|
||||
output.EvadeChance = 0
|
||||
else
|
||||
local enemyAccuracy = round(calcVal(enemyDB, "Accuracy"))
|
||||
output.EvadeChance = 100 - calcHitChance(output.Evasion, enemyAccuracy)
|
||||
output.EvadeChance = 100 - calcHitChance(output.Evasion, enemyAccuracy) * calcMod(enemyDB, nil, "HitChance")
|
||||
if breakdown then
|
||||
breakdown.EvadeChance = {
|
||||
s_format("Enemy level: %d ^8(%s the Configuration tab)", env.enemyLevel, env.configInput.enemyLevel and "overridden from" or "can be overridden in"),
|
||||
@@ -2894,11 +2930,12 @@ end
|
||||
|
||||
local calcs = { }
|
||||
|
||||
-- Get calculator for tree node modifiers
|
||||
-- Get fast calculator for adding tree node modifiers
|
||||
function calcs.getNodeCalculator(build)
|
||||
return getCalculator(build, true, function(env, nodeList, remove)
|
||||
-- Build and merge/unmerge modifiers for these nodes
|
||||
local nodeModList = buildNodeModList(env, nodeList)
|
||||
return getCalculator(build, true, function(env, nodeList)
|
||||
-- Build and merge modifiers for these nodes
|
||||
env.modDB:AddList(buildNodeModList(env, nodeList))
|
||||
--[[local nodeModList = buildNodeModList(env, nodeList)
|
||||
if remove then
|
||||
for _, mod in ipairs(nodeModList) do
|
||||
if mod.type == "LIST" or mod.type == "FLAG" then
|
||||
@@ -2916,15 +2953,14 @@ function calcs.getNodeCalculator(build)
|
||||
end
|
||||
else
|
||||
env.modDB:AddList(nodeModList)
|
||||
end
|
||||
end]]
|
||||
end)
|
||||
end
|
||||
|
||||
-- Get calculator for item modifiers
|
||||
function calcs.getItemCalculator(build)
|
||||
return getCalculator(build, false, function(env, repSlotName, repItem)
|
||||
-- Merge main mods, replacing the item in the given slot with the given item
|
||||
mergeMainMods(env, repSlotName, repItem)
|
||||
-- Get calculator for other changes (adding/removing nodes, items, gems, etc)
|
||||
function calcs.getMiscCalculator(build)
|
||||
return getCalculator(build, false, function(env, override)
|
||||
mergeMainMods(env, override)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -450,45 +450,41 @@ function itemLib.buildItemModListForSlotNum(item, baseList, slotNum)
|
||||
local durationInc = sumLocal(modList, "Duration", "INC", 0)
|
||||
if item.base.flask.life or item.base.flask.mana then
|
||||
-- Recovery flask
|
||||
flaskData.instantPerc = sumLocal(modList, "FlaskInstantRecovery", "BASE", 0)
|
||||
local recoveryMod = 1 + sumLocal(modList, "FlaskRecovery", "INC", 0) / 100
|
||||
local rateMod = 1 + sumLocal(modList, "FlaskRecoveryRate", "INC", 0) / 100
|
||||
local instant = sumLocal(modList, "FlaskInstantRecovery", "BASE", 0)
|
||||
local durBase = item.base.flask.duration * (1 + durationInc / 100)
|
||||
flaskData.duration = item.base.flask.duration * (1 + durationInc / 100) / rateMod
|
||||
if item.base.flask.life then
|
||||
local base = item.base.flask.life * (1 + item.quality / 100) * recoveryMod
|
||||
local inst = base * instant / 100
|
||||
local grad = base * (1 - instant / 100) * (1 + durationInc / 100)
|
||||
flaskData.lifeTotal = inst + grad
|
||||
flaskData.lifeDuration = durBase / rateMod
|
||||
flaskData.lifeBase = item.base.flask.life * (1 + item.quality / 100) * recoveryMod
|
||||
flaskData.lifeInstant = flaskData.lifeBase * flaskData.instantPerc / 100
|
||||
flaskData.lifeGradual = flaskData.lifeBase * (1 - flaskData.instantPerc / 100) * (1 + durationInc / 100)
|
||||
flaskData.lifeTotal = flaskData.lifeInstant + flaskData.lifeGradual
|
||||
end
|
||||
if item.base.flask.mana then
|
||||
local base = item.base.flask.mana * (1 + item.quality / 100) * recoveryMod
|
||||
local inst = base * instant / 100
|
||||
local grad = base * (1 - instant / 100) * (1 + durationInc / 100)
|
||||
flaskData.manaTotal = inst + grad
|
||||
flaskData.manaDuration = durBase / rateMod
|
||||
flaskData.manaBase = item.base.flask.mana * (1 + item.quality / 100) * recoveryMod
|
||||
flaskData.manaInstant = flaskData.manaBase * flaskData.instantPerc / 100
|
||||
flaskData.manaGradual = flaskData.manaBase * (1 - flaskData.instantPerc / 100) * (1 + durationInc / 100)
|
||||
flaskData.manaTotal = flaskData.manaInstant + flaskData.manaGradual
|
||||
end
|
||||
else
|
||||
-- Utility flask
|
||||
flaskData.duration = round(item.base.flask.duration * (1 + (durationInc + item.quality) / 100), 1)
|
||||
flaskData.duration = item.base.flask.duration * (1 + (durationInc + item.quality) / 100)
|
||||
end
|
||||
local extra = sumLocal(modList, "FlaskCharges", "BASE", 0)
|
||||
local usedInc = sumLocal(modList, "FlaskChargesUsed", "INC", 0)
|
||||
local gainedInc = sumLocal(modList, "FlaskChargeRecovery", "INC", 0)
|
||||
flaskData.chargesMax = item.base.flask.chargesMax + extra
|
||||
flaskData.chargesUsed = m_floor(item.base.flask.chargesUsed * (1 + usedInc / 100))
|
||||
flaskData.gainMod = 1 + gainedInc / 100
|
||||
flaskData.chargesMax = item.base.flask.chargesMax + sumLocal(modList, "FlaskCharges", "BASE", 0)
|
||||
flaskData.chargesUsed = m_floor(item.base.flask.chargesUsed * (1 + sumLocal(modList, "FlaskChargesUsed", "INC", 0) / 100))
|
||||
flaskData.gainMod = 1 + sumLocal(modList, "FlaskChargeRecovery", "INC", 0) / 100
|
||||
flaskData.effectInc = sumLocal(modList, "FlaskEffect", "INC", 0)
|
||||
for _, value in ipairs(modList:Sum("LIST", nil, "Misc")) do
|
||||
if value.type == "FlaskData" then
|
||||
flaskData[value.key] = value.value
|
||||
end
|
||||
end
|
||||
elseif item.type == "Jewel" then
|
||||
item.jewelFunc = nil
|
||||
item.jewelFuncList = nil
|
||||
for _, value in ipairs(modList:Sum("LIST", nil, "Misc")) do
|
||||
if value.type == "JewelFunc" then
|
||||
item.jewelFunc = item.jewelFunc or { }
|
||||
t_insert(item.jewelFunc, value.func)
|
||||
item.jewelFuncList = item.jewelFuncList or { }
|
||||
t_insert(item.jewelFuncList, value.func)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -126,7 +126,10 @@ function main:Init()
|
||||
self:OpenPopup(800, 250, "Update Available", {
|
||||
common.New("TextListControl", nil, 0, 20, 780, 190, nil, changeList),
|
||||
common.New("ButtonControl", nil, -45, 220, 80, 20, "Update", function()
|
||||
launch:ApplyUpdate(launch.updateAvailable)
|
||||
local ret = self:CallMode("CanExit", "UPDATE")
|
||||
if ret == nil or ret == true then
|
||||
launch:ApplyUpdate(launch.updateAvailable)
|
||||
end
|
||||
main:ClosePopup()
|
||||
end),
|
||||
common.New("ButtonControl", nil, 45, 220, 80, 20, "Cancel", function()
|
||||
@@ -204,7 +207,7 @@ function main:Init()
|
||||
end
|
||||
|
||||
function main:CanExit()
|
||||
local ret = self:CallMode("CanExit")
|
||||
local ret = self:CallMode("CanExit", "EXIT")
|
||||
if ret ~= nil then
|
||||
return ret
|
||||
else
|
||||
|
||||
@@ -111,6 +111,7 @@ local modNameList = {
|
||||
-- Stun modifiers
|
||||
["stun recovery"] = "StunRecovery",
|
||||
["stun and block recovery"] = "StunRecovery",
|
||||
["block and stun recovery"] = "StunRecovery",
|
||||
["stun threshold"] = "StunThreshold",
|
||||
["block recovery"] = "BlockRecovery",
|
||||
["enemy stun threshold"] = "EnemyStunThreshold",
|
||||
@@ -236,6 +237,8 @@ local modNameList = {
|
||||
["effect"] = "FlaskEffect",
|
||||
["effect of flasks"] = "FlaskEffect",
|
||||
["amount recovered"] = "FlaskRecovery",
|
||||
["life recovered"] = "FlaskRecovery",
|
||||
["mana recovered"] = "FlaskRecovery",
|
||||
["life recovery from flasks"] = "FlaskLifeRecovery",
|
||||
["mana recovery from flasks"] = "FlaskManaRecovery",
|
||||
["flask effect duration"] = "FlaskDuration",
|
||||
@@ -397,10 +400,13 @@ local modTagList = {
|
||||
["if you've crit recently"] = { tag = { type = "Condition", var = "CritRecently" } },
|
||||
["if you've dealt a critical strike recently"] = { tag = { type = "Condition", var = "CritRecently" } },
|
||||
["if you haven't crit recently"] = { tag = { type = "Condition", var = "CritRecently", neg = true } },
|
||||
["if you've dealt a non%-critical strike recently"] = { tag = { type = "Condition", var = "NonCritRecently" } },
|
||||
["if you've killed recently"] = { tag = { type = "Condition", var = "KilledRecently" } },
|
||||
["if you haven't killed recently"] = { tag = { type = "Condition", var = "KilledRecently", neg = true } },
|
||||
["if you or your totems have killed recently"] = { tag = { type = "Condition", varList = {"KilledRecently","TotemsKilledRecently"} } },
|
||||
["if you've killed a maimed enemy recently"] = { tagList = { { type = "Condition", var = "KilledRecently" }, { type = "Condition", var = "EnemyMaimed" } } },
|
||||
["if you've frozen an enemy recently"] = { tag = { type = "Condition", var = "FrozenEnemyRecently" } },
|
||||
["if you've ignited an enemy recently"] = { tag = { type = "Condition", var = "IgnitedEnemyRecently" } },
|
||||
["if you've been hit recently"] = { tag = { type = "Condition", var = "BeenHitRecently" } },
|
||||
["if you were hit recently"] = { tag = { type = "Condition", var = "BeenHitRecently" } },
|
||||
["if you were damaged by a hit recently"] = { tag = { type = "Condition", var = "BeenHitRecently" } },
|
||||
@@ -428,6 +434,7 @@ local modTagList = {
|
||||
["against bleeding enemies"] = { tag = { type = "Condition", var = "EnemyBleeding" }, flags = ModFlag.Hit },
|
||||
["against poisoned enemies"] = { tag = { type = "Condition", var = "EnemyPoisoned" }, flags = ModFlag.Hit },
|
||||
["against hindered enemies"] = { tag = { type = "Condition", var = "EnemyHindered" }, flags = ModFlag.Hit },
|
||||
["against blinded enemies"] = { tag = { type = "Condition", var = "EnemyBlinded" }, flags = ModFlag.Hit },
|
||||
["against burning enemies"] = { tag = { type = "Condition", var = "EnemyBurning" }, flags = ModFlag.Hit },
|
||||
["against ignited enemies"] = { tag = { type = "Condition", var = "EnemyIgnited" }, flags = ModFlag.Hit },
|
||||
["against shocked enemies"] = { tag = { type = "Condition", var = "EnemyShocked" }, flags = ModFlag.Hit },
|
||||
@@ -541,6 +548,9 @@ local specialModList = {
|
||||
["your critical strike chance is lucky"] = { flag("CritChanceLucky") },
|
||||
["phasing"] = { mod("Misc", "LIST", { type = "Condition", var = "Phasing" }) },
|
||||
["onslaught"] = { mod("Misc", "LIST", { type = "Condition", var = "Onslaught" }) },
|
||||
["creates a smoke cloud on use"] = { },
|
||||
["creates chilled ground on use"] = { },
|
||||
["creates consecrated ground on use"] = { },
|
||||
-- Special item local modifiers
|
||||
["no physical damage"] = { mod("Misc", "LIST", { type = "WeaponData", key = "PhysicalMin" }), mod("Misc", "LIST", { type = "WeaponData", key = "PhysicalMax" }), mod("Misc", "LIST", { type = "WeaponData", key = "PhysicalDPS" }) },
|
||||
["all attacks with this weapon are critical strikes"] = { mod("Misc", "LIST", { type = "WeaponData", key = "critChance", value = 100 }) },
|
||||
@@ -622,6 +632,7 @@ local specialModList = {
|
||||
["non%-critical strikes deal (%d+)%% damage"] = function(num) return { mod("Damage", "MORE", -100+num, nil, ModFlag.Hit, { type = "Condition", var = "CriticalStrike", neg = true }) } end,
|
||||
["ignited enemies burn (%d+)%% faster"] = function(num) return { mod("IgniteBurnRate", "INC", num) } end,
|
||||
["enemies ignited by an attack burn (%d+)%% faster"] = function(num) return { mod("IgniteBurnRate", "INC", num, nil, ModFlag.Attack) } end,
|
||||
["gain unholy might during flask effect"] = { mod("Misc", "LIST", { type = "Condition", var = "UnholyMight" }, { type = "Condition", var = "UsingFlask" }) },
|
||||
}
|
||||
local keystoneList = {
|
||||
-- List of keystones that can be found on uniques
|
||||
|
||||
Reference in New Issue
Block a user