17,101
edits
(_getMonsterMaxHit: Consider curses which may increase damage taken by the player) |
(_getMonsterMaxHit: Further fixes for various scenarios which weren't previously accounted for) |
||
Line 389: | Line 389: | ||
function p.canSpecAttackApplyEffect(specAttack, effectType) | function p.canSpecAttackApplyEffect(specAttack, effectType) | ||
for i, effect in pairs(specAttack | local effectKeys = { 'prehitEffects', 'onhitEffects' } | ||
for i, effectKey in ipairs(effectKeys) do | |||
if type(specAttack[effectKey]) == 'table' then | |||
for j, effect in pairs(specAttack[effectKey]) do | |||
if effect.type == effectType or p.canModifiersApplyEffect(effect.modifiers, effectType) then | |||
return true | |||
end | |||
end | |||
end | end | ||
end | end | ||
return false | |||
end | |||
function p.canModifiersApplyEffect(modifiers, effectType) | |||
-- List of modifiers which can result in the application of status effects | |||
local statusModsAll = { | |||
["Stun"] = { 'increasedGlobalStunChance', 'increasedMeleeStunChance' }, | |||
["Sleep"] = { 'increasedGlobalSleepChance' }, | |||
["Poison"] = { 'increasedChanceToApplyPoison' }, | |||
["Slow"] = { 'increased15SlowStunChance2Turns', 'increased30Slow5TurnsChance' } | |||
} | |||
for | local statusMods = statusModsAll[effectType] | ||
if statusMods ~= nil and type(modifiers) == 'table' then | |||
for modName, modMagnitude in pairs(modifiers) do | |||
if Shared.contains(statusMods, modName) then | |||
return true | |||
end | |||
end | end | ||
end | end | ||
Line 412: | Line 431: | ||
end | end | ||
-- Damage adjustments are defined as follows: | |||
-- multiplier - Damage from modifier 'increasedDamageTaken' & additional damage while | |||
-- stunned, asleep, or poisoned. Defined by in-game function | |||
-- getDamageModifiers(). Applies after other percentage of flat adjustments. | |||
-- percent - Percentage adjustments to the max hit. Applies before flat & multiplier | |||
-- adjustments. | |||
-- flat - Flat adjustments to the max hit. Applies after percent adjustments, and | |||
-- after multiplier adjustments. | |||
local dmgAdjust = { ["percent"] = 100, ["flat"] = 0, ["multiplier"] = 100 } | local dmgAdjust = { ["percent"] = 100, ["flat"] = 0, ["multiplier"] = 100 } | ||
-- Check passives & effects that apply pre or on hit for damage modifiers | -- Check passives & effects that apply pre or on hit for damage modifiers | ||
Line 421: | Line 448: | ||
["increasedRangedMaxHit"] = { type = 'percent', mult = 1 }, | ["increasedRangedMaxHit"] = { type = 'percent', mult = 1 }, | ||
["increasedMagicMaxHit"] = { type = 'percent', mult = 1 }, | ["increasedMagicMaxHit"] = { type = 'percent', mult = 1 }, | ||
["increasedMeleeMaxHitFlat"] = { type = 'flat', mult = | ["increasedMaxHitFlat"] = { type = 'flat', mult = 10 }, | ||
["increasedRangedMaxHitFlat"] = { type = 'flat', mult = | ["increasedMeleeMaxHitFlat"] = { type = 'flat', mult = 10 }, | ||
["increasedMagicMaxHitFlat"] = { type = 'flat', mult = | ["increasedRangedMaxHitFlat"] = { type = 'flat', mult = 10 }, | ||
["increasedRage"] = { type = 'percent', mult = 2, maxStacks = 10 } | ["increasedMagicMaxHitFlat"] = { type = 'flat', mult = 10 }, | ||
-- Rage: +2% max hit per stack, maximum of 10 stacks | |||
["increasedRage"] = { type = 'percent', mult = 1, magnitude = 2, maxStacks = 10 }, | |||
-- Dark Blade: +1% max hit per successful hit, maximum of 30 stacks | |||
["increasedChanceDarkBlade"] = { type = 'percent', mult = 1, magnitude = 1, maxStacks = 30 }, | |||
-- Growing Madness/Moment in Time/Reign Over Time: +2% max hit per stack, maximum of 25 stacks | |||
["growingMadnessPassive"] = { type = 'percent', mult = 1, magnitude = 2, maxStacks = 25 }, | |||
["momentInTimePassive"] = { type = 'percent', mult = 1, magnitude = 2, maxStacks = 25 }, | |||
["reignOverTimePassive"] = { type = 'percent', mult = 1, magnitude = 2, maxStacks = 25 } | |||
} | } | ||
local effectKeys = { 'prehitEffects', 'onhitEffects' } | local effectKeys = { 'prehitEffects', 'onhitEffects' } | ||
-- Check monster passives for modifiers which affect damage dealt | local dmgStatuses = { | ||
-- List of status effects which can affect damage dealt | |||
["Stun"] = { type = 'multiplier', magnitude = 30 }, | |||
["Sleep"] = { type = 'multiplier', magnitude = 20 } | |||
} | |||
local canApplyStatus = {} | |||
-- Initialize table | |||
for statusName, def in pairs(dmgStatuses) do | |||
canApplyStatus[statusName] = false | |||
end | |||
local adjustForMod = function(mod, modMagnitude, effect) | |||
local magnitude = mod.magnitude or modMagnitude | |||
local maxStacks = mod.maxStacks or (effect ~= nil and effect.maxStacks) or 1 | |||
dmgAdjust[mod.type] = dmgAdjust[mod.type] + magnitude * mod.mult * maxStacks | |||
end | |||
local adjustForCurse = function(curseID, effect) | |||
local curse = Magic.getSpellByID(curseID, 'curse') | |||
if type(curse) == 'table' and type(curse.targetModifiers) == 'table' then | |||
for modName, modMagnitude in pairs(curse.targetModifiers) do | |||
local mod = dmgMods[modName] | |||
if mod ~= nil then | |||
-- The modifier is one which affects damage dealt | |||
adjustForMod(mod, modMagnitude, effect) | |||
end | |||
end | |||
end | |||
end | |||
-- Check monster passives for modifiers which affect damage dealt, and alo if any modifiers | |||
-- present can apply stun or sleep | |||
if monster ~= nil and type(monster.passives) ~= nil then | if monster ~= nil and type(monster.passives) ~= nil then | ||
for i, passiveID in ipairs(monster.passives) do | for i, passiveID in ipairs(monster.passives) do | ||
Line 434: | Line 500: | ||
for modName, modMagnitude in pairs(passive.modifiers) do | for modName, modMagnitude in pairs(passive.modifiers) do | ||
local mod = dmgMods[modName] | local mod = dmgMods[modName] | ||
if mod ~= nil then | if modName == 'applyRandomCurseOnSpawn' then | ||
-- Special case in which the enemy can apply a random curse. Currently | |||
-- Anguish III is the curse with the highest +% damage taken, so use this. | |||
adjustForCurse('melvorF:AnguishIII') | |||
elseif mod ~= nil then | |||
-- The modifier is one which affects damage dealt | -- The modifier is one which affects damage dealt | ||
adjustForMod(mod, modMagnitude) | |||
end | |||
end | |||
-- Check for application of relevant status effects | |||
if doStuns then | |||
for statusName, statusDef in pairs(dmgStatuses) do | |||
if not canApplyStatus[statusName] and p.canModifiersApplyEffect(passive.modifiers, statusName) then | |||
canApplyStatus[statusName] = true | |||
end | |||
end | end | ||
end | end | ||
Line 449: | Line 526: | ||
local hasActiveBuffSpec = false | local hasActiveBuffSpec = false | ||
if monster.specialAttacks ~= nil then | if monster.specialAttacks ~= nil then | ||
for i, specAttackID in pairs(monster.specialAttacks) do | for i, specAttackID in pairs(monster.specialAttacks) do | ||
local specAttack = GameData.getEntityByID('attacks', specAttackID) | local specAttack = GameData.getEntityByID('attacks', specAttackID) | ||
Line 463: | Line 539: | ||
if mod ~= nil then | if mod ~= nil then | ||
-- The modifier is one which affects damage dealt | -- The modifier is one which affects damage dealt | ||
adjustForMod(mod, modMagnitude, effect) | |||
end | end | ||
end | end | ||
end | end | ||
-- Check for curses which may cause the player to incur additional damage | -- Check for curses which may cause the player to incur additional damage | ||
if effect.effectType == 'Curse' | if effect.effectType == 'Curse' then | ||
-- If isRandom is true then a random curse is selected. Currently | |||
-- Anguish III is the curse with the highest +% damage taken, so | |||
-- use this. | |||
local curseID = (effect.isRandom and 'melvorF:AnguishIII') or effect.curse | |||
if curseID ~= nil then | |||
adjustForCurse(curseID, effect) | |||
end | end | ||
end | end | ||
Line 492: | Line 563: | ||
normalChance = normalChance - specAttack.defaultChance | normalChance = normalChance - specAttack.defaultChance | ||
end | end | ||
-- Check for application of relevant status effects | |||
if doStuns then | |||
for statusName, statusDef in pairs(dmgStatuses) do | |||
if not canApplyStatus[statusName] and p.canSpecAttackApplyEffect(specAttack, statusName) then | |||
canApplyStatus[statusName] = true | |||
end | |||
end | |||
end | |||
local thisMax = p.getSpecAttackMaxHit(specAttack, normalMaxHit, monster) | local thisMax = p.getSpecAttackMaxHit(specAttack, normalMaxHit, monster) | ||
if thisMax > specialMaxHit then specialMaxHit = thisMax end | if thisMax > specialMaxHit then specialMaxHit = thisMax end | ||
if Shared.contains(string.upper(specAttack.description), 'NORMAL ATTACK INSTEAD') then | if Shared.contains(string.upper(specAttack.description), 'NORMAL ATTACK INSTEAD') then | ||
Line 502: | Line 580: | ||
end | end | ||
if | if doStuns then | ||
for statusName, statusDef in pairs(dmgStatuses) do | |||
if canApplyStatus[statusName] then | |||
local adjType = statusDef.type | |||
dmgAdjust[adjType] = dmgAdjust[adjType] + statusDef.magnitude | |||
end | |||
end | |||
end | |||
end | end | ||
--Ensure that if the monster never does a normal attack, the normal max hit is irrelevant | --Ensure that if the monster never does a normal attack, the normal max hit is irrelevant |