Fixing The Evasion Mechanic

All new ideas for the upcoming releases of ToME 4.x.x should be discussed here

Moderator: Moderator

Post Reply
Message
Author
Hachem_Muche
Uruivellas
Posts: 744
Joined: Thu Nov 18, 2010 6:42 pm

Fixing The Evasion Mechanic

#1 Post by Hachem_Muche »

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:

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
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.
Chart1-2.jpg
Chart1-2.jpg (88.19 KiB) Viewed 7682 times
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.
Chart3-4.jpg
Chart3-4.jpg (89.17 KiB) Viewed 7682 times
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,
}
Note that the change to the Evasion temporary effect is backward compatible with all of the other (unchanged) code in the game.

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,
}
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.
Author of the Infinite 500 and PlenumTooltip addons, and the joys of Scaling in ToME.

nate
Wyrmic
Posts: 261
Joined: Fri Jan 18, 2013 8:35 am

Re: Fixing The Evasion Mechanic

#2 Post by nate »

I'm reading this after your recent link in the "evade magic projectiles" thread.

I'm afraid I don't understand your formula, or else I don't understand your graph. 75% evasion is high end from Evasion talent, but when I run it through your formula, I get 37.5, which isn't what your graph shows.

However, can I suggest an alternative? Evasion is improperly balanced, because it scales linearly, and because twice as much evasion isn't twice as good-- it's much, much better than twice as good.

For instance, with 25% evasion, you'll avoid 25% of incoming melee. In other words, at 1000 hp, you'll be able to take 1333 hit points of damage-- a 33% improvement.

Double it to 50% evasion, and at 1000 hp, you'll be able to take 2000 points of damage-- a 100% improvement.

Double it again to 100% evasion, and you'll be able to take an infinite amount of damage.

The right way to deal with this is to scale it appropriately, to a reciprocal. Functional evasion rate should be proportional to something like 1 - 100/(100+evasion). For instance, if your linear talent progression goes 20/40/60/80/100, you get 17/29/38/44/50% actual evasion rate out of it, which is what a linear improvement in melee defense due to evasion should look like.

This basic format for getting linear benefit should apply to lots of things. Weapon attack speed and resistances work the same way, where the value of x% increases as you add them up. (A 10% attack speed weapon is 100% more effective than a 20% attack speed weapon; 90% resist all is 100% more effective than 80% resist all.)
Proud father of Fx4fx and Chronometer add-ons; proud mother of Fated add-on

Hachem_Muche
Uruivellas
Posts: 744
Joined: Thu Nov 18, 2010 6:42 pm

Re: Fixing The Evasion Mechanic

#3 Post by Hachem_Muche »

nate wrote:I'm reading this after your recent link in the "evade magic projectiles" thread.

I'm afraid I don't understand your formula, or else I don't understand your graph. 75% evasion is high end from Evasion talent, but when I run it through your formula, I get 37.5, which isn't what your graph shows.
Thanks for your feedback. The 37.5% evasion for my proposed formula is correct. What you may have missed is that in addition to the chance to evade attacks outright, the high dex defender also gets 56.6 defense to help avoid attacks.
nate wrote:However, can I suggest an alternative? Evasion is improperly balanced, because it scales linearly, and because twice as much evasion isn't twice as good-- it's much, much better than twice as good.
This is, of course, the crux of the problem.
nate wrote:The right way to deal with this is to scale it appropriately, to a reciprocal. Functional evasion rate should be proportional to something like 1 - 100/(100+evasion). For instance, if your linear talent progression goes 20/40/60/80/100, you get 17/29/38/44/50% actual evasion rate out of it, which is what a linear improvement in melee defense due to evasion should look like.
This is a good start (and I have used similar formulas extensively in my high-level addon). It's just not quite good enough as levels increase. The fundamental problem with the current evasion mechanic is that, at high talent (stat) levels, the attacker's skills simply don't matter. Even with a reciprocal progression, the value of the attacker's offense is steadily eroded at high levels and there is no way to counter it. In contrast, the opposed skill attack vs. defense system is balanced because these attributes improve for both attacker and defender with level, and hence can scale indefinitely as long they are improve at similar rates.
nate wrote:This basic format for getting linear benefit should apply to lots of things. Weapon attack speed and resistances work the same way, where the value of x% increases as you add them up. (A 10% attack speed weapon is 100% more effective than a 20% attack speed weapon; 90% resist all is 100% more effective than 80% resist all.)
There is support for this within the T-engine, and it is used in many places. There have been some discussions about bugs and inconsistent application, however, generally in regards to stacking of different effects.
Author of the Infinite 500 and PlenumTooltip addons, and the joys of Scaling in ToME.

