From ac45d6eb9eb4d7c09cbedf800537b1f46531f1ef Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Tue, 17 Mar 2026 09:38:29 +1100 Subject: [PATCH] Fix Molten Strike of the Zenith Total Weighted Ball Average calc The value for the extra damage and additonal projectiles on the 5th strike was hardcoded so when GGG changed the value to 600% the calc was still using 800% Now has the calc on the gem itself and pulls those stats directly from the gem so there are no more hardcoded values --- src/Data/Skills/act_str.lua | 117 ++++++++++++++++++++++++---------- src/Export/Skills/act_str.txt | 117 ++++++++++++++++++++++++---------- 2 files changed, 168 insertions(+), 66 deletions(-) diff --git a/src/Data/Skills/act_str.lua b/src/Data/Skills/act_str.lua index 619f94bb89..1e04f5a1e5 100644 --- a/src/Data/Skills/act_str.lua +++ b/src/Data/Skills/act_str.lua @@ -7687,38 +7687,16 @@ skills["MoltenStrike"] = { t_insert(breakdown.OverlapChance, s_format("^8=^7 %.2f^8%%", output.OverlapChance)) end - local numProjectiles = skillModList:Sum("BASE", skillCfg, "ProjectileCount") + local numProjectiles = output.ProjectileCount local dpsMult = 1 - if skillPart == 3 or skillPart == 5 or skillPart == 6 then + if skillPart == 3 then dpsMult = overlapChance * numProjectiles - - if skillPart ~= 6 then - if breakdown then - breakdown.SkillDPSMultiplier = {} - t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier") - t_insert(breakdown.SkillDPSMultiplier, "^8= number of projectiles * overlap chance") - t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d^8 *^7 %.3f^8", numProjectiles, overlapChance)) - t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMult)) - end - else - -- zenith: make an effective dpsMult for the weighted average of normal and 5th attack balls - local gemQuality = activeSkill.activeEffect.quality - local fifthAttackMulti = 1 + 8 + 0.1 * gemQuality - local fifthAttackOverallMulti = fifthAttackMulti * overlapChance * (numProjectiles + 5) - dpsMult = 0.8 * dpsMult + 0.2 * fifthAttackOverallMulti - - if breakdown then - breakdown.SkillDPSMultiplier = {} - t_insert(breakdown.SkillDPSMultiplier, "Weighted average DPS multiplier for balls") - t_insert(breakdown.SkillDPSMultiplier, "^8= (0.8 * balls dps) + (0.2 * 5th attack balls dps)") - t_insert(breakdown.SkillDPSMultiplier, "^8= (0.8 * normal ball hit * overlap chance * number of projectiles) " .. - "+ (0.2 * ball hit * 5th attack multiplier * overlap chance * (number of projectiles + 5))") - t_insert(breakdown.SkillDPSMultiplier, "^8= ball hit * overlap chance * (0.8 * number of projectiles " .. - "+ 0.2 * 5th attack multiplier * (number of projectiles + 5))") - t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * ^7%.3f ^8* (0.8 * ^7%d ^8+ 0.2 * ^7%.1f ^8* ^7%d^8)", - overlapChance, numProjectiles, fifthAttackMulti, numProjectiles + 5)) - t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * ^7 %.3f", dpsMult)) - end + if breakdown then + breakdown.SkillDPSMultiplier = {} + t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier") + t_insert(breakdown.SkillDPSMultiplier, "^8= number of projectiles * overlap chance") + t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d^8 *^7 %.3f^8", numProjectiles, overlapChance)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMult)) end end if dpsMult ~= 1 then @@ -7856,16 +7834,89 @@ skills["MoltenStrikeAltX"] = { area = true, }, }, - preDamageFunc = skills.MoltenStrike.preDamageFunc, + preDamageFunc = function(activeSkill, output, breakdown) + local skillCfg = activeSkill.skillCfg + local skillData = activeSkill.skillData + local skillPart = activeSkill.skillPart + local skillModList = activeSkill.skillModList + local t_insert = table.insert + local s_format = string.format + + -- melee part doesn't need to calc balls + if skillPart == 1 then + return + end + + local enemyRadius = skillModList:Override(skillCfg, "EnemyRadius") or skillModList:Sum("BASE", skillCfg, "EnemyRadius") + local ballRadius = output.AreaOfEffectRadius + local innerRadius = output.AreaOfEffectRadiusSecondary + local outerRadius = output.AreaOfEffectRadiusTertiary + + -- logic adapted from MoldyDwarf's calculator + local hitRange = enemyRadius + ballRadius - innerRadius + local landingRange = outerRadius - innerRadius + local overlapChance = math.min(1, hitRange / landingRange) + output.OverlapChance = overlapChance * 100 + + if breakdown then + breakdown.OverlapChance = { } + t_insert(breakdown.OverlapChance, "Chance for individual balls to land on the enemy:") + t_insert(breakdown.OverlapChance, "^8= (area where a ball can land on enemy) / (total area)") + t_insert(breakdown.OverlapChance, "^8= (enemy radius + ball radius - min travel) / (max travel - min travel)") + t_insert(breakdown.OverlapChance, s_format("^8= (^7%d^8 + ^7%d^8 - ^7%d) / (^7%d^8 - ^7%d)", + enemyRadius, ballRadius, innerRadius, outerRadius, innerRadius)) + t_insert(breakdown.OverlapChance, s_format("^8=^7 %.2f^8%%", output.OverlapChance)) + end + + local numProjectiles = output.ProjectileCount + local dpsMult = 1 + if skillPart == 3 or skillPart == 5 or skillPart == 6 then + dpsMult = overlapChance * numProjectiles + + if skillPart ~= 6 then + if breakdown then + breakdown.SkillDPSMultiplier = {} + t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier") + t_insert(breakdown.SkillDPSMultiplier, "^8= number of projectiles * overlap chance") + t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d^8 *^7 %.3f^8", numProjectiles, overlapChance)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMult)) + end + else + -- zenith: make an effective dpsMult for the weighted average of normal and 5th attack balls + local fifthAttackMulti = 1 + skillData.FifthStrikeDamage / 100 + local fifthAttackOverallMulti = fifthAttackMulti * overlapChance * (numProjectiles + skillData.FifthStrikeProjectiles) + dpsMult = 0.8 * dpsMult + 0.2 * fifthAttackOverallMulti + + if breakdown then + breakdown.SkillDPSMultiplier = {} + t_insert(breakdown.SkillDPSMultiplier, "Weighted average DPS multiplier for balls") + t_insert(breakdown.SkillDPSMultiplier, "^8= (0.8 * balls dps) + (0.2 * 5th attack balls dps)") + t_insert(breakdown.SkillDPSMultiplier, s_format("^8= (0.8 * normal ball hit * overlap chance * number of projectiles) " .. + "+ (0.2 * ball hit * 5th attack multiplier * overlap chance * (number of projectiles + %d))", skillData.FifthStrikeProjectiles)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * overlap chance * (0.8 * number of projectiles " .. + "+ 0.2 * 5th attack multiplier * (number of projectiles + %d))", skillData.FifthStrikeProjectiles)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * ^7%.3f ^8* (0.8 * ^7%d ^8+ 0.2 * ^7%.1f ^8* ^7%d^8)", + overlapChance, numProjectiles, fifthAttackMulti, numProjectiles + skillData.FifthStrikeProjectiles)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * ^7 %.3f", dpsMult)) + end + end + end + if dpsMult ~= 1 then + skillData.dpsMultiplier = (skillData.dpsMultiplier or 1) * dpsMult + output.SkillDPSMultiplier = (output.SkillDPSMultiplier or 1) * dpsMult + end + end, statMap = { ["active_skill_hit_ailment_damage_with_projectile_+%_final"] = { mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPartList = { 2, 3, 4, 5, 6 } }) }, ["molten_strike_every_5th_attack_projectiles_damage_+%_final"] = { - mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPartList = { 4, 5 } }) + mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPartList = { 4, 5 } }), + skill("FifthStrikeDamage", nil), }, ["molten_strike_every_5th_attack_fire_X_additional_projectiles"] = { - mod("ProjectileCount", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 4, 5 } }) + mod("ProjectileCount", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 4, 5 } }), + skill("FifthStrikeProjectiles", nil), }, }, baseFlags = { diff --git a/src/Export/Skills/act_str.txt b/src/Export/Skills/act_str.txt index 4d2478c56e..d5da4291fb 100644 --- a/src/Export/Skills/act_str.txt +++ b/src/Export/Skills/act_str.txt @@ -1386,38 +1386,16 @@ local skills, mod, flag, skill = ... t_insert(breakdown.OverlapChance, s_format("^8=^7 %.2f^8%%", output.OverlapChance)) end - local numProjectiles = skillModList:Sum("BASE", skillCfg, "ProjectileCount") + local numProjectiles = output.ProjectileCount local dpsMult = 1 - if skillPart == 3 or skillPart == 5 or skillPart == 6 then + if skillPart == 3 then dpsMult = overlapChance * numProjectiles - - if skillPart ~= 6 then - if breakdown then - breakdown.SkillDPSMultiplier = {} - t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier") - t_insert(breakdown.SkillDPSMultiplier, "^8= number of projectiles * overlap chance") - t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d^8 *^7 %.3f^8", numProjectiles, overlapChance)) - t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMult)) - end - else - -- zenith: make an effective dpsMult for the weighted average of normal and 5th attack balls - local gemQuality = activeSkill.activeEffect.quality - local fifthAttackMulti = 1 + 8 + 0.1 * gemQuality - local fifthAttackOverallMulti = fifthAttackMulti * overlapChance * (numProjectiles + 5) - dpsMult = 0.8 * dpsMult + 0.2 * fifthAttackOverallMulti - - if breakdown then - breakdown.SkillDPSMultiplier = {} - t_insert(breakdown.SkillDPSMultiplier, "Weighted average DPS multiplier for balls") - t_insert(breakdown.SkillDPSMultiplier, "^8= (0.8 * balls dps) + (0.2 * 5th attack balls dps)") - t_insert(breakdown.SkillDPSMultiplier, "^8= (0.8 * normal ball hit * overlap chance * number of projectiles) " .. - "+ (0.2 * ball hit * 5th attack multiplier * overlap chance * (number of projectiles + 5))") - t_insert(breakdown.SkillDPSMultiplier, "^8= ball hit * overlap chance * (0.8 * number of projectiles " .. - "+ 0.2 * 5th attack multiplier * (number of projectiles + 5))") - t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * ^7%.3f ^8* (0.8 * ^7%d ^8+ 0.2 * ^7%.1f ^8* ^7%d^8)", - overlapChance, numProjectiles, fifthAttackMulti, numProjectiles + 5)) - t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * ^7 %.3f", dpsMult)) - end + if breakdown then + breakdown.SkillDPSMultiplier = {} + t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier") + t_insert(breakdown.SkillDPSMultiplier, "^8= number of projectiles * overlap chance") + t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d^8 *^7 %.3f^8", numProjectiles, overlapChance)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMult)) end end if dpsMult ~= 1 then @@ -1480,16 +1458,89 @@ local skills, mod, flag, skill = ... area = true, }, }, - preDamageFunc = skills.MoltenStrike.preDamageFunc, + preDamageFunc = function(activeSkill, output, breakdown) + local skillCfg = activeSkill.skillCfg + local skillData = activeSkill.skillData + local skillPart = activeSkill.skillPart + local skillModList = activeSkill.skillModList + local t_insert = table.insert + local s_format = string.format + + -- melee part doesn't need to calc balls + if skillPart == 1 then + return + end + + local enemyRadius = skillModList:Override(skillCfg, "EnemyRadius") or skillModList:Sum("BASE", skillCfg, "EnemyRadius") + local ballRadius = output.AreaOfEffectRadius + local innerRadius = output.AreaOfEffectRadiusSecondary + local outerRadius = output.AreaOfEffectRadiusTertiary + + -- logic adapted from MoldyDwarf's calculator + local hitRange = enemyRadius + ballRadius - innerRadius + local landingRange = outerRadius - innerRadius + local overlapChance = math.min(1, hitRange / landingRange) + output.OverlapChance = overlapChance * 100 + + if breakdown then + breakdown.OverlapChance = { } + t_insert(breakdown.OverlapChance, "Chance for individual balls to land on the enemy:") + t_insert(breakdown.OverlapChance, "^8= (area where a ball can land on enemy) / (total area)") + t_insert(breakdown.OverlapChance, "^8= (enemy radius + ball radius - min travel) / (max travel - min travel)") + t_insert(breakdown.OverlapChance, s_format("^8= (^7%d^8 + ^7%d^8 - ^7%d) / (^7%d^8 - ^7%d)", + enemyRadius, ballRadius, innerRadius, outerRadius, innerRadius)) + t_insert(breakdown.OverlapChance, s_format("^8=^7 %.2f^8%%", output.OverlapChance)) + end + + local numProjectiles = output.ProjectileCount + local dpsMult = 1 + if skillPart == 3 or skillPart == 5 or skillPart == 6 then + dpsMult = overlapChance * numProjectiles + + if skillPart ~= 6 then + if breakdown then + breakdown.SkillDPSMultiplier = {} + t_insert(breakdown.SkillDPSMultiplier, "DPS multiplier") + t_insert(breakdown.SkillDPSMultiplier, "^8= number of projectiles * overlap chance") + t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %d^8 *^7 %.3f^8", numProjectiles, overlapChance)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8=^7 %.3f", dpsMult)) + end + else + -- zenith: make an effective dpsMult for the weighted average of normal and 5th attack balls + local fifthAttackMulti = 1 + skillData.FifthStrikeDamage / 100 + local fifthAttackOverallMulti = fifthAttackMulti * overlapChance * (numProjectiles + skillData.FifthStrikeProjectiles) + dpsMult = 0.8 * dpsMult + 0.2 * fifthAttackOverallMulti + + if breakdown then + breakdown.SkillDPSMultiplier = {} + t_insert(breakdown.SkillDPSMultiplier, "Weighted average DPS multiplier for balls") + t_insert(breakdown.SkillDPSMultiplier, "^8= (0.8 * balls dps) + (0.2 * 5th attack balls dps)") + t_insert(breakdown.SkillDPSMultiplier, s_format("^8= (0.8 * normal ball hit * overlap chance * number of projectiles) " .. + "+ (0.2 * ball hit * 5th attack multiplier * overlap chance * (number of projectiles + %d))", skillData.FifthStrikeProjectiles)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * overlap chance * (0.8 * number of projectiles " .. + "+ 0.2 * 5th attack multiplier * (number of projectiles + %d))", skillData.FifthStrikeProjectiles)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * ^7%.3f ^8* (0.8 * ^7%d ^8+ 0.2 * ^7%.1f ^8* ^7%d^8)", + overlapChance, numProjectiles, fifthAttackMulti, numProjectiles + skillData.FifthStrikeProjectiles)) + t_insert(breakdown.SkillDPSMultiplier, s_format("^8= ball hit * ^7 %.3f", dpsMult)) + end + end + end + if dpsMult ~= 1 then + skillData.dpsMultiplier = (skillData.dpsMultiplier or 1) * dpsMult + output.SkillDPSMultiplier = (output.SkillDPSMultiplier or 1) * dpsMult + end + end, statMap = { ["active_skill_hit_ailment_damage_with_projectile_+%_final"] = { mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPartList = { 2, 3, 4, 5, 6 } }) }, ["molten_strike_every_5th_attack_projectiles_damage_+%_final"] = { - mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPartList = { 4, 5 } }) + mod("Damage", "MORE", nil, bit.band(ModFlag.Hit, ModFlag.Ailment), 0, { type = "SkillPart", skillPartList = { 4, 5 } }), + skill("FifthStrikeDamage", nil), }, ["molten_strike_every_5th_attack_fire_X_additional_projectiles"] = { - mod("ProjectileCount", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 4, 5 } }) + mod("ProjectileCount", "BASE", nil, 0, 0, { type = "SkillPart", skillPartList = { 4, 5 } }), + skill("FifthStrikeProjectiles", nil), }, }, #baseMod skill("projectileSpeedAppliesToMSAreaOfEffect", true)