Files
PathOfBuilding/Classes/ConfigTab.lua
Openarl d79b6b6ca3 Release 1.2.18
- Added jewel templates
- Added Tulfall
- Creating a new build opens an unnamed build instead of prompting for a build name
- Support for EE
2016-11-29 21:18:03 +10:00

370 lines
19 KiB
Lua

-- Path of Building
--
-- Module: Config Tab
-- Configuration tab for the current build.
--
local launch, main = ...
local t_insert = table.insert
local m_max = math.max
local varList = {
{ section = "General" },
{ var = "enemyLevel", type = "number", label = "Enemy Level:", tooltip = "This overrides the default enemy level used to estimate your hit and evade chances.\nThe default level is your character level, capped at 84, which is the same value\nused in-game to calculate the stats on the character sheet." },
{ var = "conditionLowLife", type = "check", label = "Are you always on Low Life?", tooltip = "You will automatically be considered to be on Low Life if you have at least 65% life reserved,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "LowLife" }, "Config")
end },
{ var = "conditionFullLife", type = "check", label = "Are you always on Full Life?", tooltip = "You will automatically be considered to be on Full Life if you have Chaos Innoculation,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "FullLife" }, "Config")
end },
{ section = "When In Combat" },
{ var = "usePowerCharges", type = "check", label = "Do you use Power Charges?" },
{ var = "useFrenzyCharges", type = "check", label = "Do you use Frenzy Charges?" },
{ var = "useEnduranceCharges", type = "check", label = "Do you use Endurance Charges?" },
{ var = "buffOnslaught", type = "check", label = "Do you have Onslaught?", tooltip = "In addition to allowing any 'while you have Onslaught' modifiers to apply,\nthis will enable the Onslaught buff itself. (20% increased Attack/Cast/Movement Speed)", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "Onslaught" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "buffUnholyMight", type = "check", label = "Do you have Unholy Might?", tooltip = "This will enable the Unholy Might buff. (Gain 30% of Physical Damage as Extra Chaos Damage)", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "UnholyMight" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "buffPhasing", type = "check", label = "Do you have Phasing?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "Phasing" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "buffFortify", type = "check", label = "Do you have Fortify?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "Fortify" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionUsingFlask", type = "check", label = "Do you have a Flask active?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "UsingFlask" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionOnConsecratedGround", type = "check", label = "Are you on Consecrated Ground?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "OnConsecratedGround" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionHitRecently", type = "check", label = "Have you Hit Recently?", tooltip = "You will automatically be considered to have Hit Recently if your main skill is self-cast,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "HitRecently" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionCritRecently", type = "check", label = "Have you Crit Recently?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "CritRecently" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionKilledRecently", type = "check", label = "Have you Killed Recently?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "KilledRecently" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionTotemsKilledRecently", type = "check", label = "Have your Totems Killed Recently?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "TotemsKilledRecently" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionBeenHitRecently", type = "check", label = "Have you been Hit Recently?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "BeenHitRecently" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "buffPendulum", type = "check", label = "Is Pendulum of Destruction active?", ifNode = 57197, apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "PendulumOfDestruction" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionAttackedRecently", type = "check", label = "Have you Attacked Recently?", ifNode = 3154, tooltip = "You will automatically be considered to have Attacked Recently if your main skill is an attack,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "AttackedRecently" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionCastSpellRecently", type = "check", label = "Have you Cast a Spell Recently?", ifNode = 3154, tooltip = "You will automatically be considered to have Cast a Spell Recently if your main skill is a spell,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "CastSpellRecently" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionUsedFireSkillInPast10Sec", type = "check", label = "Used a Fire Skill in the past 10s?", ifNode = 61259, apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "UsedFireSkillInPast10Sec" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionUsedColdSkillInPast10Sec", type = "check", label = "Used a Cold Skill in the past 10s?", ifNode = 61259, apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "UsedColdSkillInPast10Sec" }, "Config", { type = "Condition", var = "Combat" })
end },
{ var = "conditionUsedLightningSkillInPast10Sec", type = "check", label = "Used a Light. Skill in the past 10s?", ifNode = 61259, apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "UsedLightningSkillInPast10Sec" }, "Config", { type = "Condition", var = "Combat" })
end },
{ section = "For Effective DPS" },
{ var = "conditionEnemyFullLife", type = "check", label = "Is the enemy on Full Life?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyFullLife" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyLowLife", type = "check", label = "Is the enemy on Low Life?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyLowLife" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyCursed", type = "check", label = "Is the enemy Cursed?", tooltip = "Your enemy will automatically be considered to be Cursed if you have at least one curse enabled,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyCursed" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyBleeding", type = "check", label = "Is the enemy Bleeding?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyBleeding" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyPoisoned", type = "check", label = "Is the enemy Poisoned?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyPoisoned" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyMaimed", type = "check", label = "Is the enemy Maimed?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyMaimed" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyBurning", type = "check", label = "Is the enemy Burning?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyBurning" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyIgnited", type = "check", label = "Is the enemy Ignited?", tooltip = "This also implies that the enemy is Burning.", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyIgnited" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyChilled", type = "check", label = "Is the enemy Chilled?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyChilled" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyFrozen", type = "check", label = "Is the enemy Frozen?", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyFrozen" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "conditionEnemyShocked", type = "check", label = "Is the enemy Shocked?", tooltip = "In addition to allowing any 'against Shocked Enemies' modifiers to apply,\nthis will apply Shock's Damage Taken modifier to the enemy.", apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "Condition", var = "EnemyShocked" }, "Config", { type = "Condition", var = "Effective" })
end },
{ var = "enemyIsBoss", type = "check", label = "Is the enemy a Boss?", tooltip = "This adds the following modifiers:\n60% less Effect of your Curses\n+30% to enemy Elemental Resistances\n+15% to enemy Chaos Resistance", apply = function(val, modList, enemyModList)
enemyModList:NewMod("CurseEffect", "MORE", -60, "Boss")
enemyModList:NewMod("ElementalResist", "BASE", 30, "Boss")
enemyModList:NewMod("ChaosResist", "BASE", 15, "Boss")
end },
{ var = "enemyPhysicalReduction", type = "number", label = "Enemy Phys. Damage Reduction:", apply = function(val, modList, enemyModList)
enemyModList:NewMod("PhysicalDamageReduction", "INC", val, "Config")
end },
{ var = "enemyFireResist", type = "number", label = "Enemy Fire Resistance:", apply = function(val, modList, enemyModList)
enemyModList:NewMod("FireResist", "BASE", val, "Config")
end },
{ var = "enemyColdResist", type = "number", label = "Enemy Cold Resistance:", apply = function(val, modList, enemyModList)
enemyModList:NewMod("ColdResist", "BASE", val, "Config")
end },
{ var = "enemyLightningResist", type = "number", label = "Enemy Lightning Resistance:", apply = function(val, modList, enemyModList)
enemyModList:NewMod("LightningResist", "BASE", val, "Config")
end },
{ var = "enemyChaosResist", type = "number", label = "Enemy Chaos Resistance:", apply = function(val, modList, enemyModList)
enemyModList:NewMod("ChaosResist", "BASE", val, "Config")
end },
{ var = "enemyConditionHitByFireDamage", type = "check", label = "Enemy was Hit by Fire Damage?", ifNode = 39085, apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "EnemyCondition", var = "HitByFireDamage" }, "Config")
end },
{ var = "enemyConditionHitByColdDamage", type = "check", label = "Enemy was Hit by Cold Damage?", ifNode = 39085, apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "EnemyCondition", var = "HitByColdDamage" }, "Config")
end },
{ var = "enemyConditionHitByLightningDamage", type = "check", label = "Enemy was Hit by Light. Damage?", ifNode = 39085, apply = function(val, modList, enemyModList)
modList:NewMod("Misc", "LIST", { type = "EnemyCondition", var = "HitByLightningDamage" }, "Config")
end },
}
local ConfigTabClass = common.NewClass("ConfigTab", "UndoHandler", "ControlHost", "Control", function(self, build)
self.UndoHandler()
self.ControlHost()
self.Control()
self.build = build
self.input = { }
self.sectionList = { }
self.varControls = { }
self:BuildModList()
local lastSection
for _, varData in ipairs(varList) do
if varData.section then
lastSection = common.New("SectionControl", {"TOPLEFT",self,"TOPLEFT"}, 0, 0, 300, 0, varData.section)
lastSection.varControlList = { }
lastSection.height = function(self)
local height = 20
for _, varControl in pairs(self.varControlList) do
if varControl:IsShown() then
height = height + 20
end
end
return m_max(height, 32)
end
t_insert(self.sectionList, lastSection)
t_insert(self.controls, lastSection)
else
local control
if varData.type == "check" then
control = common.New("CheckBoxControl", {"TOPLEFT",lastSection,"TOPLEFT"}, 216, 0, 18, nil, function(state)
self.input[varData.var] = state
self:AddUndoState()
self:BuildModList()
self.build.buildFlag = true
end)
elseif varData.type == "number" then
control = common.New("EditControl", {"TOPLEFT",lastSection,"TOPLEFT"}, 216, 0, 50, 18, "", nil, "^%-%d", 4, function(buf)
self.input[varData.var] = tonumber(buf)
self:AddUndoState()
self:BuildModList()
self.build.buildFlag = true
end)
end
if varData.ifNode then
control.shown = function()
return self.build.spec.allocNodes[varData.ifNode]
end
control.tooltip = function()
return "This option is specific to '"..self.build.spec.nodes[varData.ifNode].dn.."'."..(varData.tooltip and "\n"..varData.tooltip or "")
end
else
control.tooltip = varData.tooltip
end
t_insert(self.controls, common.New("LabelControl", {"RIGHT",control,"LEFT"}, -4, 2, 0, 14, "^7"..varData.label))
self.varControls[varData.var] = control
t_insert(self.controls, control)
t_insert(lastSection.varControlList, control)
end
end
end)
function ConfigTabClass:Load(xml, fileName)
for _, node in ipairs(xml) do
if node.elem == "Input" then
if not node.attrib.name then
launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing name attribute", fileName)
return true
end
if node.attrib.number then
self.input[node.attrib.name] = tonumber(node.attrib.number)
elseif node.attrib.string then
self.input[node.attrib.name] = node.attrib.string
elseif node.attrib.boolean then
self.input[node.attrib.name] = node.attrib.boolean == "true"
else
launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing number, string or boolean attribute", fileName)
return true
end
end
end
self:BuildModList()
self:UpdateControls()
self:ResetUndo()
end
function ConfigTabClass:Save(xml)
for k, v in pairs(self.input) do
local child = { elem = "Input", attrib = {name = k} }
if type(v) == "number" then
child.attrib.number = tostring(v)
elseif type(v) == "boolean" then
child.attrib.boolean = tostring(v)
else
child.attrib.string = tostring(v)
end
t_insert(xml, child)
end
self.modFlag = false
end
function ConfigTabClass:UpdateControls()
for var, control in pairs(self.varControls) do
if control._className == "EditControl" then
control:SetText(tostring(self.input[var] or ""))
elseif control._className == "CheckBoxControl" then
control.state = self.input[var]
end
end
end
function ConfigTabClass:Draw(viewPort, inputEvents)
self.x = viewPort.x
self.y = viewPort.y
self.width = viewPort.width
self.height = viewPort.height
for id, event in ipairs(inputEvents) do
if event.type == "KeyDown" then
if event.key == "z" and IsKeyDown("CTRL") then
self:Undo()
self.build.buildFlag = true
elseif event.key == "y" and IsKeyDown("CTRL") then
self:Redo()
self.build.buildFlag = true
end
end
end
self:ProcessControlsInput(inputEvents, viewPort)
local colY = { }
for _, section in ipairs(self.sectionList) do
local y = 14
for _, varControl in ipairs(section.varControlList) do
if varControl:IsShown() then
varControl.y = y
y = y + 20
end
end
local width, height = section:GetSize()
local col = 1
while true do
colY[col] = colY[col] or 18
if colY[col] + height + 10 <= viewPort.height then
break
end
col = col + 1
end
section.x = 10 + (col - 1) * 310
section.y = colY[col]
colY[col] = colY[col] + height + 18
end
main:DrawBackground(viewPort)
self:DrawControls(viewPort)
end
function ConfigTabClass:BuildModList()
local modList = common.New("ModList")
self.modList = modList
local enemyModList = common.New("ModList")
self.enemyModList = enemyModList
local input = self.input
for _, varData in ipairs(varList) do
if varData.apply then
if varData.type == "check" then
if input[varData.var] then
varData.apply(true, modList, enemyModList)
end
elseif varData.type == "number" then
if input[varData.var] and input[varData.var] ~= 0 then
varData.apply(input[varData.var], modList, enemyModList)
end
end
end
end
end
function ConfigTabClass:ImportCalcSettings()
local input = self.input
local calcsInput = self.build.calcsTab.input
local function import(old, new)
input[new] = calcsInput[old]
calcsInput[old] = nil
end
import("Cond_LowLife", "conditionLowLife")
import("Cond_FullLife", "conditionFullLife")
import("buff_power", "usePowerCharges")
import("buff_frenzy", "useFrenzyCharges")
import("buff_endurance", "useEnduranceCharges")
import("CondBuff_Onslaught", "buffOnslaught")
import("CondBuff_Phasing", "buffPhasing")
import("CondBuff_Fortify", "buffFortify")
import("CondBuff_UsingFlask", "conditionUsingFlask")
import("buff_pendulum", "usePendulum")
import("CondEff_EnemyCursed", "conditionEnemyCursed")
import("CondEff_EnemyBleeding", "conditionEnemyBleeding")
import("CondEff_EnemyPoisoned", "conditionEnemyPoisoned")
import("CondEff_EnemyBurning", "conditionEnemyBurning")
import("CondEff_EnemyIgnited", "conditionEnemyIgnited")
import("CondEff_EnemyChilled", "conditionEnemyChilled")
import("CondEff_EnemyFrozen", "conditionEnemyFrozen")
import("CondEff_EnemyShocked", "conditionEnemyShocked")
import("effective_physicalRed", "enemyPhysicalReduction")
import("effective_fireResist", "enemyFireResist")
import("effective_coldResist", "enemyColdResist")
import("effective_lightningResist", "enemyLightningResist")
import("effective_chaosResist", "enemyChaosResist")
import("effective_enemyIsBoss", "enemyIsBoss")
self:BuildModList()
self:UpdateControls()
end
function ConfigTabClass:CreateUndoState()
return copyTable(self.input)
end
function ConfigTabClass:RestoreUndoState(state)
wipeTable(self.input)
for k, v in pairs(state) do
self.input[k] = v
end
self:UpdateControls()
self:BuildModList()
end