nate
Wyrmic
Posts: 261
Joined: Fri Jan 18, 2013 8:35 am

Re: Fixing The Evasion Mechanic

#4 Post by nate »

I see what I did-- I read the new defense line as the new evasion line. That's why I thought the formula didn't agree with the graph.

The way I see it, you're saying there are a few problems:

1) Evasion gives vastly accelerating returns, leading to the potential for immunity from one type of damage, and an unbalanced talent in a game of diminishing returns (take 0 or take 5)
2) Evasion doesn't take the attacker into account-- precise strikes, for instance, doesn't help at all. This feels wrong thematically. An accurate attacker should be less vulnerable to being evaded.

The first one is easy to solve via any kind of proportional-to-the-reciprocal method, of which you can take your pick.

I'm concerned, however, about your solution to the second problem, which is by moving some of the Evasion to Defense. I'm not really familiar with the accuracy/defense code, I've just read the wiki when it comes to that, but my understanding is that it doesn't handle outliers particularly well-- if defense > accuracy + 20, there's just a flat hit rate, right? It works well enough because there's rarely a huge difference between accuracy and defense. But if you start adding 63 points to defense ((5*1.3)^0.5*(100+100)/8), on a character already built to maximize defense, doesn't that equation change?

Okay, we'll say I have defense 57, and I'm being attacked by somebody with accuracy 66. I activate my +63 defense ability. Suddenly, there's absolutely no difference between anybody with an accuracy of 0 and anybody with an accuracy of 100 (which according to your values should be almost everybody.) At least with the old way, the higher accuracy mobs had a better chance of hitting me than the clumsy mobs, thanks to more hits getting through to the evasion check.

If you want to make attacker accuracy make a bigger difference in evade rates, why not just reduce evasion rates with attacker accuracy instead of attacker level? Functionally, evasion and high defense do the same things anyways (reduce incoming melee damage, increase the variance on incoming damage).
Proud father of Fx4fx and Chronometer add-ons; proud mother of Fated add-on

Hachem_Muche
Uruivellas
Posts: 744
Joined: Thu Nov 18, 2010 6:42 pm

Re: Fixing The Evasion Mechanic

#5 Post by Hachem_Muche »

nate wrote:- if defense > accuracy + 20, there's just a flat hit rate, right? It works well enough because there's rarely a huge difference between accuracy and defense. But if you start adding 63 points to defense ((5*1.3)^0.5*(100+100)/8), on a character already built to maximize defense, doesn't that equation change?
That's basically how the defense/accuracy balance works, but the situation is not as bad as it first seems. There is also very substantial diminishing returns on the effective values of these stats as you invest in them. The raw combat stats (those shown on equipment and skill descriptions) are reduced (see the _M:rescaleCombatStats formula in Combat.lua if you're interested in the formula) to produce the effective stats that show up on the character sheet and tooltips that are actually used in the combat calculations. So, in your example of a character with 57 defense activating a +63 defense bonus, effective defense goes from 38.5 to 50. The diminishing returns is generally enough to keep things reasonably balanced, at least until late in the Maj'Eyal campaign. I have proposed and extensively tested an alternate hit function to extend game balance further and mitigate combat stat irrelevancy. (see http://forums.te4.org/viewtopic.php?f=36&t=35229)
nate wrote:If you want to make attacker accuracy make a bigger difference in evade rates, why not just reduce evasion rates with attacker accuracy instead of attacker level? Functionally, evasion and high defense do the same things anyways (reduce incoming melee damage, increase the variance on incoming damage).
This is pretty much exactly what I have done by replacing some evasion with defense. Keeping up to 50% evasion is a compromise to keep the skill relevant for characters that don't invest in defense, which would otherwise gain much less benefit from the talent.
Author of the Infinite 500 and PlenumTooltip addons, and the joys of Scaling in ToME.

nate
Wyrmic
Posts: 261
Joined: Fri Jan 18, 2013 8:35 am

Re: Fixing The Evasion Mechanic

#6 Post by nate »

Ah, thanks, that makes sense!
Proud father of Fx4fx and Chronometer add-ons; proud mother of Fated add-on

Post Reply