diff --git a/src/Classes/Item.lua b/src/Classes/Item.lua index da10d93e4c..37b55c5bce 100644 --- a/src/Classes/Item.lua +++ b/src/Classes/Item.lua @@ -1574,7 +1574,7 @@ function ItemClass:BuildModList() noSupports = skill.noSupports, source = self.modSource, triggered = skill.triggered, - triggerChance = skill.triggerChance + triggerChance = skill.triggerChance, }) end end diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index 1fa1ca6319..82071aaccc 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -150,7 +150,7 @@ end function calcs.copyActiveSkill(env, mode, skill) local newSkill = calcs.createActiveSkill(skill.activeEffect, skill.supportList, skill.actor, skill.socketGroup, skill.summonSkill) local newEnv, _, _, _ = calcs.initEnv(env.build, mode, env.override) - calcs.buildActiveSkillModList(newEnv, newSkill, {[cacheSkillUUID(newSkill)] = true}) + calcs.buildActiveSkillModList(newEnv, newSkill, {[cacheSkillUUID(newSkill, newEnv)] = true}) newSkill.skillModList = new("ModList", newSkill.baseSkillModList) if newSkill.minion then newSkill.minion.modDB = new("ModDB") diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 41ee7cee13..b00bbfd568 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -5107,88 +5107,6 @@ function calcs.offence(env, actor, activeSkill) end end - -- The Saviour - if activeSkill.activeEffect.grantedEffect.name == "Reflection" then - local usedSkill = nil - local usedSkillBestDps = 0 - local calcMode = env.mode == "CALCS" and "CALCS" or "MAIN" - for _, triggerSkill in ipairs(actor.activeSkillList) do - if triggerSkill ~= activeSkill and triggerSkill.skillTypes[SkillType.Attack] and band(triggerSkill.skillCfg.flags, bor(ModFlag.Sword, ModFlag.Weapon1H)) == bor(ModFlag.Sword, ModFlag.Weapon1H) then - -- Grab a fully-processed by calcs.perform() version of the skill that Mirage Warrior(s) will use - local uuid = cacheSkillUUID(triggerSkill) - if not GlobalCache.cachedData[calcMode][uuid] then - calcs.buildActiveSkill(env, calcMode, triggerSkill) - end - -- We found a skill and it can crit - if GlobalCache.cachedData[calcMode][uuid] and GlobalCache.cachedData[calcMode][uuid].CritChance and GlobalCache.cachedData[calcMode][uuid].CritChance > 0 then - if not usedSkill then - usedSkill = GlobalCache.cachedData[calcMode][uuid].ActiveSkill - usedSkillBestDps = GlobalCache.cachedData[calcMode][uuid].TotalDPS - else - if GlobalCache.cachedData[calcMode][uuid].TotalDPS > usedSkillBestDps then - usedSkill = GlobalCache.cachedData[calcMode][uuid].ActiveSkill - usedSkillBestDps = GlobalCache.cachedData[calcMode][uuid].TotalDPS - end - end - end - end - end - - if usedSkill then - local moreDamage = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "SaviourMirageWarriorLessDamage") - local maxMirageWarriors = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "SaviourMirageWarriorMaxCount") - local newSkill, newEnv = calcs.copyActiveSkill(env, calcMode, usedSkill) - - -- Add new modifiers to new skill (which already has all the old skill's modifiers) - newSkill.skillModList:NewMod("Damage", "MORE", moreDamage, "The Saviour", activeSkill.ModFlags, activeSkill.KeywordFlags) - if env.player.itemList["Weapon 1"] and env.player.itemList["Weapon 2"] and env.player.itemList["Weapon 1"].name == env.player.itemList["Weapon 2"].name then - maxMirageWarriors = maxMirageWarriors / 2 - end - newSkill.skillModList:NewMod("QuantityMultiplier", "BASE", maxMirageWarriors, "The Saviour Mirage Warriors", activeSkill.ModFlags, activeSkill.KeywordFlags) - - if usedSkill.skillPartName then - env.player.mainSkill.skillPart = usedSkill.skillPart - env.player.mainSkill.skillPartName = usedSkill.skillPartName - env.player.mainSkill.infoMessage2 = usedSkill.activeEffect.grantedEffect.name - else - env.player.mainSkill.skillPartName = usedSkill.activeEffect.grantedEffect.name - end - - newSkill.skillCfg.skillCond["usedByMirage"] = true - - -- Recalculate the offensive/defensive aspects of this new skill - newEnv.player.mainSkill = newSkill - calcs.perform(newEnv) - env.player.mainSkill = newSkill - - env.player.mainSkill.infoMessage = tostring(maxMirageWarriors) .. " Mirage Warriors using " .. usedSkill.activeEffect.grantedEffect.name - - -- Re-link over the output - env.player.output = newEnv.player.output - if newSkill.minion then - env.minion = newEnv.player.mainSkill.minion - env.minion.output = newEnv.minion.output - end - - -- Make any necessary corrections to output - env.player.output.ManaCost = 0 - - -- Re-link over the breakdown (if present) - if newEnv.player.breakdown then - env.player.breakdown = newEnv.player.breakdown - - -- Make any necessary corrections to breakdown - env.player.breakdown.ManaCost = nil - - if newSkill.minion then - env.minion.breakdown = newEnv.minion.breakdown - end - end - else - activeSkill.infoMessage2 = "No Saviour active skill found" - end - end - -- Calculate combined DPS estimate, including DoTs local baseDPS = output[(skillData.showAverage and "AverageDamage") or "TotalDPS"] output.CombinedDPS = baseDPS diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index efef4021a8..b0f89f1ca5 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -2687,5 +2687,5 @@ function calcs.perform(env, avoidCache, fullDPSSkipEHP) calcs.offence(env, env.minion, env.minion.mainSkill) end - cacheData(cacheSkillUUID(env.player.mainSkill), env) + cacheData(cacheSkillUUID(env.player.mainSkill, env), env) end diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 6e4a503d53..d3c50e0621 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -1091,6 +1091,7 @@ function calcs.initEnv(build, mode, override, specEnv) activeGemInstance.gemId = nil activeGemInstance.level = grantedSkill.level activeGemInstance.enableGlobal1 = true + activeGemInstance.noSupports = grantedSkill.noSupports if grantedSkill.triggered then activeGemInstance.triggered = grantedSkill.triggered end diff --git a/src/Modules/CalcTriggers.lua b/src/Modules/CalcTriggers.lua index c9ac6758bc..82ca0a29e1 100644 --- a/src/Modules/CalcTriggers.lua +++ b/src/Modules/CalcTriggers.lua @@ -56,8 +56,8 @@ local function processAddedCastTime(skill, breakdown) end end -local function packageSkillDataForSimulation(skill) - return { uuid = cacheSkillUUID(skill), cd = skill.skillData.cooldown, cdOverride = skill.skillModList:Override(skill.skillCfg, "CooldownRecovery"), addsCastTime = processAddedCastTime(skill), icdr = calcLib.mod(skill.skillModList, skill.skillCfg, "CooldownRecovery")} +local function packageSkillDataForSimulation(skill, env) + return { uuid = cacheSkillUUID(skill, env), cd = skill.skillData.cooldown, cdOverride = skill.skillModList:Override(skill.skillCfg, "CooldownRecovery"), addsCastTime = processAddedCastTime(skill), icdr = calcLib.mod(skill.skillModList, skill.skillCfg, "CooldownRecovery")} end -- Identify the trigger action skill for trigger conditions, take highest Attack Per Second @@ -67,7 +67,7 @@ local function findTriggerSkill(env, skill, source, triggerRate, comparer) return (not source and cachedSpeed) or (cachedSpeed and cachedSpeed > (triggerRate or 0)) end - local uuid = cacheSkillUUID(skill) + local uuid = cacheSkillUUID(skill, env) if not GlobalCache.cachedData["CACHE"][uuid] or GlobalCache.noCache then calcs.buildActiveSkill(env, "CACHE", skill) end @@ -75,7 +75,7 @@ local function findTriggerSkill(env, skill, source, triggerRate, comparer) if GlobalCache.cachedData["CACHE"][uuid] and comparer(uuid, source, triggerRate) then return skill, GlobalCache.cachedData["CACHE"][uuid].Speed, uuid end - return source, triggerRate, source and cacheSkillUUID(source) + return source, triggerRate, source and cacheSkillUUID(source, env) end -- Calculate the impact other skills and source rate to trigger cooldown alignment have on the trigger rate @@ -251,7 +251,7 @@ function calcMultiSpellRotationImpact(env, skills, sourceRate, triggerCD, actor) local mainRate local trigRateTable = { simRes = SIM_RESOLUTION, rates = {}, } for _, sd in ipairs(skills) do - if cacheSkillUUID(actor.mainSkill) == sd.uuid then + if cacheSkillUUID(actor.mainSkill, env) == sd.uuid then mainRate = sd.rate end t_insert(trigRateTable.rates, { name = sd.uuid, rate = sd.rate }) @@ -267,7 +267,7 @@ local function mirageArcherHandler(env) -- This creates and populates env.player.mainSkill.mirage table if not env.player.mainSkill.skillFlags.minion and not env.player.mainSkill.skillData.limitedProcessing then local usedSkill = nil - local uuid = cacheSkillUUID(env.player.mainSkill) + local uuid = cacheSkillUUID(env.player.mainSkill, env) local calcMode = env.mode == "CALCS" and "CALCS" or "MAIN" -- cache a new copy of this skill that's affected by Mirage Archer @@ -444,7 +444,7 @@ local function CWCHandler(env) source, trigRate = findTriggerSkill(env, skill, source, trigRate) end if skill.skillData.triggeredWhileChannelling and (match1 or match2) then - t_insert(triggeredSkills, packageSkillDataForSimulation(skill)) + t_insert(triggeredSkills, packageSkillDataForSimulation(skill, env)) end end if not source or #triggeredSkills < 1 then @@ -569,7 +569,7 @@ local function CWCHandler(env) env.player.mainSkill.skillFlags.globalTrigger = true env.player.mainSkill.skillData.triggerSource = source env.player.mainSkill.skillData.triggerRate = output.SkillTriggerRate - env.player.mainSkill.skillData.triggerSourceUUID = cacheSkillUUID(source, env.mode) + env.player.mainSkill.skillData.triggerSourceUUID = cacheSkillUUID(source, env) env.player.mainSkill.infoMessage = triggerName .."'s Trigger: ".. source.activeEffect.grantedEffect.name env.player.infoTrigger = env.player.mainSkill.infoTrigger or triggerName end @@ -583,7 +583,7 @@ local function theSaviourHandler(env) for _, triggerSkill in ipairs(env.player.activeSkillList) do if triggerSkill ~= env.player.mainSkill and triggerSkill.skillTypes[SkillType.Attack] and not triggerSkill.skillTypes[SkillType.Totem] and not triggerSkill.skillTypes[SkillType.SummonsTotem] and band(triggerSkill.skillCfg.flags, bor(ModFlag.Sword, ModFlag.Weapon1H)) == bor(ModFlag.Sword, ModFlag.Weapon1H) then -- Grab a fully-processed by calcs.perform() version of the skill that Mirage Warrior(s) will use - local uuid = cacheSkillUUID(triggerSkill) + local uuid = cacheSkillUUID(triggerSkill, env) if not GlobalCache.cachedData[calcMode][uuid] then calcs.buildActiveSkill(env, calcMode, triggerSkill) end @@ -668,7 +668,7 @@ local function tawhoaChosenHandler(env) local isDisabled = triggerSkill.skillFlags and triggerSkill.skillFlags.disable if triggerSkill ~= env.player.mainSkill and (triggerSkill.skillTypes[SkillType.Slam] or triggerSkill.skillTypes[SkillType.Melee]) and triggerSkill.skillTypes[SkillType.Attack] and not triggerSkill.skillTypes[SkillType.Vaal] and not triggered and not isDisabled and not triggerSkill.skillTypes[SkillType.Totem] and not triggerSkill.skillTypes[SkillType.SummonsTotem] then -- Grab a fully-processed by calcs.perform() version of the skill that Tawhoa's Chosen will use - local uuid = cacheSkillUUID(triggerSkill) + local uuid = cacheSkillUUID(triggerSkill, env) if not GlobalCache.cachedData[calcMode][uuid] then calcs.buildActiveSkill(env, calcMode, triggerSkill) end @@ -716,7 +716,7 @@ local function tawhoaChosenHandler(env) local simBreakdown if EffectiveSourceRate ~= 0 then - SkillTriggerRate, simBreakdown = calcMultiSpellRotationImpact(env, {{ uuid = cacheSkillUUID(usedSkill), cd = triggeredCD }}, EffectiveSourceRate, effectiveTriggerCD) + SkillTriggerRate, simBreakdown = calcMultiSpellRotationImpact(env, {{ uuid = cacheSkillUUID(usedSkill, env), cd = triggeredCD }}, EffectiveSourceRate, effectiveTriggerCD) if breakdown then BreakdownSkillTriggerRate = { s_format("%.2f ^8(effective trigger rate of trigger)", EffectiveSourceRate), @@ -843,7 +843,7 @@ local function defaultTriggerHandler(env, config) source, trigRate, uuid = findTriggerSkill(env, skill, source, trigRate, config.comparer) end if config.triggeredSkillCond and config.triggeredSkillCond(env,skill) then - t_insert(triggeredSkills, packageSkillDataForSimulation(skill)) + t_insert(triggeredSkills, packageSkillDataForSimulation(skill, env)) end end end @@ -952,7 +952,7 @@ local function defaultTriggerHandler(env, config) -- Handling for mana spending rate for Manaforged Arrows Support if actor.mainSkill.skillData.triggeredByManaforged and trigRate > 0 then - local triggeredUUID = cacheSkillUUID(actor.mainSkill) + local triggeredUUID = cacheSkillUUID(actor.mainSkill, env) if not GlobalCache.cachedData["CACHE"][triggeredUUID] then calcs.buildActiveSkill(env, "CACHE", actor.mainSkill, {[triggeredUUID] = true}) end @@ -1217,7 +1217,7 @@ local function defaultTriggerHandler(env, config) if actor.mainSkill.skillFlags.globalTrigger and not config.triggeredSkillCond then output.SkillTriggerRate = output.EffectiveSourceRate else - output.SkillTriggerRate, simBreakdown = calcMultiSpellRotationImpact(env, config.triggeredSkillCond and triggeredSkills or {packageSkillDataForSimulation(actor.mainSkill)}, output.EffectiveSourceRate, (not actor.mainSkill.skillData.triggeredByBrand and ( triggerCD or triggeredCD ) or 0) / icdr, actor) + output.SkillTriggerRate, simBreakdown = calcMultiSpellRotationImpact(env, config.triggeredSkillCond and triggeredSkills or {packageSkillDataForSimulation(actor.mainSkill, env)}, output.EffectiveSourceRate, (not actor.mainSkill.skillData.triggeredByBrand and ( triggerCD or triggeredCD ) or 0) / icdr, actor) local triggerBotsEffective = actor.modDB:Flag(nil, "HaveTriggerBots") and actor.mainSkill.skillTypes[SkillType.Spell] if triggerBotsEffective then output.SkillTriggerRate = 2 * output.SkillTriggerRate @@ -1284,7 +1284,7 @@ local function defaultTriggerHandler(env, config) addTriggerIncMoreMods(actor.mainSkill, source or actor.mainSkill) if source and source ~= actor.mainSkill then actor.mainSkill.skillData.triggerSource = source - actor.mainSkill.skillData.triggerSourceUUID = cacheSkillUUID(source, env.mode) + actor.mainSkill.skillData.triggerSourceUUID = cacheSkillUUID(source, env) actor.mainSkill.infoMessage = (config.customTriggerName or ((config.triggerName ~= source.activeEffect.grantedEffect.name and config.triggerName or triggeredName) .. ( actor == env.minion and "'s attack Trigger: " or "'s Trigger: "))) .. source.activeEffect.grantedEffect.name else actor.mainSkill.infoMessage = actor.mainSkill.triggeredBy and actor.mainSkill.triggeredBy.grantedEffect.name or config.triggerName .. " Trigger" @@ -1464,7 +1464,7 @@ local configTable = { end end if skill.skillData.triggeredByCraft and env.player.mainSkill.socketGroup.slot == skill.socketGroup.slot then - t_insert(triggeredSkills, packageSkillDataForSimulation(skill)) + t_insert(triggeredSkills, packageSkillDataForSimulation(skill, env)) end end return {trigRate = trigRate, source = source, uuid = uuid, useCastRate = useCastRate, triggeredSkills = triggeredSkills} @@ -1522,7 +1522,7 @@ local configTable = { if env.minion and env.minion.mainSkill then return {triggerName = "Summon Holy Relic", actor = env.minion, - triggeredSkills = {{ uuid = cacheSkillUUID(env.minion.mainSkill), cd = env.minion.mainSkill.skillData.cooldown}}, + triggeredSkills = {{ uuid = cacheSkillUUID(env.minion.mainSkill, env), cd = env.minion.mainSkill.skillData.cooldown}}, triggerSkillCond = function(env, skill) return skill.skillTypes[SkillType.Attack] end} end end, @@ -1754,7 +1754,7 @@ local function logNoHandler(skillName, triggerName, uniqueName) end function calcs.triggers(env) - if not env.player.mainSkill.skillFlags.disable and not env.player.mainSkill.skillData.limitedProcessing then + if not env.player.mainSkill.skillFlags.disable and not env.player.mainSkill.skillData.limitedProcessing and not (env.player.mainSkill.activeEffect.srcInstance and env.player.mainSkill.activeEffect.srcInstance.noSupports) then local skillName = env.minion and env.minion.mainSkill.activeEffect.grantedEffect.name or env.player.mainSkill.activeEffect.grantedEffect.name local triggerName = env.player.mainSkill.triggeredBy and env.player.mainSkill.triggeredBy.grantedEffect.name local uniqueName = getUniqueItemTriggerName(env.player.mainSkill) diff --git a/src/Modules/Calcs.lua b/src/Modules/Calcs.lua index 9cf141c937..0fbfa3de69 100644 --- a/src/Modules/Calcs.lua +++ b/src/Modules/Calcs.lua @@ -207,7 +207,7 @@ function calcs.calcFullDPS(build, mode, override, specEnv) -- calc defences extra part should only run on the last skill of FullDPS local numActiveSkillInFullDPS = 0 for _, activeSkill in ipairs(fullEnv.player.activeSkillList) do - if activeSkill.socketGroup and activeSkill.socketGroup.includeInFullDPS and not isExcludedFromFullDps(activeSkill) then + if activeSkill.socketGroup and activeSkill.socketGroup.includeInFullDPS and not GlobalCache.excludeFullDpsList[cacheSkillUUID(activeSkill, fullEnv)] then local activeSkillCount, enabled = getActiveSkillCount(activeSkill) if enabled then numActiveSkillInFullDPS = numActiveSkillInFullDPS + 1 @@ -217,11 +217,11 @@ function calcs.calcFullDPS(build, mode, override, specEnv) GlobalCache.numActiveSkillInFullDPS = 0 for _, activeSkill in ipairs(fullEnv.player.activeSkillList) do - if activeSkill.socketGroup and activeSkill.socketGroup.includeInFullDPS and not isExcludedFromFullDps(activeSkill) then + if activeSkill.socketGroup and activeSkill.socketGroup.includeInFullDPS and not GlobalCache.excludeFullDpsList[cacheSkillUUID(activeSkill, fullEnv)] then local activeSkillCount, enabled = getActiveSkillCount(activeSkill) if enabled then GlobalCache.numActiveSkillInFullDPS = GlobalCache.numActiveSkillInFullDPS + 1 - local cachedData = getCachedData(activeSkill, mode) + local cachedData = GlobalCache.cachedData[mode][cacheSkillUUID(activeSkill, fullEnv)] if cachedData and next(override) == nil and not GlobalCache.noCache then usedEnv = cachedData.Env activeSkill = usedEnv.player.mainSkill @@ -411,9 +411,9 @@ end function calcs.buildActiveSkill(env, mode, skill, limitedProcessingFlags) local fullEnv, _, _, _ = calcs.initEnv(env.build, mode, env.override) for _, activeSkill in ipairs(fullEnv.player.activeSkillList) do - if cacheSkillUUID(activeSkill) == cacheSkillUUID(skill) then + if cacheSkillUUID(activeSkill, fullEnv) == cacheSkillUUID(activeSkill, fullEnv) then fullEnv.player.mainSkill = activeSkill - fullEnv.player.mainSkill.skillData.limitedProcessing = limitedProcessingFlags and limitedProcessingFlags[cacheSkillUUID(activeSkill)] + fullEnv.player.mainSkill.skillData.limitedProcessing = limitedProcessingFlags and limitedProcessingFlags[cacheSkillUUID(activeSkill, fullEnv)] calcs.perform(fullEnv) return end @@ -430,7 +430,7 @@ function calcs.buildOutput(build, mode) local output = env.player.output for _, skill in ipairs(env.player.activeSkillList) do - local uuid = cacheSkillUUID(skill) + local uuid = cacheSkillUUID(skill, env) if not GlobalCache.cachedData["CACHE"][uuid] then calcs.buildActiveSkill(env, "CACHE", skill) end diff --git a/src/Modules/Common.lua b/src/Modules/Common.lua index 7511b11727..72004a35ab 100644 --- a/src/Modules/Common.lua +++ b/src/Modules/Common.lua @@ -683,21 +683,30 @@ function zip(a, b) end -- Generate a UUID for a skill -function cacheSkillUUID(skill) +function cacheSkillUUID(skill, env) local strName = skill.activeEffect.grantedEffect.name:gsub("%s+", "") -- strip spaces local strSlotName = (skill.socketGroup and skill.socketGroup.slot and skill.socketGroup.slot:upper() or "NO_SLOT"):gsub("%s+", "") -- strip spaces - local indx = 1 + local slotIndx = 1 + local groupIdx = 1 if skill.socketGroup and skill.socketGroup.gemList and skill.activeEffect.srcInstance then for idx, gem in ipairs(skill.socketGroup.gemList) do -- we compare table addresses rather than names since two of the same gem -- can be socketed in the same slot if gem == skill.activeEffect.srcInstance then - indx = idx + slotIndx = idx break end end end - return strName.."_"..strSlotName.."_"..tostring(indx) + + for i, group in ipairs(env.build.skillsTab.socketGroupList) do + if skill.socketGroup == group then + groupIdx = i + break + end + end + + return strName.."_"..strSlotName.."_"..tostring(indx) .. "_" .. tostring(groupIdx) end -- Global Cache related @@ -727,13 +736,6 @@ function cacheData(uuid, env) } end --- Obtain a stored cached processed skill identified by --- its UUID and pulled from an appropriate env mode (e.g., MAIN) -function getCachedData(skill, mode) - local uuid = cacheSkillUUID(skill) - return GlobalCache.cachedData[mode][uuid] -end - -- Add an entry for a fabricated skill (e.g., Mirage Archers) -- to be deleted if it's not longer needed function addDeleteGroupEntry(name) @@ -779,18 +781,6 @@ function wipeGlobalCache() GlobalCache.noCache = nil end --- Full DPS related: add to roll-up exclusion list --- this is for skills that are used by Mirage Warriors for example -function addToFullDpsExclusionList(skill) - --ConPrintf("ADDING TO FULL DPS EXCLUDE: " .. cacheSkillUUID(skill)) - GlobalCache.excludeFullDpsList[cacheSkillUUID(skill)] = true -end - --- Full DPS related: check if skill is in roll-up exclusion list -function isExcludedFromFullDps(skill) - return GlobalCache.excludeFullDpsList[cacheSkillUUID(skill)] -end - -- Check if a specific named gem is enabled in a socket group belonging to a skill function supportEnabled(skillName, activeSkill) for _, gemInstance in ipairs(activeSkill.socketGroup.gemList) do