Fixing The Evasion Mechanic
Posted: Sat Dec 01, 2012 10:14 pm
The current implementation of Evasion in the game is problematic because it can become overpowered versus melee damage. The current formulas for Evasion are for the survival talent EVASION:
Evasion% = 5 * TalentLevel + Cunning/4 + Dexterity/4
and for the halfling racial talent DUCK AND DODGE:
Evasion% = Luck
In addition, the evasion chance is scaled up or down based on the relative levels of the attacker and defender. This exacerbates the difficulties faced in the game by melee pcs, which are already at a disadvantage overall compared to their ranged counterparts. I believe this scaling factor should be removed since evasion effectiveness already improves with level.
It has been possible to get nearly 100% evasion both with DUCK AND DODGE and with the normal EVASION talent for some time. The B43 prodigy, Lucky Day (+40 Luck), on a halfling with the Duck and Dodge Talent can achieve 100% evasion with the Elixir of Serendipity (5 luck). By the end game, it is also possible to get very close to 100% avoidance with the EVASION skill and high stats. This allows a defender to almost completely shut down the melee capabilities of most attackers, and is clearly too powerful.
The problem lies with the evasion game mechanic. As a flat percent check, the combat abilites of the attacker do not matter. In fact, evasioin gets better and better the stronger the melee abilites of the attacker become. To redress this inverted game balance problem I propose splitting the evasion effect into a flat percent check limited to 50% maximum and a (potentially large) defense bonus to achieve similar results but maintain game balance going forward. (I have already incorporated and tested these new formulas in the b43 version of the Infinite500 addon, where the problem first became apparent.)
For the EVASION talent I have changed the formula to:
Base = 5 * TalentLevel + Cunning/4 + Dexterity/4
Evasion% = 50*Base/(Base + 25)
Defense = TalentLevel^0.5 * (Cunning + Dexterity)/8
Where Base is the current formlua, Evasion% is the current evasion effect that is limited to < 50% regardless of talent level, and Defense is the new raw (before rescaling) defense bonus. Retaining the current evasion mechanic means that EVASION is still always good for everyone, regardless of other considerations, while the defense bonus rewards character builds that focus on avoiding melee attacks. With this formula, evasion can still get very good, but it's impossible to avoid melee attacks completely.
For DUCK AND DODGE I have changed the formula to:
Evasion% = 50
Defense = BaseDefense * Luck/200
where BaseDefense is the total (raw) defense of the character from other sources. The effect is to give a flat 50% chance to avoid all melee attacks while scaling up defense with a multiplier based on luck. This formula keeps DUCK AND DODGE's luck-based flavor, but, as above, cannot produce virtual immunity to melee attacks.
I have evaluted the effectiveness of these changes with the following assumptions:
The attacker and defender are the same level.
Defender makes avoiding attacks a priority:
Halfling character with 55 luck to start, +5 luck at level 25 from Elixir of Serendipity, and takes the Lucky Day Prodigy at level 40
Dexterity and Cunning are maxed out early (17 at level 1) and prioritized through level 50 (100 at level 50).
Character has access to one defense talent (assumed to be dual weapon defense here)
Talent level mastery is 1.3 and a new raw talent level is acquired at levels 1, 15, 25, 35, 45 for EVASION and the defense talent
For the attacker:
Acquires levels in the Combat Accuracy talent at the same rate the defender gains its defense talent
Low dexterity attacker dexterity ranges from 10.1 at level 1 to 15 at level 50 (linear)
Mid dexterity attacker dexterity ranges from 10.8 to 50 (linear)
High dexterity attacker dexterity equals defender dexterity (17 to 100)
These assumptions give the following values for attack and defense:
These are scaled (character sheet) values.
The results of these changes compared to the existing formulas are plotted below. (The new formula I have proposed for calculating hit probabilities would smooth out the results and limit the effectiveness of the improved defense, but I have used the existing formula for this analysis.)
Chart 1 shows the direct computed values from the proposed and existing formulas for the EVASION talent. The more interesting results appear in Chart 2 which shows the relative effectiveness of the changes on the ability of the defender to avoid being hit. The chance for a Mid Dex attacker to hit the defender are very similar across the range for both formulas, but most importantly, there is a much wider range of probabilities for higher level characters. That is, the capabilities of the attacker matter much more. Chart 3 shows the computed values for the proposed and existing formulas for the DUCK AND DODGE talent, highlighting the dramatic effect of the LUCKY DAY prodigy at level 40. Chart 4 (note change of scale) shows the overall effectiveness of this talent with the exising and proposed formulas. As with EVASION, the quality of the attack is much more important at high levels, and in particular, the chance to hit never reaches zero. I've just completed a Maj'Eyal campaign with a halfling shadowblade (with the DUCK AND DODGE talent) using these changes. The results have been good. The effectiveness of these talents is very situational. DUCK AND DODGE probably saved me from a couple of deaths, and was useful in tight spots, but I still had to retreat, even against purely melee opponents, when I started running low on hit points. Similarly, it's quite advantageous to wait for EVASION to wear off before using a big melee talent against an npc, but still worth pressing the attack to finish them if they're near death.
As noted above, I have already implemented these changes in the Infinite 500 addon. The code changes (marked in comments by "I5") are pretty modest:
Note that the change to the Evasion temporary effect is backward compatible with all of the other (unchanged) code in the game.
Based on my testing, and experience with the game, along with the current philosophy of limiting flat percent immunities, I think these changes are the right approach to updating this potentially game-breaking mechanic.
Evasion% = 5 * TalentLevel + Cunning/4 + Dexterity/4
and for the halfling racial talent DUCK AND DODGE:
Evasion% = Luck
In addition, the evasion chance is scaled up or down based on the relative levels of the attacker and defender. This exacerbates the difficulties faced in the game by melee pcs, which are already at a disadvantage overall compared to their ranged counterparts. I believe this scaling factor should be removed since evasion effectiveness already improves with level.
It has been possible to get nearly 100% evasion both with DUCK AND DODGE and with the normal EVASION talent for some time. The B43 prodigy, Lucky Day (+40 Luck), on a halfling with the Duck and Dodge Talent can achieve 100% evasion with the Elixir of Serendipity (5 luck). By the end game, it is also possible to get very close to 100% avoidance with the EVASION skill and high stats. This allows a defender to almost completely shut down the melee capabilities of most attackers, and is clearly too powerful.
The problem lies with the evasion game mechanic. As a flat percent check, the combat abilites of the attacker do not matter. In fact, evasioin gets better and better the stronger the melee abilites of the attacker become. To redress this inverted game balance problem I propose splitting the evasion effect into a flat percent check limited to 50% maximum and a (potentially large) defense bonus to achieve similar results but maintain game balance going forward. (I have already incorporated and tested these new formulas in the b43 version of the Infinite500 addon, where the problem first became apparent.)
For the EVASION talent I have changed the formula to:
Base = 5 * TalentLevel + Cunning/4 + Dexterity/4
Evasion% = 50*Base/(Base + 25)
Defense = TalentLevel^0.5 * (Cunning + Dexterity)/8
Where Base is the current formlua, Evasion% is the current evasion effect that is limited to < 50% regardless of talent level, and Defense is the new raw (before rescaling) defense bonus. Retaining the current evasion mechanic means that EVASION is still always good for everyone, regardless of other considerations, while the defense bonus rewards character builds that focus on avoiding melee attacks. With this formula, evasion can still get very good, but it's impossible to avoid melee attacks completely.
For DUCK AND DODGE I have changed the formula to:
Evasion% = 50
Defense = BaseDefense * Luck/200
where BaseDefense is the total (raw) defense of the character from other sources. The effect is to give a flat 50% chance to avoid all melee attacks while scaling up defense with a multiplier based on luck. This formula keeps DUCK AND DODGE's luck-based flavor, but, as above, cannot produce virtual immunity to melee attacks.
I have evaluted the effectiveness of these changes with the following assumptions:
The attacker and defender are the same level.
Defender makes avoiding attacks a priority:
Halfling character with 55 luck to start, +5 luck at level 25 from Elixir of Serendipity, and takes the Lucky Day Prodigy at level 40
Dexterity and Cunning are maxed out early (17 at level 1) and prioritized through level 50 (100 at level 50).
Character has access to one defense talent (assumed to be dual weapon defense here)
Talent level mastery is 1.3 and a new raw talent level is acquired at levels 1, 15, 25, 35, 45 for EVASION and the defense talent
For the attacker:
Acquires levels in the Combat Accuracy talent at the same rate the defender gains its defense talent
Low dexterity attacker dexterity ranges from 10.1 at level 1 to 15 at level 50 (linear)
Mid dexterity attacker dexterity ranges from 10.8 to 50 (linear)
High dexterity attacker dexterity equals defender dexterity (17 to 100)
These assumptions give the following values for attack and defense:
Code: Select all
Character level 1 5 10 15 20 25 30 35 40 45 50
Defender Defense 10.3 13.5 17.2 22.9 25.1 31.8 34.5 41.1 48.5 54.2 56.6
Low Dex Offense 14.1 14.5 15.0 22.8 23.0 28.3 28.5 33.8 34.0 39.3 39.5
Mid Dex Offense 14.8 18.0 21.0 28.0 30.0 37.0 39.0 44.0 45.3 50.0 51.3
High Dex Offense 20.5 24.0 28.0 37.5 41.0 47.3 50.0 56.3 59.0 64.0 66.0
The results of these changes compared to the existing formulas are plotted below. (The new formula I have proposed for calculating hit probabilities would smooth out the results and limit the effectiveness of the improved defense, but I have used the existing formula for this analysis.)
Chart 1 shows the direct computed values from the proposed and existing formulas for the EVASION talent. The more interesting results appear in Chart 2 which shows the relative effectiveness of the changes on the ability of the defender to avoid being hit. The chance for a Mid Dex attacker to hit the defender are very similar across the range for both formulas, but most importantly, there is a much wider range of probabilities for higher level characters. That is, the capabilities of the attacker matter much more. Chart 3 shows the computed values for the proposed and existing formulas for the DUCK AND DODGE talent, highlighting the dramatic effect of the LUCKY DAY prodigy at level 40. Chart 4 (note change of scale) shows the overall effectiveness of this talent with the exising and proposed formulas. As with EVASION, the quality of the attack is much more important at high levels, and in particular, the chance to hit never reaches zero. I've just completed a Maj'Eyal campaign with a halfling shadowblade (with the DUCK AND DODGE talent) using these changes. The results have been good. The effectiveness of these talents is very situational. DUCK AND DODGE probably saved me from a couple of deaths, and was useful in tight spots, but I still had to retreat, even against purely melee opponents, when I started running low on hit points. Similarly, it's quite advantageous to wait for EVASION to wear off before using a big melee talent against an npc, but still worth pressing the attack to finish them if they're near death.
As noted above, I have already implemented these changes in the Infinite 500 addon. The code changes (marked in comments by "I5") are pretty modest:
Code: Select all
newEffect{
name = "EVASION", image = "talents/evasion.png",
desc = "Evasion",
--I5 long_desc = function(self, eff) return ("The target has %d%% chance to evade melee attacks."):format(eff.chance) end,
long_desc = function(self, eff) --I5
return ("The target has %d%% chance to evade melee attacks"):format(eff.chance) .. ((eff.defense>0 and (" and gains %d defense"):format(eff.defense)) or "") .. "."
end, --I5
type = "physical",
subtype = { evade=true },
status = "beneficial",
--I5 parameters = { chance=10 },
parameters = { chance=10, defense=0 }, --I5
on_gain = function(self, err) return "#Target# tries to evade attacks.", "+Evasion" end,
on_lose = function(self, err) return "#Target# is no longer evading attacks.", "-Evasion" end,
activate = function(self, eff)
eff.tmpid = self:addTemporaryValue("evasion", eff.chance)
eff.defid = self:addTemporaryValue("combat_def", eff.defense) --I5
end,
deactivate = function(self, eff)
self:removeTemporaryValue("evasion", eff.tmpid)
self:removeTemporaryValue("combat_def", eff.defid) --I5
end,
}
Code: Select all
function _M:checkEvasion(target)
if not target:attr("evasion") or self == target then return end
local evasion = target:attr("evasion")
print("checkEvasion", evasion, target.level, self.level)
--I5 evasion = evasion * (target.level / self.level)
print("=> evasion chance", evasion)
return rng.percent(evasion)
end
Code: Select all
newTalent{
name = "Evasion",
type = {"cunning/survival", 4},
points = 5,
require = cuns_req4,
random_ego = "defensive",
tactical = { ESCAPE = 2, DEFEND = 2 },
cooldown = 30,
getDur = function(self) return 5+math.floor(25*self:getWil(10,true)/(self:getWil(10,true)+15)) end, --I5 Limit < 30
getChanceDef = function(self, t) --I5
local tl = self:getTalentLevel(t)*5 + self:getCun(25,true) + self:getDex(25,true) --I5
return 50*tl/(tl+25), self:getTalentLevel(t)^.5 * (self:getCun(25,true) + self:getDex(25,true))/2 -- I5 Limit evasion chance <50%
end,
action = function(self, t)
--I5 local dur = 5 + self:getWil(10)
local dur = t.getDur(self) --I5
local chance,def = t.getChanceDef(self,t) --I5 Updated effect "EVASION" in data.temporary_effects.physical.lua
--I5 local chance = 5 * self:getTalentLevel(t) + self:getCun(25, true) + self:getDex(25, true)
--I5 self:setEffect(self.EFF_EVASION, dur, {chance=chance})
self:setEffect(self.EFF_EVASION, dur, {chance=chance, defense = def}) --I5
return true
end,
info = function(self, t)
local chance,def = t.getChanceDef(self,t)
--I5 return ([[Your quick wit allows you to see attacks before they come, granting you a %d%% chance to completely evade them for %d turns.
-- Duration increases with Willpower, and chance to evade with Cunning and Dexterity.]]):format(5 * self:getTalentLevel(t) + self:getCun(25, true) + self:getDex(25, true), 5 + self:getWil(10))
return ([[Your quick wit allows you to see attacks before they come, granting you a %d%% chance to completely evade them and granting you %d defense for %d turns.
Duration increases with Willpower, and chance to evade and defense with Cunning and Dexterity.]]):
format(chance, def,t.getDur(self))
end,
}
Code: Select all
newTalent{
name = "Duck and Dodge",
type = {"race/halfling", 2},
require = racial_req2,
points = 5,
mode = "passive",
getThreshold = function(self, t) return math.max(10, (15 - self:getTalentLevelRaw(t))) / 100 end,
--I5 getEvasionChance = function(self, t) return self:getStat("lck") end,
getEvasionChance = function(self, t) return 50 end, --I5
--I5 getDuration = function(self, t) return 1 + math.ceil(self:getTalentLevel(t)/2) end,
getDuration = function(self, t) return math.floor(0.45+1.6*self:getTalentLevel(t)^.5) end, --I5
--I5 _M:onTakeHit function in mod.class.Actor.lua updated for trigger
--I5 "EVASION" effect updated in mod.data.timed_effects.physical.lua to implement effect
getDefense = function(self) --I5
local oldevasion = self:hasEffect(self.EFF_EVASION)
return self:getStat("lck")/200*(self:combatDefenseBase() - (oldevasion and oldevasion.defense or 0)) --I5 Prevent stacking
end, --I5
info = function(self, t)
local threshold = t.getThreshold(self, t)
local evasion = t.getEvasionChance(self, t)
local duration = t.getDuration(self, t)
--I5 return ([[Your incredible luck kicks in at just the right moment to save your skin.
-- Whenever you take %d%% or more of your life from a single attack you gain Evasion equal to your luck stat (currently %d%%) for the next %d turns.]]):
-- format(threshold * 100, evasion, duration)
return ([[Your incredible luck kicks in at just the right moment to save your skin.
Whenever you take %d%% or more of your life from a single attack you gain Evasion (%d%%) and %d additional defense (based on your luck) for the next %d turns.]]):
format(threshold * 100, evasion, t.getDefense(self), duration)
end,
}